diff options
Diffstat (limited to 'Python/venv1/Lib/site-packages/keyboard/_winkeyboard.py')
| -rw-r--r-- | Python/venv1/Lib/site-packages/keyboard/_winkeyboard.py | 620 |
1 files changed, 0 insertions, 620 deletions
diff --git a/Python/venv1/Lib/site-packages/keyboard/_winkeyboard.py b/Python/venv1/Lib/site-packages/keyboard/_winkeyboard.py deleted file mode 100644 index 528e95f..0000000 --- a/Python/venv1/Lib/site-packages/keyboard/_winkeyboard.py +++ /dev/null @@ -1,620 +0,0 @@ -# -*- coding: utf-8 -*- -""" -This is the Windows backend for keyboard events, and is implemented by -invoking the Win32 API through the ctypes module. This is error prone -and can introduce very unpythonic failure modes, such as segfaults and -low level memory leaks. But it is also dependency-free, very performant -well documented on Microsoft's webstie and scattered examples. - -# TODO: -- Keypad numbers still print as numbers even when numlock is off. -- No way to specify if user wants a keypad key or not in `map_char`. -""" -from __future__ import unicode_literals -import re -import atexit -import traceback -from threading import Lock -from collections import defaultdict - -from ._keyboard_event import KeyboardEvent, KEY_DOWN, KEY_UP -from ._canonical_names import normalize_name -try: - # Force Python2 to convert to unicode and not to str. - chr = unichr -except NameError: - pass - -# This part is just declaring Win32 API structures using ctypes. In C -# this would be simply #include "windows.h". - -import ctypes -from ctypes import c_short, c_char, c_uint8, c_int32, c_int, c_uint, c_uint32, c_long, Structure, CFUNCTYPE, POINTER -from ctypes.wintypes import WORD, DWORD, BOOL, HHOOK, MSG, LPWSTR, WCHAR, WPARAM, LPARAM, LONG, HMODULE, LPCWSTR, HINSTANCE, HWND -LPMSG = POINTER(MSG) -ULONG_PTR = POINTER(DWORD) - -kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) -GetModuleHandleW = kernel32.GetModuleHandleW -GetModuleHandleW.restype = HMODULE -GetModuleHandleW.argtypes = [LPCWSTR] - -#https://github.com/boppreh/mouse/issues/1 -#user32 = ctypes.windll.user32 -user32 = ctypes.WinDLL('user32', use_last_error = True) - -VK_PACKET = 0xE7 - -INPUT_MOUSE = 0 -INPUT_KEYBOARD = 1 -INPUT_HARDWARE = 2 - -KEYEVENTF_KEYUP = 0x02 -KEYEVENTF_UNICODE = 0x04 - -class KBDLLHOOKSTRUCT(Structure): - _fields_ = [("vk_code", DWORD), - ("scan_code", DWORD), - ("flags", DWORD), - ("time", c_int), - ("dwExtraInfo", ULONG_PTR)] - -# Included for completeness. -class MOUSEINPUT(ctypes.Structure): - _fields_ = (('dx', LONG), - ('dy', LONG), - ('mouseData', DWORD), - ('dwFlags', DWORD), - ('time', DWORD), - ('dwExtraInfo', ULONG_PTR)) - -class KEYBDINPUT(ctypes.Structure): - _fields_ = (('wVk', WORD), - ('wScan', WORD), - ('dwFlags', DWORD), - ('time', DWORD), - ('dwExtraInfo', ULONG_PTR)) - -class HARDWAREINPUT(ctypes.Structure): - _fields_ = (('uMsg', DWORD), - ('wParamL', WORD), - ('wParamH', WORD)) - -class _INPUTunion(ctypes.Union): - _fields_ = (('mi', MOUSEINPUT), - ('ki', KEYBDINPUT), - ('hi', HARDWAREINPUT)) - -class INPUT(ctypes.Structure): - _fields_ = (('type', DWORD), - ('union', _INPUTunion)) - -LowLevelKeyboardProc = CFUNCTYPE(c_int, WPARAM, LPARAM, POINTER(KBDLLHOOKSTRUCT)) - -SetWindowsHookEx = user32.SetWindowsHookExW -SetWindowsHookEx.argtypes = [c_int, LowLevelKeyboardProc, HINSTANCE , DWORD] -SetWindowsHookEx.restype = HHOOK - -CallNextHookEx = user32.CallNextHookEx -#CallNextHookEx.argtypes = [c_int , c_int, c_int, POINTER(KBDLLHOOKSTRUCT)] -CallNextHookEx.restype = c_int - -UnhookWindowsHookEx = user32.UnhookWindowsHookEx -UnhookWindowsHookEx.argtypes = [HHOOK] -UnhookWindowsHookEx.restype = BOOL - -GetMessage = user32.GetMessageW -GetMessage.argtypes = [LPMSG, HWND, c_uint, c_uint] -GetMessage.restype = BOOL - -TranslateMessage = user32.TranslateMessage -TranslateMessage.argtypes = [LPMSG] -TranslateMessage.restype = BOOL - -DispatchMessage = user32.DispatchMessageA -DispatchMessage.argtypes = [LPMSG] - - -keyboard_state_type = c_uint8 * 256 - -GetKeyboardState = user32.GetKeyboardState -GetKeyboardState.argtypes = [keyboard_state_type] -GetKeyboardState.restype = BOOL - -GetKeyNameText = user32.GetKeyNameTextW -GetKeyNameText.argtypes = [c_long, LPWSTR, c_int] -GetKeyNameText.restype = c_int - -MapVirtualKey = user32.MapVirtualKeyW -MapVirtualKey.argtypes = [c_uint, c_uint] -MapVirtualKey.restype = c_uint - -ToUnicode = user32.ToUnicode -ToUnicode.argtypes = [c_uint, c_uint, keyboard_state_type, LPWSTR, c_int, c_uint] -ToUnicode.restype = c_int - -SendInput = user32.SendInput -SendInput.argtypes = [c_uint, POINTER(INPUT), c_int] -SendInput.restype = c_uint - -# https://msdn.microsoft.com/en-us/library/windows/desktop/ms646307(v=vs.85).aspx -MAPVK_VK_TO_CHAR = 2 -MAPVK_VK_TO_VSC = 0 -MAPVK_VSC_TO_VK = 1 -MAPVK_VK_TO_VSC_EX = 4 -MAPVK_VSC_TO_VK_EX = 3 - -VkKeyScan = user32.VkKeyScanW -VkKeyScan.argtypes = [WCHAR] -VkKeyScan.restype = c_short - -LLKHF_INJECTED = 0x00000010 - -WM_KEYDOWN = 0x0100 -WM_KEYUP = 0x0101 -WM_SYSKEYDOWN = 0x104 # Used for ALT key -WM_SYSKEYUP = 0x105 - - -# This marks the end of Win32 API declarations. The rest is ours. - -keyboard_event_types = { - WM_KEYDOWN: KEY_DOWN, - WM_KEYUP: KEY_UP, - WM_SYSKEYDOWN: KEY_DOWN, - WM_SYSKEYUP: KEY_UP, -} - -# List taken from the official documentation, but stripped of the OEM-specific keys. -# Keys are virtual key codes, values are pairs (name, is_keypad). -official_virtual_keys = { - 0x03: ('control-break processing', False), - 0x08: ('backspace', False), - 0x09: ('tab', False), - 0x0c: ('clear', False), - 0x0d: ('enter', False), - 0x10: ('shift', False), - 0x11: ('ctrl', False), - 0x12: ('alt', False), - 0x13: ('pause', False), - 0x14: ('caps lock', False), - 0x15: ('ime kana mode', False), - 0x15: ('ime hanguel mode', False), - 0x15: ('ime hangul mode', False), - 0x17: ('ime junja mode', False), - 0x18: ('ime final mode', False), - 0x19: ('ime hanja mode', False), - 0x19: ('ime kanji mode', False), - 0x1b: ('esc', False), - 0x1c: ('ime convert', False), - 0x1d: ('ime nonconvert', False), - 0x1e: ('ime accept', False), - 0x1f: ('ime mode change request', False), - 0x20: ('spacebar', False), - 0x21: ('page up', False), - 0x22: ('page down', False), - 0x23: ('end', False), - 0x24: ('home', False), - 0x25: ('left', False), - 0x26: ('up', False), - 0x27: ('right', False), - 0x28: ('down', False), - 0x29: ('select', False), - 0x2a: ('print', False), - 0x2b: ('execute', False), - 0x2c: ('print screen', False), - 0x2d: ('insert', False), - 0x2e: ('delete', False), - 0x2f: ('help', False), - 0x30: ('0', False), - 0x31: ('1', False), - 0x32: ('2', False), - 0x33: ('3', False), - 0x34: ('4', False), - 0x35: ('5', False), - 0x36: ('6', False), - 0x37: ('7', False), - 0x38: ('8', False), - 0x39: ('9', False), - 0x41: ('a', False), - 0x42: ('b', False), - 0x43: ('c', False), - 0x44: ('d', False), - 0x45: ('e', False), - 0x46: ('f', False), - 0x47: ('g', False), - 0x48: ('h', False), - 0x49: ('i', False), - 0x4a: ('j', False), - 0x4b: ('k', False), - 0x4c: ('l', False), - 0x4d: ('m', False), - 0x4e: ('n', False), - 0x4f: ('o', False), - 0x50: ('p', False), - 0x51: ('q', False), - 0x52: ('r', False), - 0x53: ('s', False), - 0x54: ('t', False), - 0x55: ('u', False), - 0x56: ('v', False), - 0x57: ('w', False), - 0x58: ('x', False), - 0x59: ('y', False), - 0x5a: ('z', False), - 0x5b: ('left windows', False), - 0x5c: ('right windows', False), - 0x5d: ('applications', False), - 0x5f: ('sleep', False), - 0x60: ('0', True), - 0x61: ('1', True), - 0x62: ('2', True), - 0x63: ('3', True), - 0x64: ('4', True), - 0x65: ('5', True), - 0x66: ('6', True), - 0x67: ('7', True), - 0x68: ('8', True), - 0x69: ('9', True), - 0x6a: ('*', True), - 0x6b: ('+', True), - 0x6c: ('separator', True), - 0x6d: ('-', True), - 0x6e: ('decimal', True), - 0x6f: ('/', True), - 0x70: ('f1', False), - 0x71: ('f2', False), - 0x72: ('f3', False), - 0x73: ('f4', False), - 0x74: ('f5', False), - 0x75: ('f6', False), - 0x76: ('f7', False), - 0x77: ('f8', False), - 0x78: ('f9', False), - 0x79: ('f10', False), - 0x7a: ('f11', False), - 0x7b: ('f12', False), - 0x7c: ('f13', False), - 0x7d: ('f14', False), - 0x7e: ('f15', False), - 0x7f: ('f16', False), - 0x80: ('f17', False), - 0x81: ('f18', False), - 0x82: ('f19', False), - 0x83: ('f20', False), - 0x84: ('f21', False), - 0x85: ('f22', False), - 0x86: ('f23', False), - 0x87: ('f24', False), - 0x90: ('num lock', False), - 0x91: ('scroll lock', False), - 0xa0: ('left shift', False), - 0xa1: ('right shift', False), - 0xa2: ('left ctrl', False), - 0xa3: ('right ctrl', False), - 0xa4: ('left menu', False), - 0xa5: ('right menu', False), - 0xa6: ('browser back', False), - 0xa7: ('browser forward', False), - 0xa8: ('browser refresh', False), - 0xa9: ('browser stop', False), - 0xaa: ('browser search key', False), - 0xab: ('browser favorites', False), - 0xac: ('browser start and home', False), - 0xad: ('volume mute', False), - 0xae: ('volume down', False), - 0xaf: ('volume up', False), - 0xb0: ('next track', False), - 0xb1: ('previous track', False), - 0xb2: ('stop media', False), - 0xb3: ('play/pause media', False), - 0xb4: ('start mail', False), - 0xb5: ('select media', False), - 0xb6: ('start application 1', False), - 0xb7: ('start application 2', False), - 0xbb: ('+', False), - 0xbc: (',', False), - 0xbd: ('-', False), - 0xbe: ('.', False), - #0xbe:('/', False), # Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '/?. - 0xe5: ('ime process', False), - 0xf6: ('attn', False), - 0xf7: ('crsel', False), - 0xf8: ('exsel', False), - 0xf9: ('erase eof', False), - 0xfa: ('play', False), - 0xfb: ('zoom', False), - 0xfc: ('reserved ', False), - 0xfd: ('pa1', False), - 0xfe: ('clear', False), -} - -tables_lock = Lock() -to_name = defaultdict(list) -from_name = defaultdict(list) -scan_code_to_vk = {} - -distinct_modifiers = [ - (), - ('shift',), - ('alt gr',), - ('num lock',), - ('shift', 'num lock'), - ('caps lock',), - ('shift', 'caps lock'), - ('alt gr', 'num lock'), -] - -name_buffer = ctypes.create_unicode_buffer(32) -unicode_buffer = ctypes.create_unicode_buffer(32) -keyboard_state = keyboard_state_type() -def get_event_names(scan_code, vk, is_extended, modifiers): - is_keypad = (scan_code, vk, is_extended) in keypad_keys - is_official = vk in official_virtual_keys - if is_keypad and is_official: - yield official_virtual_keys[vk][0] - - keyboard_state[0x10] = 0x80 * ('shift' in modifiers) - keyboard_state[0x11] = 0x80 * ('alt gr' in modifiers) - keyboard_state[0x12] = 0x80 * ('alt gr' in modifiers) - keyboard_state[0x14] = 0x01 * ('caps lock' in modifiers) - keyboard_state[0x90] = 0x01 * ('num lock' in modifiers) - keyboard_state[0x91] = 0x01 * ('scroll lock' in modifiers) - unicode_ret = ToUnicode(vk, scan_code, keyboard_state, unicode_buffer, len(unicode_buffer), 0) - if unicode_ret and unicode_buffer.value: - yield unicode_buffer.value - # unicode_ret == -1 -> is dead key - # ToUnicode has the side effect of setting global flags for dead keys. - # Therefore we need to call it twice to clear those flags. - # If your 6 and 7 keys are named "^6" and "^7", this is the reason. - ToUnicode(vk, scan_code, keyboard_state, unicode_buffer, len(unicode_buffer), 0) - - name_ret = GetKeyNameText(scan_code << 16 | is_extended << 24, name_buffer, 1024) - if name_ret and name_buffer.value: - yield name_buffer.value - - char = user32.MapVirtualKeyW(vk, MAPVK_VK_TO_CHAR) & 0xFF - if char != 0: - yield chr(char) - - if not is_keypad and is_official: - yield official_virtual_keys[vk][0] - -def _setup_name_tables(): - """ - Ensures the scan code/virtual key code/name translation tables are - filled. - """ - with tables_lock: - if to_name: return - - # Go through every possible scan code, and map them to virtual key codes. - # Then vice-versa. - all_scan_codes = [(sc, user32.MapVirtualKeyExW(sc, MAPVK_VSC_TO_VK_EX, 0)) for sc in range(0x100)] - all_vks = [(user32.MapVirtualKeyExW(vk, MAPVK_VK_TO_VSC_EX, 0), vk) for vk in range(0x100)] - for scan_code, vk in all_scan_codes + all_vks: - # `to_name` and `from_name` entries will be a tuple (scan_code, vk, extended, shift_state). - if (scan_code, vk, 0, 0, 0) in to_name: - continue - - if scan_code not in scan_code_to_vk: - scan_code_to_vk[scan_code] = vk - - # Brute force all combinations to find all possible names. - for extended in [0, 1]: - for modifiers in distinct_modifiers: - entry = (scan_code, vk, extended, modifiers) - # Get key names from ToUnicode, GetKeyNameText, MapVirtualKeyW and official virtual keys. - names = list(get_event_names(*entry)) - if names: - # Also map lowercased key names, but only after the properly cased ones. - lowercase_names = [name.lower() for name in names] - to_name[entry] = names + lowercase_names - # Remember the "id" of the name, as the first techniques - # have better results and therefore priority. - for i, name in enumerate(map(normalize_name, names + lowercase_names)): - from_name[name].append((i, entry)) - - # TODO: single quotes on US INTL is returning the dead key (?), and therefore - # not typing properly. - - # Alt gr is way outside the usual range of keys (0..127) and on my - # computer is named as 'ctrl'. Therefore we add it manually and hope - # Windows is consistent in its inconsistency. - for extended in [0, 1]: - for modifiers in distinct_modifiers: - to_name[(541, 162, extended, modifiers)] = ['alt gr'] - from_name['alt gr'].append((1, (541, 162, extended, modifiers))) - - modifiers_preference = defaultdict(lambda: 10) - modifiers_preference.update({(): 0, ('shift',): 1, ('alt gr',): 2, ('ctrl',): 3, ('alt',): 4}) - def order_key(line): - i, entry = line - scan_code, vk, extended, modifiers = entry - return modifiers_preference[modifiers], i, extended, vk, scan_code - for name, entries in list(from_name.items()): - from_name[name] = sorted(set(entries), key=order_key) - -# Called by keyboard/__init__.py -init = _setup_name_tables - -# List created manually. -keypad_keys = [ - # (scan_code, virtual_key_code, is_extended) - (126, 194, 0), - (126, 194, 0), - (28, 13, 1), - (28, 13, 1), - (53, 111, 1), - (53, 111, 1), - (55, 106, 0), - (55, 106, 0), - (69, 144, 1), - (69, 144, 1), - (71, 103, 0), - (71, 36, 0), - (72, 104, 0), - (72, 38, 0), - (73, 105, 0), - (73, 33, 0), - (74, 109, 0), - (74, 109, 0), - (75, 100, 0), - (75, 37, 0), - (76, 101, 0), - (76, 12, 0), - (77, 102, 0), - (77, 39, 0), - (78, 107, 0), - (78, 107, 0), - (79, 35, 0), - (79, 97, 0), - (80, 40, 0), - (80, 98, 0), - (81, 34, 0), - (81, 99, 0), - (82, 45, 0), - (82, 96, 0), - (83, 110, 0), - (83, 46, 0), -] - -shift_is_pressed = False -altgr_is_pressed = False -ignore_next_right_alt = False -shift_vks = set([0x10, 0xa0, 0xa1]) -def prepare_intercept(callback): - """ - Registers a Windows low level keyboard hook. The provided callback will - be invoked for each high-level keyboard event, and is expected to return - True if the key event should be passed to the next program, or False if - the event is to be blocked. - - No event is processed until the Windows messages are pumped (see - start_intercept). - """ - _setup_name_tables() - - def process_key(event_type, vk, scan_code, is_extended): - global shift_is_pressed, altgr_is_pressed, ignore_next_right_alt - #print(event_type, vk, scan_code, is_extended) - - # Pressing alt-gr also generates an extra "right alt" event - if vk == 0xA5 and ignore_next_right_alt: - ignore_next_right_alt = False - return True - - modifiers = ( - ('shift',) * shift_is_pressed + - ('alt gr',) * altgr_is_pressed + - ('num lock',) * (user32.GetKeyState(0x90) & 1) + - ('caps lock',) * (user32.GetKeyState(0x14) & 1) + - ('scroll lock',) * (user32.GetKeyState(0x91) & 1) - ) - entry = (scan_code, vk, is_extended, modifiers) - if entry not in to_name: - to_name[entry] = list(get_event_names(*entry)) - - names = to_name[entry] - name = names[0] if names else None - - # TODO: inaccurate when holding multiple different shifts. - if vk in shift_vks: - shift_is_pressed = event_type == KEY_DOWN - if scan_code == 541 and vk == 162: - ignore_next_right_alt = True - altgr_is_pressed = event_type == KEY_DOWN - - is_keypad = (scan_code, vk, is_extended) in keypad_keys - return callback(KeyboardEvent(event_type=event_type, scan_code=scan_code or -vk, name=name, is_keypad=is_keypad)) - - def low_level_keyboard_handler(nCode, wParam, lParam): - try: - vk = lParam.contents.vk_code - # Ignore the second `alt` DOWN observed in some cases. - fake_alt = (LLKHF_INJECTED | 0x20) - # Ignore events generated by SendInput with Unicode. - if vk != VK_PACKET and lParam.contents.flags & fake_alt != fake_alt: - event_type = keyboard_event_types[wParam] - is_extended = lParam.contents.flags & 1 - scan_code = lParam.contents.scan_code - should_continue = process_key(event_type, vk, scan_code, is_extended) - if not should_continue: - return -1 - except Exception as e: - print('Error in keyboard hook:') - traceback.print_exc() - - return CallNextHookEx(None, nCode, wParam, lParam) - - WH_KEYBOARD_LL = c_int(13) - keyboard_callback = LowLevelKeyboardProc(low_level_keyboard_handler) - handle = GetModuleHandleW(None) - thread_id = DWORD(0) - keyboard_hook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboard_callback, handle, thread_id) - - # Register to remove the hook when the interpreter exits. Unfortunately a - # try/finally block doesn't seem to work here. - atexit.register(UnhookWindowsHookEx, keyboard_callback) - -def listen(callback): - prepare_intercept(callback) - msg = LPMSG() - while not GetMessage(msg, 0, 0, 0): - TranslateMessage(msg) - DispatchMessage(msg) - -def map_name(name): - _setup_name_tables() - - entries = from_name.get(name) - if not entries: - raise ValueError('Key name {} is not mapped to any known key.'.format(repr(name))) - for i, entry in entries: - scan_code, vk, is_extended, modifiers = entry - yield scan_code or -vk, modifiers - -def _send_event(code, event_type): - if code == 541: - # Alt-gr is made of ctrl+alt. Just sending even 541 doesn't do anything. - user32.keybd_event(0x11, code, event_type, 0) - user32.keybd_event(0x12, code, event_type, 0) - elif code > 0: - vk = scan_code_to_vk.get(code, 0) - user32.keybd_event(vk, code, event_type, 0) - else: - # Negative scan code is a way to indicate we don't have a scan code, - # and the value actually contains the Virtual key code. - user32.keybd_event(-code, 0, event_type, 0) - -def press(code): - _send_event(code, 0) - -def release(code): - _send_event(code, 2) - -def type_unicode(character): - # This code and related structures are based on - # http://stackoverflow.com/a/11910555/252218 - surrogates = bytearray(character.encode('utf-16le')) - presses = [] - releases = [] - for i in range(0, len(surrogates), 2): - higher, lower = surrogates[i:i+2] - structure = KEYBDINPUT(0, (lower << 8) + higher, KEYEVENTF_UNICODE, 0, None) - presses.append(INPUT(INPUT_KEYBOARD, _INPUTunion(ki=structure))) - structure = KEYBDINPUT(0, (lower << 8) + higher, KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, 0, None) - releases.append(INPUT(INPUT_KEYBOARD, _INPUTunion(ki=structure))) - inputs = presses + releases - nInputs = len(inputs) - LPINPUT = INPUT * nInputs - pInputs = LPINPUT(*inputs) - cbSize = c_int(ctypes.sizeof(INPUT)) - SendInput(nInputs, pInputs, cbSize) - -if __name__ == '__main__': - _setup_name_tables() - import pprint - pprint.pprint(to_name) - pprint.pprint(from_name) - #listen(lambda e: print(e.to_json()) or True) |
