Skip to content

Commit 6ddbf20

Browse files
committed
Fix ModifiedKey roll-interaction with same non-modified keys
1 parent 0b26d06 commit 6ddbf20

File tree

2 files changed

+65
-29
lines changed

2 files changed

+65
-29
lines changed

kmk/keys.py

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -255,33 +255,36 @@ def maybe_make_numpad_key(candidate: str) -> Optional[Key]:
255255

256256
def maybe_make_shifted_key(candidate: str) -> Optional[Key]:
257257
codes = (
258-
(30, ('EXCLAIM', 'EXLM', '!')),
259-
(31, ('AT', '@')),
260-
(32, ('HASH', 'POUND', '#')),
261-
(33, ('DOLLAR', 'DLR', '$')),
262-
(34, ('PERCENT', 'PERC', '%')),
263-
(35, ('CIRCUMFLEX', 'CIRC', '^')),
264-
(36, ('AMPERSAND', 'AMPR', '&')),
265-
(37, ('ASTERISK', 'ASTR', '*')),
266-
(38, ('LEFT_PAREN', 'LPRN', '(')),
267-
(39, ('RIGHT_PAREN', 'RPRN', ')')),
268-
(45, ('UNDERSCORE', 'UNDS', '_')),
269-
(46, ('PLUS', '+')),
270-
(47, ('LEFT_CURLY_BRACE', 'LCBR', '{')),
271-
(48, ('RIGHT_CURLY_BRACE', 'RCBR', '}')),
272-
(49, ('PIPE', '|')),
273-
(51, ('COLON', 'COLN', ':')),
274-
(52, ('DOUBLE_QUOTE', 'DQUO', 'DQT', '"')),
275-
(53, ('TILDE', 'TILD', '~')),
276-
(54, ('LEFT_ANGLE_BRACKET', 'LABK', '<')),
277-
(55, ('RIGHT_ANGLE_BRACKET', 'RABK', '>')),
278-
(56, ('QUESTION', 'QUES', '?')),
258+
('1', ('EXCLAIM', 'EXLM', '!')),
259+
('2', ('AT', '@')),
260+
('3', ('HASH', 'POUND', '#')),
261+
('4', ('DOLLAR', 'DLR', '$')),
262+
('5', ('PERCENT', 'PERC', '%')),
263+
('6', ('CIRCUMFLEX', 'CIRC', '^')),
264+
('7', ('AMPERSAND', 'AMPR', '&')),
265+
('8', ('ASTERISK', 'ASTR', '*')),
266+
('9', ('LEFT_PAREN', 'LPRN', '(')),
267+
('0', ('RIGHT_PAREN', 'RPRN', ')')),
268+
('-', ('UNDERSCORE', 'UNDS', '_')),
269+
('=', ('PLUS', '+')),
270+
('[', ('LEFT_CURLY_BRACE', 'LCBR', '{')),
271+
(']', ('RIGHT_CURLY_BRACE', 'RCBR', '}')),
272+
('\\', ('PIPE', '|')),
273+
(';', ('COLON', 'COLN', ':')),
274+
("'", ('DOUBLE_QUOTE', 'DQUO', 'DQT', '"')),
275+
('`', ('TILDE', 'TILD', '~')),
276+
(',', ('LEFT_ANGLE_BRACKET', 'LABK', '<')),
277+
('.', ('RIGHT_ANGLE_BRACKET', 'RABK', '>')),
278+
('/', ('QUESTION', 'QUES', '?')),
279279
)
280280

281-
for code, names in codes:
281+
for unshifted, names in codes:
282282
if candidate in names:
283283
return make_key(
284-
names=names, constructor=ModifiedKey, code=code, modifier=KC.LSFT
284+
names=names,
285+
constructor=ModifiedKey,
286+
code=KC[unshifted],
287+
modifier=KC.LSFT,
285288
)
286289

287290

@@ -430,15 +433,19 @@ def __repr__(self):
430433
return super().__repr__() + '(code=' + str(self.code) + ')'
431434

