Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ModifiedKey roll-interaction with same non-modified keys #1072

Merged
merged 1 commit into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 41 additions & 29 deletions kmk/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)


Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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 (
Expand Down
24 changes: 24 additions & 0 deletions tests/test_kmk_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)],
Expand All @@ -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)],
Expand Down
Loading