diff --git a/pynput_service.py b/pynput_service.py index 90b8741ce..14a8f1793 100644 --- a/pynput_service.py +++ b/pynput_service.py @@ -1,12 +1,10 @@ from pynput.keyboard import Key, Controller from pynput.keyboard._xorg import KeyCode from pynput._util.xorg import display_manager +import Xlib import os import sys import socket -from Xlib.ext.xtest import fake_input -from Xlib import X -import Xlib KeyCode._from_symbol("\0") # test @@ -17,15 +15,52 @@ class MyController(Controller): :param event: The *X* keyboard event. :param int keysym: The keysym to handle. """ + event = Xlib.display.event.KeyPress if is_press \ + else Xlib.display.event.KeyRelease keysym = self._keysym(key) - keycode = self._display.keysym_to_keycode(keysym) - with display_manager(self._display) as dm: - Xlib.ext.xtest.fake_input( - dm, - Xlib.X.KeyPress if is_press else Xlib.X.KeyRelease, - keycode) + # Make sure to verify that the key was resolved + if keysym is None: + raise self.InvalidKeyException(key) + # If the key has a virtual key code, use that immediately with + # fake_input; fake input,being an X server extension, has access to + # more internal state that we do + if key.vk is not None: + with display_manager(self._display) as dm: + Xlib.ext.xtest.fake_input( + dm, + Xlib.X.KeyPress if is_press else Xlib.X.KeyRelease, + dm.keysym_to_keycode(key.vk)) + + # Otherwise use XSendEvent; we need to use this in the general case to + # work around problems with keyboard layouts + else: + try: + keycode = self._display.keysym_to_keycode(keysym) + with self.modifiers as modifiers: + alt_gr = Key.alt_gr in modifiers + if alt_gr: + keycode, shift_state = self.keyboard_mapping[keysym] + self._send_key(event, keycode, shift_state) + else: + with display_manager(self._display) as dm: + Xlib.ext.xtest.fake_input( + dm, + Xlib.X.KeyPress if is_press else Xlib.X.KeyRelease, + keycode) + except KeyError: + with self._borrow_lock: + keycode, index, count = self._borrows[keysym] + self._send_key( + event, + keycode, + index_to_shift(self._display, index)) + count += 1 if is_press else -1 + self._borrows[keysym] = (keycode, index, count) + + # Notify any running listeners + self._emit('_on_fake_event', key, is_press) keyboard = MyController()