432435
def on_press(self, keyboard: Keyboard, coord_int: Optional[int] = None) -> None:
433-
keyboard.hid_pending = True
434-
keyboard.keys_pressed.add(self)
435436
if keyboard.implicit_modifier is not None:
436437
keyboard.keys_pressed.discard(keyboard.implicit_modifier)
437438
keyboard.implicit_modifier = None
439+
if self in keyboard.keys_pressed:
440+
keyboard.keys_pressed.discard(self)
441+
keyboard.hid_pending = True
442+
keyboard._send_hid()
443+
keyboard.keys_pressed.add(self)
444+
keyboard.hid_pending = True
438445

439446
def on_release(self, keyboard: Keyboard, coord_int: Optional[int] = None) -> None:
440-
keyboard.hid_pending = True
441447
keyboard.keys_pressed.discard(self)
448+
keyboard.hid_pending = True
442449

443450

444451
class KeyboardKey(_DefaultKey):
@@ -483,19 +490,24 @@ def __init__(self, code: [Key, int], modifier: [ModifierKey]):
483490
self.modifier = modifier
484491

485492
def on_press(self, keyboard: Keyboard, coord_int: Optional[int] = None) -> None:
486-
self.modifier.on_press(keyboard, coord_int)
493+
if self.key in keyboard.keys_pressed:
494+
self.key.on_release(keyboard, coord_int)
495+
keyboard._send_hid()
496+
keyboard.keys_pressed.add(self.modifier)
487497
if self.key is not None:
488498
self.key.on_press(keyboard, coord_int)
489499
if keyboard.implicit_modifier is not None:
490-
keyboard.implicit_modifier.on_release(keyboard, coord_int)
500+
keyboard.keys_pressed.discard(keyboard.implicit_modifier)
491501
keyboard.implicit_modifier = self.modifier
502+
keyboard.hid_pending = True
492503

493504
def on_release(self, keyboard: Keyboard, coord_int: Optional[int] = None) -> None:
494-
self.modifier.on_release(keyboard, coord_int)
505+
keyboard.keys_pressed.discard(self.modifier)
495506
if self.key is not None:
496507
self.key.on_release(keyboard, coord_int)
497508
if keyboard.implicit_modifier == self.modifier:
498509
keyboard.implicit_modifier = None
510+
keyboard.hid_pending = True
499511

500512
def __repr__(self):
501513
return (

tests/test_kmk_keys.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def test_modified_keys(self):
5151
KC.RALT(KC.LSFT),
5252
KC.RALT(KC.LSFT(KC.N4)),
5353
KC.LSFT,
54+
KC.N1,
5455
]
5556
],
5657
debug_enabled=False,
@@ -86,6 +87,18 @@ def test_modified_keys(self):
8687
[{KC.LSFT, KC.N1}, {KC.LSFT}, {}],
8788
)
8889

90+
keyboard.test(
91+
'Shifted key + unshifted key rolled',
92+
[(1, True), (6, True), (1, False), (6, False)],
93+
[{KC.LSFT, KC.N1}, {}, {KC.N1}, {}],
94+
)
95+
96+
keyboard.test(
97+
'Unshifted key + shifted key rolled',
98+
[(6, True), (1, True), (6, False), (1, False)],
99+
[{KC.N1}, {}, {KC.LSFT, KC.N1}, {KC.LSFT}, {}],
100+
)
101+
89102
keyboard.test(
90103
'Shift + shifted key',
91104
[(5, True), (1, True), (5, False), (1, False)],
@@ -98,6 +111,17 @@ def test_modified_keys(self):
98111
[{KC.RALT, KC.LSFT, KC.N2}, {}],
99112
)
100113

114+
keyboard.test(
115+
'Shifted key + modified shifted key rolled',
116+
[(1, True), (2, True), (1, False), (2, False)],
117+
[
118+
{KC.LSFT, KC.N1},
119+
{KC.RALT, KC.LSFT, KC.N1, KC.N2},
120+
{KC.RALT, KC.LSFT, KC.N2},
121+
{},
122+
],
123+
)
124+
101125
keyboard.test(
102126
'Modified modifier',
103127
[(3, True), (3, False)],

0 commit comments

Comments
 (0)