diff --git a/kmk/keys.py b/kmk/keys.py index 27e9127fc..df4959ee9 100644 --- a/kmk/keys.py +++ b/kmk/keys.py @@ -255,33 +255,36 @@ def maybe_make_numpad_key(candidate: str) -> Optional[Key]: def maybe_make_shifted_key(candidate: str) -> Optional[Key]: codes = ( - (30, ('EXCLAIM', 'EXLM', '!')), - (31, ('AT', '@')), - (32, ('HASH', 'POUND', '#')), - (33, ('DOLLAR', 'DLR', '$')), - (34, ('PERCENT', 'PERC', '%')), - (35, ('CIRCUMFLEX', 'CIRC', '^')), - (36, ('AMPERSAND', 'AMPR', '&')), - (37, ('ASTERISK', 'ASTR', '*')), - (38, ('LEFT_PAREN', 'LPRN', '(')), - (39, ('RIGHT_PAREN', 'RPRN', ')')), - (45, ('UNDERSCORE', 'UNDS', '_')), - (46, ('PLUS', '+')), - (47, ('LEFT_CURLY_BRACE', 'LCBR', '{')), - (48, ('RIGHT_CURLY_BRACE', 'RCBR', '}')), - (49, ('PIPE', '|')), - (51, ('COLON', 'COLN', ':')), - (52, ('DOUBLE_QUOTE', 'DQUO', 'DQT', '"')), - (53, ('TILDE', 'TILD', '~')), - (54, ('LEFT_ANGLE_BRACKET', 'LABK', '<')), - (55, ('RIGHT_ANGLE_BRACKET', 'RABK', '>')), - (56, ('QUESTION', 'QUES', '?')), + ('1', ('EXCLAIM', 'EXLM', '!')), + ('2', ('AT', '@')), + ('3', ('HASH', 'POUND', '#')), + ('4', ('DOLLAR', 'DLR', '$')), + ('5', ('PERCENT', 'PERC', '%')), + ('6', ('CIRCUMFLEX', 'CIRC', '^')), + ('7', ('AMPERSAND', 'AMPR', '&')), + ('8', ('ASTERISK', 'ASTR', '*')), + ('9', ('LEFT_PAREN', 'LPRN', '(')), + ('0', ('RIGHT_PAREN', 'RPRN', ')')), + ('-', ('UNDERSCORE', 'UNDS', '_')), + ('=', ('PLUS', '+')), + ('[', ('LEFT_CURLY_BRACE', 'LCBR', '{')), + (']', ('RIGHT_CURLY_BRACE', 'RCBR', '}')), + ('\\', ('PIPE', '|')), + (';', ('COLON', 'COLN', ':')), + ("'", ('DOUBLE_QUOTE', 'DQUO', 'DQT', '"')), + ('`', ('TILDE', 'TILD', '~')), + (',', ('LEFT_ANGLE_BRACKET', 'LABK', '<')), + ('.', ('RIGHT_ANGLE_BRACKET', 'RABK', '>')), + ('/', ('QUESTION', 'QUES', '?')), ) - for code, names in codes: + for unshifted, names in codes: if candidate in names: return make_key( - names=names, constructor=ModifiedKey, code=code, modifier=KC.LSFT + names=names, + constructor=ModifiedKey, + code=KC[unshifted], + modifier=KC.LSFT, ) @@ -430,15 +433,19 @@ def __repr__(self): return super().__repr__() + '(code=' + str(self.code) + ')' def on_press(self, keyboard: Keyboard, coord_int: Optional[int] = None) -> None: - keyboard.hid_pending = True - keyboard.keys_pressed.add(self) if keyboard.implicit_modifier is not None: keyboard.keys_pressed.discard(keyboard.implicit_modifier) keyboard.implicit_modifier = None + if self in keyboard.keys_pressed: + keyboard.keys_pressed.discard(self) + keyboard.hid_pending = True + keyboard._send_hid() + keyboard.keys_pressed.add(self) + keyboard.hid_pending = True def on_release(self, keyboard: Keyboard, coord_int: Optional[int] = None) -> None: - keyboard.hid_pending = True keyboard.keys_pressed.discard(self) + keyboard.hid_pending = True class KeyboardKey(_DefaultKey): @@ -483,19 +490,24 @@ def __init__(self, code: [Key, int], modifier: [ModifierKey]): self.modifier = modifier def on_press(self, keyboard: Keyboard, coord_int: Optional[int] = None) -> None: - self.modifier.on_press(keyboard, coord_int) + if self.key in keyboard.keys_pressed: + self.key.on_release(keyboard, coord_int) + keyboard._send_hid() + keyboard.keys_pressed.add(self.modifier) if self.key is not None: self.key.on_press(keyboard, coord_int) if keyboard.implicit_modifier is not None: - keyboard.implicit_modifier.on_release(keyboard, coord_int) + keyboard.keys_pressed.discard(keyboard.implicit_modifier) keyboard.implicit_modifier = self.modifier + keyboard.hid_pending = True def on_release(self, keyboard: Keyboard, coord_int: Optional[int] = None) -> None: - self.modifier.on_release(keyboard, coord_int) + keyboard.keys_pressed.discard(self.modifier) if self.key is not None: self.key.on_release(keyboard, coord_int) if keyboard.implicit_modifier == self.modifier: keyboard.implicit_modifier = None + keyboard.hid_pending = True def __repr__(self): return ( diff --git a/tests/test_kmk_keys.py b/tests/test_kmk_keys.py index 4e0a51faa..65d9929d3 100644 --- a/tests/test_kmk_keys.py +++ b/tests/test_kmk_keys.py @@ -51,6 +51,7 @@ def test_modified_keys(self): KC.RALT(KC.LSFT), KC.RALT(KC.LSFT(KC.N4)), KC.LSFT, + KC.N1, ] ], debug_enabled=False, @@ -86,6 +87,18 @@ def test_modified_keys(self): [{KC.LSFT, KC.N1}, {KC.LSFT}, {}], ) + keyboard.test( + 'Shifted key + unshifted key rolled', + [(1, True), (6, True), (1, False), (6, False)], + [{KC.LSFT, KC.N1}, {}, {KC.N1}, {}], + ) + + keyboard.test( + 'Unshifted key + shifted key rolled', + [(6, True), (1, True), (6, False), (1, False)], + [{KC.N1}, {}, {KC.LSFT, KC.N1}, {KC.LSFT}, {}], + ) + keyboard.test( 'Shift + shifted key', [(5, True), (1, True), (5, False), (1, False)], @@ -98,6 +111,17 @@ def test_modified_keys(self): [{KC.RALT, KC.LSFT, KC.N2}, {}], ) + keyboard.test( + 'Shifted key + modified shifted key rolled', + [(1, True), (2, True), (1, False), (2, False)], + [ + {KC.LSFT, KC.N1}, + {KC.RALT, KC.LSFT, KC.N1, KC.N2}, + {KC.RALT, KC.LSFT, KC.N2}, + {}, + ], + ) + keyboard.test( 'Modified modifier', [(3, True), (3, False)],