class Listener(ListenerMixin, _base.Listener): #: The Windows hook ID for low level keyboard events, ``WH_KEYBOARD_LL`` _EVENTS = 13 _WM_INPUTLANGCHANGE = 0x0051 _WM_KEYDOWN = 0x0100 _WM_KEYUP = 0x0101 _WM_SYSKEYDOWN = 0x0104 _WM_SYSKEYUP = 0x0105 # A bit flag attached to messages indicating that the payload is an actual # UTF-16 character code _UTF16_FLAG = 0x1000 # A special virtual key code designating unicode characters _VK_PACKET = 0xE7 #: The messages that correspond to a key press _PRESS_MESSAGES = (_WM_KEYDOWN, _WM_SYSKEYDOWN) #: The messages that correspond to a key release _RELEASE_MESSAGES = (_WM_KEYUP, _WM_SYSKEYUP) #: Additional window messages to propagate to the subclass handler. _WM_NOTIFICATIONS = (_WM_INPUTLANGCHANGE, ) #: A mapping from keysym to special key _SPECIAL_KEYS = {key.value.vk: key for key in Key} _HANDLED_EXCEPTIONS = (SystemHook.SuppressException, ) class _KBDLLHOOKSTRUCT(ctypes.Structure): """Contains information about a mouse event passed to a ``WH_KEYBOARD_LL`` hook procedure, ``LowLevelKeyboardProc``. """ _fields_ = [('vkCode', wintypes.DWORD), ('scanCode', wintypes.DWORD), ('flags', wintypes.DWORD), ('time', wintypes.DWORD), ('dwExtraInfo', ctypes.c_void_p)] #: A pointer to a :class:`KBDLLHOOKSTRUCT` _LPKBDLLHOOKSTRUCT = ctypes.POINTER(_KBDLLHOOKSTRUCT) def __init__(self, *args, **kwargs): super(Listener, self).__init__(*args, **kwargs) self._translator = KeyTranslator() self._event_filter = self._options.get('event_filter', lambda msg, data: True) def _convert(self, code, msg, lpdata): if code != SystemHook.HC_ACTION: return data = ctypes.cast(lpdata, self._LPKBDLLHOOKSTRUCT).contents is_packet = data.vkCode == self._VK_PACKET # Suppress further propagation of the event if it is filtered if self._event_filter(msg, data) is False: return None elif is_packet: return (msg | self._UTF16_FLAG, data.scanCode) else: return (msg, data.vkCode) @AbstractListener._emitter def _process(self, wparam, lparam): msg = wparam vk = lparam # If the key has the UTF-16 flag, we treat it as a unicode character, # otherwise convert the event to a KeyCode; this may fail, and in that # case we pass None is_utf16 = msg & self._UTF16_FLAG if is_utf16: msg = msg ^ self._UTF16_FLAG scan = vk key = KeyCode.from_char(six.unichr(scan)) else: try: key = self._event_to_key(msg, vk) except OSError: key = None if msg in self._PRESS_MESSAGES: self.on_press(key) elif msg in self._RELEASE_MESSAGES: self.on_release(key) # pylint: disable=R0201 @contextlib.contextmanager def _receive(self): """An empty context manager; we do not need to fake keyboard events. """ yield # pylint: enable=R0201 def _on_notification(self, code, wparam, lparam): """Receives ``WM_INPUTLANGCHANGE`` and updates the cached layout. """ if code == self._WM_INPUTLANGCHANGE: self._translator.update_layout() def _event_to_key(self, msg, vk): """Converts an :class:`_KBDLLHOOKSTRUCT` to a :class:`KeyCode`. :param msg: The message received. :param vk: The virtual key code to convert. :return: a :class:`pynput.keyboard.KeyCode` :raises OSError: if the message and data could not be converted """ # If the virtual key code corresponds to a Key value, we prefer that if vk in self._SPECIAL_KEYS: return self._SPECIAL_KEYS[vk] else: return KeyCode(**self._translate(vk, msg in self._PRESS_MESSAGES)) def _translate(self, vk, is_press): """Translates a virtual key code to a parameter list passable to :class:`pynput.keyboard.KeyCode`. :param int vk: The virtual key code. :param bool is_press: Whether this is a press event. :return: a parameter list to the :class:`pynput.keyboard.KeyCode` constructor """ return self._translator(vk, is_press) def canonical(self, key): # If the key has a scan code, and we can find the character for it, # return that, otherwise call the super class scan = getattr(key, '_scan', None) if scan is not None: char = self._translator.char_from_scan(scan) if char is not None: return KeyCode.from_char(char) return super(Listener, self).canonical(key)
def __init__(self, *args, **kwargs): super(Listener, self).__init__(*args, **kwargs) self._translator = KeyTranslator() self._event_filter = self._options.get( 'event_filter', lambda msg, data: True)
def __init__(self, *args, **kwargs): super(Listener, self).__init__(*args, **kwargs) self._translator = KeyTranslator()