def _send_key(self, event, keycode, shift_state): """Sends a single keyboard event. :param event: The *X* keyboard event. :param int keycode: The calculated keycode. :param int shift_state: The shift state. The actual value used is :attr:`shift_state` or'd with this value. """ with display_manager(self._display) as dm, self.modifiers as modifiers: # Under certain cimcumstances, such as when running under Xephyr, # the value returned by dm.get_input_focus is an int window = dm.get_input_focus().focus send_event = getattr(window, 'send_event', lambda event: dm.send_event(window, event)) send_event( event(detail=keycode, state=shift_state | self._shift_mask(modifiers), time=0, root=dm.screen().root, window=window, same_screen=0, child=Xlib.X.NONE, root_x=0, root_y=0, event_x=0, event_y=0))
def _resolve_borrowing(self, key): """Tries to resolve a key by modifying the layout temporarily. A borrowed *keysym* does not exist on the keyboard, but is temporarily added to the layout. :param KeyCode key: The key to resolve. """ keysym = self._key_to_keysym(key) if keysym is None: return None mapping = self._display.get_keyboard_mapping(8, 255 - 8) def i2kc(index): return index + 8 def kc2i(keycode): return keycode - 8 #: Finds a keycode and index by looking at already used keycodes def reuse(): for _, (keycode, _, _) in self._borrows.items(): keycodes = mapping[kc2i(keycode)] # Only the first four items are addressable by X for index in range(4): if not keycodes[index]: return keycode, index #: Finds a keycode and index by using a new keycode def borrow(): for i, keycodes in enumerate(mapping): if not any(keycodes): return i2kc(i), 0 #: Finds a keycode and index by reusing an old, unused one def overwrite(): for keysym, (keycode, index, count) in self._borrows.items(): if count < 1: del self._borrows[keysym] return keycode, index #: Registers a keycode for a specific key and modifier state def register(dm, keycode, index): i = kc2i(keycode) mapping[i][index] = keysym dm.change_keyboard_mapping(keycode, mapping[i:i + 1]) self._borrows[keysym] = (keycode, index, 0) try: with display_manager(self._display) as dm, self._borrow_lock as _: # First try an already used keycode, then try a new one, and # fall back on reusing one that is not currently pressed register(dm, *(reuse() or borrow() or overwrite())) return keysym except TypeError: return None
def _handle(self, key, is_press): """Resolves a key identifier and sends a keyboard event. :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) # 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 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, shift_state = self.keyboard_mapping[keysym] self._send_key(event, keycode, shift_state) 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)
def _release(self, button): with display_manager(self._display) as dm: Xlib.ext.xtest.fake_input(dm, Xlib.X.ButtonRelease, button.value)
def _press(self, button): with display_manager(self._display) as dm: Xlib.ext.xtest.fake_input(dm, Xlib.X.ButtonPress, button.value)
def _position_set(self, pos): px, py = self._check_bounds(*pos) with display_manager(self._display) as dm: Xlib.ext.xtest.fake_input(dm, Xlib.X.MotionNotify, x=px, y=py)
def _position_get(self): with display_manager(self._display) as dm: qp = dm.screen().root.query_pointer() return (qp.root_x, qp.root_y)
def _update_keyboard_mapping(self): """Updates the keyboard mapping. """ with display_manager(self._display) as dm: self._keyboard_mapping = keyboard_mapping(dm)