import dataclasses class Error(Exception): pass class UnrecognizedKeyCodeError(Error): pass @dataclasses.dataclass class JavaScriptKeyEvent: meta_modifier: bool alt_modifier: bool shift_modifier: bool ctrl_modifier: bool key: str key_code: int # JS keycodes source: https://github.com/wesbos/keycodes # HID keycodes source: https://gist.github.com/MightyPork/6da26e382a7ad91b5496ee55fdc73db2 # TODO: For simplicity, we map all modifiers keys to the left key, but we could # support distinct keys for left and right if we check the location parameter # from the JavaScript message. _JS_TO_HID_KEYCODES = { 3: 0x48, # Pause / Break 8: 0x2a, # Backspace / Delete 9: 0x2b, # Tab 12: 0x53, # Clear 13: 0x28, # Enter 16: 0xe1, # Shift (Left) 17: 0xe0, # Ctrl (left) 18: 0xe1, # Alt (left) 19: 0x48, # Pause / Break 20: 0x39, # Caps Lock 21: 0x90, # Hangeul 25: 0x91, # Hanja 27: 0x29, # Escape 32: 0x2c, # Spacebar 33: 0x4b, # Page Up 34: 0x4e, # Page Down 35: 0x4d, # End 36: 0x4a, # Home 37: 0x50, # Left Arrow 38: 0x52, # Up Arrow 39: 0x4f, # Right Arrow 40: 0x51, # Down Arrow 41: 0x77, # Select 43: 0x74, # Execute 44: 0x46, # Print Screen 45: 0x49, # Insert 46: 0x4c, # Delete 47: 0x75, # Help 48: 0x27, # 0 49: 0x1e, # 1 50: 0x1f, # 2 51: 0x20, # 3 52: 0x21, # 4 53: 0x22, # 5 54: 0x23, # 6 55: 0x24, # 7 56: 0x25, # 8 57: 0x26, # 9 59: 0x33, # Semicolon 60: 0xc5, # < 61: 0x2e, # Equal sign 65: 0x04, # a 66: 0x05, # b 67: 0x06, # c 68: 0x07, # d 69: 0x08, # e 70: 0x09, # f 71: 0x0a, # g 72: 0x0b, # h 73: 0x0c, # i 74: 0x0d, # j 75: 0x0e, # k 76: 0x0f, # l 77: 0x10, # m 78: 0x11, # n 79: 0x12, # o 80: 0x13, # p 81: 0x14, # q 82: 0x15, # r 83: 0x16, # s 84: 0x17, # t 85: 0x18, # u 86: 0x19, # v 87: 0x1a, # w 88: 0x1b, # x 89: 0x1c, # y 90: 0x1d, # z 91: 0xe3, # Windows key / Meta Key (Left) 96: 0x62, # Numpad 0 97: 0x59, # Numpad 1 98: 0x5a, # Numpad 2 99: 0x5b, # Numpad 3 100: 0x5c, # Numpad 4 101: 0x5d, # Numpad 5 102: 0x5e, # Numpad 6 103: 0x5f, # Numpad 7 104: 0x60, # Numpad 8 105: 0x61, # Numpad 9 112: 0x3a, # F1 113: 0x3b, # F2 114: 0x3c, # F3 115: 0x3d, # F4 116: 0x3e, # F5 117: 0x3f, # F6 118: 0x40, # F7 119: 0x41, # F8 120: 0x42, # F9 121: 0x43, # F10 122: 0x44, # F11 123: 0x45, # F12 124: 0x68, # F13 125: 0x69, # F14 126: 0x6a, # F15 127: 0x6b, # F16 128: 0x6c, # F17 129: 0x6d, # F18 130: 0x6e, # F19 131: 0x6f, # F20 132: 0x70, # F21 133: 0x71, # F22 134: 0x72, # F23 144: 0x53, # Num Lock 145: 0x47, # Scroll Lock 161: 0x1e, # ! 163: 0x32, # Hash 173: 0x2d, # Minus 179: 0xe8, # Media play/pause 168: 0xfa, # Refresh 186: 0x33, # Semicolon 187: 0x2e, # Equal sign 188: 0x36, # Comma 189: 0x2d, # Minus sign 190: 0x37, # Period 191: 0x38, # Forward slash 192: 0x35, # Accent grave 219: 0x2f, # Left bracket ([, {]) 220: 0x31, # Back slash 221: 0x30, # Right bracket (], }) 222: 0x34, # Single quote 223: 0x35, # Accent grave (`) } def convert(js_key_event): control_chars = 0 for i, pressed in enumerate([ js_key_event.ctrl_modifier, js_key_event.shift_modifier, js_key_event.alt_modifier, js_key_event.meta_modifier ]): if pressed: control_chars |= 1 << i try: return control_chars, _JS_TO_HID_KEYCODES[js_key_event.key_code] except KeyError: raise UnrecognizedKeyCodeError( 'Unrecognized key code %s (%d)' % (js_key_event.key, js_key_event.key_code))