Skip to content
Open
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
24 changes: 20 additions & 4 deletions lib/pynput/_util/xorg.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import operator
import Xlib.display
import Xlib.keysymdef
import Xlib.keysymdef.xkb
import Xlib.threaded
import Xlib.XK

Expand Down Expand Up @@ -94,9 +95,21 @@ def _find_mask(display, symbol):
:return: the modifier mask
"""
# Get the key code for the symbol
modifier_keycode = display.keysym_to_keycode(
Xlib.XK.string_to_keysym(symbol)
)
keysym = Xlib.XK.string_to_keysym(symbol)
if not keysym:
# pylint: disable=W0702; we want to ignore errors
try:
keysym = getattr(Xlib.keysymdef.xkb, 'XK_' + symbol, 0)
except:
pass
# pylint: enable=W0702

if not keysym:
return 0

modifier_keycode = display.keysym_to_keycode(keysym)
if not modifier_keycode:
return 0

for index, keycodes in enumerate(display.get_modifier_mapping()):
for keycode in keycodes:
Expand Down Expand Up @@ -132,7 +145,10 @@ def alt_gr_mask(display):
:return: the modifier mask
"""
if not hasattr(display, '__altgr_mask'):
display.__altgr_mask = _find_mask(display, 'Mode_switch')
mask = _find_mask(display, 'Mode_switch')
if not mask:
mask = _find_mask(display, 'ISO_Level3_Shift')
display.__altgr_mask = mask
return display.__altgr_mask


Expand Down
36 changes: 36 additions & 0 deletions lib/pynput/keyboard/_xorg.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,16 @@ def __init__(self, *args, **kwargs):
self.ALT_GR_MASK = alt_gr_mask(self._display)
# pylint: enable=C0103

if Key.alt_gr.value.vk:
try:
import Xlib.keysymdef.xkb as _xkb
if not self._display.keysym_to_keycode(Key.alt_gr.value.vk):
iso_vk = getattr(_xkb, 'XK_ISO_Level3_Shift', 0)
if iso_vk and self._display.keysym_to_keycode(iso_vk):
Key.alt_gr.value.vk = iso_vk
except:
pass

def __del__(self):
if hasattr(self, '_display'):
self._display.close()
Expand Down Expand Up @@ -518,6 +528,12 @@ class Listener(ListenerMixin, _base.Listener):

#: A mapping from keysym to special key
_SPECIAL_KEYS = {key.value.vk: key for key in Key}
try:
import Xlib.keysymdef.xkb as _xkb
if hasattr(_xkb, 'XK_ISO_Level3_Shift'):
_SPECIAL_KEYS[_xkb.XK_ISO_Level3_Shift] = Key.alt_gr
except (ImportError, AttributeError):
pass

#: A mapping from numeric keypad keys to keys
_KEYPAD_KEYS = {
Expand Down Expand Up @@ -565,6 +581,17 @@ def _run(self):
super(Listener, self)._run()

def _initialize(self, display):
# Ensure Key.alt_gr.value.vk matches the active system keysym for AltGr
if Key.alt_gr.value.vk:
try:
import Xlib.keysymdef.xkb as _xkb
if not display.keysym_to_keycode(Key.alt_gr.value.vk):
iso_vk = getattr(_xkb, 'XK_ISO_Level3_Shift', 0)
if iso_vk and display.keysym_to_keycode(iso_vk):
Key.alt_gr.value.vk = iso_vk
except:
pass

# Get the keyboard mapping to be able to translate event details to
# key codes
min_keycode = display.display.info.min_keycode
Expand Down Expand Up @@ -624,6 +651,15 @@ def _keycode_to_keysym(self, display, keycode, index):

:return: a keysym
"""
if index & 0x2 and self._keyboard_mapping is not None:
try:
min_keycode = display.display.info.min_keycode
keysyms = self._keyboard_mapping[keycode - min_keycode]
if len(keysyms) >= 6 and keysyms[index + 2] != 0:
return keysyms[index + 2]
except (IndexError, TypeError):
pass

keysym = display.keycode_to_keysym(keycode, index)
if keysym:
return keysym
Expand Down