-
Notifications
You must be signed in to change notification settings - Fork 283
Incorrect keyboard mapping for Dvorak Programmer Layout on Xorg #652
Description
Description
When using pynput.Keyboard on Xorg to type on a keyboard with the Dvorak Programmer layout, most characters are correct, but a few are incorrect. If I try to type "Y" via Controller().press('Y') then an "F" is typed. I believe I've tracked this down to not having an AltGr key set on this keyboard layout.
Xlib.display.Display.keysym_to_keycode returns a 0 if the keysym is not bound to any key. This causes the __altgr_mask, and then the group_mask in pynput._util.xorg.keyboard_mapping (see below) to become 1, the same as the shift mask. When constructing the mapping dict in that function, the "Y" keysym is written to mapping correctly an first, but the key_codes to a few keysyms (e.g. "Y", "C", "?") get overwritten with the QWERTY layout key_code. A hacky workaround is shown below (added break statement).
def keyboard_mapping(display):
"""Generates a mapping from *keysyms* to *key codes* and required
modifier shift states.
:param Xlib.display.Display display: The display for which to retrieve the
keyboard mapping.
:return: the keyboard mapping
"""
mapping = {}
shift_mask = 1 << 0
group_mask = alt_gr_mask(display)
# Iterate over all keysym lists in the keyboard mapping
min_keycode = display.display.info.min_keycode
keycode_count = display.display.info.max_keycode - min_keycode + 1
for index, keysyms in enumerate(display.get_keyboard_mapping(
min_keycode, keycode_count)):
key_code = index + min_keycode
# Normalise the keysym list to yield a tuple containing the two groups
normalized = keysym_normalize(keysyms)
if not normalized:
continue
# Iterate over the groups to extract the shift and modifier state
for groups, group in zip(normalized, (False, True)):
for keysym, shift in zip(groups, (False, True)):
if not keysym:
continue
shift_state = 0 \
| (shift_mask if shift else 0) \
| (group_mask if group else 0)
# Prefer already known lesser shift states
if keysym in mapping and mapping[keysym][1] < shift_state:
continue
mapping[keysym] = (key_code, shift_state)
break # <---------- Adding this break "fixes" the issue for me, though of course this isn't the right solution
return mappingPlatform and pynput version
Your operating system and version, and the version of pynput.
Ubuntu 24.04
Pynput 1.8.1