# ========================================================================== #
#                                                                            #
#    KVMD - The main PiKVM daemon.                                           #
#                                                                            #
#    Copyright (C) 2018-2022  Maxim Devaev <mdevaev@gmail.com>               #
#                                                                            #
#    This program is free software: you can redistribute it and/or modify    #
#    it under the terms of the GNU General Public License as published by    #
#    the Free Software Foundation, either version 3 of the License, or       #
#    (at your option) any later version.                                     #
#                                                                            #
#    This program is distributed in the hope that it will be useful,         #
#    but WITHOUT ANY WARRANTY; without even the implied warranty of          #
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           #
#    GNU General Public License for more details.                            #
#                                                                            #
#    You should have received a copy of the GNU General Public License       #
#    along with this program.  If not, see <https://www.gnu.org/licenses/>.  #
#                                                                            #
# ========================================================================== #


import dataclasses

from typing import Dict


# =====
@dataclasses.dataclass(frozen=True)
class McuKey:
    code: int


@dataclasses.dataclass(frozen=True)
class OtgKey:
    code: int
    is_modifier: bool


@dataclasses.dataclass(frozen=True)
class Key:
    mcu: McuKey
    otg: OtgKey


KEYMAP: Dict[str, Key] = {
    "KeyA": Key(mcu=McuKey(code=1), otg=OtgKey(code=4, is_modifier=False)),
    "KeyB": Key(mcu=McuKey(code=2), otg=OtgKey(code=5, is_modifier=False)),
    "KeyC": Key(mcu=McuKey(code=3), otg=OtgKey(code=6, is_modifier=False)),
    "KeyD": Key(mcu=McuKey(code=4), otg=OtgKey(code=7, is_modifier=False)),
    "KeyE": Key(mcu=McuKey(code=5), otg=OtgKey(code=8, is_modifier=False)),
    "KeyF": Key(mcu=McuKey(code=6), otg=OtgKey(code=9, is_modifier=False)),
    "KeyG": Key(mcu=McuKey(code=7), otg=OtgKey(code=10, is_modifier=False)),
    "KeyH": Key(mcu=McuKey(code=8), otg=OtgKey(code=11, is_modifier=False)),
    "KeyI": Key(mcu=McuKey(code=9), otg=OtgKey(code=12, is_modifier=False)),
    "KeyJ": Key(mcu=McuKey(code=10), otg=OtgKey(code=13, is_modifier=False)),
    "KeyK": Key(mcu=McuKey(code=11), otg=OtgKey(code=14, is_modifier=False)),
    "KeyL": Key(mcu=McuKey(code=12), otg=OtgKey(code=15, is_modifier=False)),
    "KeyM": Key(mcu=McuKey(code=13), otg=OtgKey(code=16, is_modifier=False)),
    "KeyN": Key(mcu=McuKey(code=14), otg=OtgKey(code=17, is_modifier=False)),
    "KeyO": Key(mcu=McuKey(code=15), otg=OtgKey(code=18, is_modifier=False)),
    "KeyP": Key(mcu=McuKey(code=16), otg=OtgKey(code=19, is_modifier=False)),
    "KeyQ": Key(mcu=McuKey(code=17), otg=OtgKey(code=20, is_modifier=False)),
    "KeyR": Key(mcu=McuKey(code=18), otg=OtgKey(code=21, is_modifier=False)),
    "KeyS": Key(mcu=McuKey(code=19), otg=OtgKey(code=22, is_modifier=False)),
    "KeyT": Key(mcu=McuKey(code=20), otg=OtgKey(code=23, is_modifier=False)),
    "KeyU": Key(mcu=McuKey(code=21), otg=OtgKey(code=24, is_modifier=False)),
    "KeyV": Key(mcu=McuKey(code=22), otg=OtgKey(code=25, is_modifier=False)),
    "KeyW": Key(mcu=McuKey(code=23), otg=OtgKey(code=26, is_modifier=False)),
    "KeyX": Key(mcu=McuKey(code=24), otg=OtgKey(code=27, is_modifier=False)),
    "KeyY": Key(mcu=McuKey(code=25), otg=OtgKey(code=28, is_modifier=False)),
    "KeyZ": Key(mcu=McuKey(code=26), otg=OtgKey(code=29, is_modifier=False)),
    "Digit1": Key(mcu=McuKey(code=27), otg=OtgKey(code=30, is_modifier=False)),
    "Digit2": Key(mcu=McuKey(code=28), otg=OtgKey(code=31, is_modifier=False)),
    "Digit3": Key(mcu=McuKey(code=29), otg=OtgKey(code=32, is_modifier=False)),
    "Digit4": Key(mcu=McuKey(code=30), otg=OtgKey(code=33, is_modifier=False)),
    "Digit5": Key(mcu=McuKey(code=31), otg=OtgKey(code=34, is_modifier=False)),
    "Digit6": Key(mcu=McuKey(code=32), otg=OtgKey(code=35, is_modifier=False)),
    "Digit7": Key(mcu=McuKey(code=33), otg=OtgKey(code=36, is_modifier=False)),
    "Digit8": Key(mcu=McuKey(code=34), otg=OtgKey(code=37, is_modifier=False)),
    "Digit9": Key(mcu=McuKey(code=35), otg=OtgKey(code=38, is_modifier=False)),
    "Digit0": Key(mcu=McuKey(code=36), otg=OtgKey(code=39, is_modifier=False)),
    "Enter": Key(mcu=McuKey(code=37), otg=OtgKey(code=40, is_modifier=False)),
    "Escape": Key(mcu=McuKey(code=38), otg=OtgKey(code=41, is_modifier=False)),
    "Backspace": Key(mcu=McuKey(code=39), otg=OtgKey(code=42, is_modifier=False)),
    "Tab": Key(mcu=McuKey(code=40), otg=OtgKey(code=43, is_modifier=False)),
    "Space": Key(mcu=McuKey(code=41), otg=OtgKey(code=44, is_modifier=False)),
    "Minus": Key(mcu=McuKey(code=42), otg=OtgKey(code=45, is_modifier=False)),
    "Equal": Key(mcu=McuKey(code=43), otg=OtgKey(code=46, is_modifier=False)),
    "BracketLeft": Key(mcu=McuKey(code=44), otg=OtgKey(code=47, is_modifier=False)),
    "BracketRight": Key(mcu=McuKey(code=45), otg=OtgKey(code=48, is_modifier=False)),
    "Backslash": Key(mcu=McuKey(code=46), otg=OtgKey(code=49, is_modifier=False)),
    "Semicolon": Key(mcu=McuKey(code=47), otg=OtgKey(code=51, is_modifier=False)),
    "Quote": Key(mcu=McuKey(code=48), otg=OtgKey(code=52, is_modifier=False)),
    "Backquote": Key(mcu=McuKey(code=49), otg=OtgKey(code=53, is_modifier=False)),
    "Comma": Key(mcu=McuKey(code=50), otg=OtgKey(code=54, is_modifier=False)),
    "Period": Key(mcu=McuKey(code=51), otg=OtgKey(code=55, is_modifier=False)),
    "Slash": Key(mcu=McuKey(code=52), otg=OtgKey(code=56, is_modifier=False)),
    "CapsLock": Key(mcu=McuKey(code=53), otg=OtgKey(code=57, is_modifier=False)),
    "F1": Key(mcu=McuKey(code=54), otg=OtgKey(code=58, is_modifier=False)),
    "F2": Key(mcu=McuKey(code=55), otg=OtgKey(code=59, is_modifier=False)),
    "F3": Key(mcu=McuKey(code=56), otg=OtgKey(code=60, is_modifier=False)),
    "F4": Key(mcu=McuKey(code=57), otg=OtgKey(code=61, is_modifier=False)),
    "F5": Key(mcu=McuKey(code=58), otg=OtgKey(code=62, is_modifier=False)),
    "F6": Key(mcu=McuKey(code=59), otg=OtgKey(code=63, is_modifier=False)),
    "F7": Key(mcu=McuKey(code=60), otg=OtgKey(code=64, is_modifier=False)),
    "F8": Key(mcu=McuKey(code=61), otg=OtgKey(code=65, is_modifier=False)),
    "F9": Key(mcu=McuKey(code=62), otg=OtgKey(code=66, is_modifier=False)),
    "F10": Key(mcu=McuKey(code=63), otg=OtgKey(code=67, is_modifier=False)),
    "F11": Key(mcu=McuKey(code=64), otg=OtgKey(code=68, is_modifier=False)),
    "F12": Key(mcu=McuKey(code=65), otg=OtgKey(code=69, is_modifier=False)),
    "PrintScreen": Key(mcu=McuKey(code=66), otg=OtgKey(code=70, is_modifier=False)),
    "Insert": Key(mcu=McuKey(code=67), otg=OtgKey(code=73, is_modifier=False)),
    "Home": Key(mcu=McuKey(code=68), otg=OtgKey(code=74, is_modifier=False)),
    "PageUp": Key(mcu=McuKey(code=69), otg=OtgKey(code=75, is_modifier=False)),
    "Delete": Key(mcu=McuKey(code=70), otg=OtgKey(code=76, is_modifier=False)),
    "End": Key(mcu=McuKey(code=71), otg=OtgKey(code=77, is_modifier=False)),
    "PageDown": Key(mcu=McuKey(code=72), otg=OtgKey(code=78, is_modifier=False)),
    "ArrowRight": Key(mcu=McuKey(code=73), otg=OtgKey(code=79, is_modifier=False)),
    "ArrowLeft": Key(mcu=McuKey(code=74), otg=OtgKey(code=80, is_modifier=False)),
    "ArrowDown": Key(mcu=McuKey(code=75), otg=OtgKey(code=81, is_modifier=False)),
    "ArrowUp": Key(mcu=McuKey(code=76), otg=OtgKey(code=82, is_modifier=False)),
    "ControlLeft": Key(mcu=McuKey(code=77), otg=OtgKey(code=1, is_modifier=True)),
    "ShiftLeft": Key(mcu=McuKey(code=78), otg=OtgKey(code=2, is_modifier=True)),
    "AltLeft": Key(mcu=McuKey(code=79), otg=OtgKey(code=4, is_modifier=True)),
    "MetaLeft": Key(mcu=McuKey(code=80), otg=OtgKey(code=8, is_modifier=True)),
    "ControlRight": Key(mcu=McuKey(code=81), otg=OtgKey(code=16, is_modifier=True)),
    "ShiftRight": Key(mcu=McuKey(code=82), otg=OtgKey(code=32, is_modifier=True)),
    "AltRight": Key(mcu=McuKey(code=83), otg=OtgKey(code=64, is_modifier=True)),
    "MetaRight": Key(mcu=McuKey(code=84), otg=OtgKey(code=128, is_modifier=True)),
    "Pause": Key(mcu=McuKey(code=85), otg=OtgKey(code=72, is_modifier=False)),
    "ScrollLock": Key(mcu=McuKey(code=86), otg=OtgKey(code=71, is_modifier=False)),
    "NumLock": Key(mcu=McuKey(code=87), otg=OtgKey(code=83, is_modifier=False)),
    "ContextMenu": Key(mcu=McuKey(code=88), otg=OtgKey(code=101, is_modifier=False)),
    "NumpadDivide": Key(mcu=McuKey(code=89), otg=OtgKey(code=84, is_modifier=False)),
    "NumpadMultiply": Key(mcu=McuKey(code=90), otg=OtgKey(code=85, is_modifier=False)),
    "NumpadSubtract": Key(mcu=McuKey(code=91), otg=OtgKey(code=86, is_modifier=False)),
    "NumpadAdd": Key(mcu=McuKey(code=92), otg=OtgKey(code=87, is_modifier=False)),
    "NumpadEnter": Key(mcu=McuKey(code=93), otg=OtgKey(code=88, is_modifier=False)),
    "Numpad1": Key(mcu=McuKey(code=94), otg=OtgKey(code=89, is_modifier=False)),
    "Numpad2": Key(mcu=McuKey(code=95), otg=OtgKey(code=90, is_modifier=False)),
    "Numpad3": Key(mcu=McuKey(code=96), otg=OtgKey(code=91, is_modifier=False)),
    "Numpad4": Key(mcu=McuKey(code=97), otg=OtgKey(code=92, is_modifier=False)),
    "Numpad5": Key(mcu=McuKey(code=98), otg=OtgKey(code=93, is_modifier=False)),
    "Numpad6": Key(mcu=McuKey(code=99), otg=OtgKey(code=94, is_modifier=False)),
    "Numpad7": Key(mcu=McuKey(code=100), otg=OtgKey(code=95, is_modifier=False)),
    "Numpad8": Key(mcu=McuKey(code=101), otg=OtgKey(code=96, is_modifier=False)),
    "Numpad9": Key(mcu=McuKey(code=102), otg=OtgKey(code=97, is_modifier=False)),
    "Numpad0": Key(mcu=McuKey(code=103), otg=OtgKey(code=98, is_modifier=False)),
    "NumpadDecimal": Key(mcu=McuKey(code=104), otg=OtgKey(code=99, is_modifier=False)),
    "Power": Key(mcu=McuKey(code=105), otg=OtgKey(code=102, is_modifier=False)),
    "IntlBackslash": Key(mcu=McuKey(code=106), otg=OtgKey(code=100, is_modifier=False)),
    "IntlYen": Key(mcu=McuKey(code=107), otg=OtgKey(code=137, is_modifier=False)),
}


# =====
class WebModifiers:
    SHIFT_LEFT = "ShiftLeft"
    SHIFT_RIGHT = "ShiftRight"
    SHIFTS = set([SHIFT_LEFT, SHIFT_RIGHT])

    ALT_LEFT = "AltLeft"
    ALT_RIGHT = "AltRight"
    ALTS = set([ALT_LEFT, ALT_RIGHT])

    CTRL_LEFT = "ControlLeft"
    CTRL_RIGHT = "ControlRight"
    CTRLS = set([CTRL_RIGHT, CTRL_RIGHT])


class X11Modifiers:
    SHIFT_LEFT = 65505
    SHIFT_RIGHT = 65506
    SHIFTS = set([SHIFT_LEFT, SHIFT_RIGHT])

    ALTGR = 65027  # XK_ISO_Level3_Shift

    CTRL_LEFT = 65507
    CTRL_RIGHT = 65508
    CTRLS = set([CTRL_LEFT, CTRL_RIGHT])


# =====
@dataclasses.dataclass(frozen=True)
class At1Key:
    code: int
    shift: bool
    altgr: bool = False
    ctrl: bool = False


X11_TO_AT1 = {
    65307: [At1Key(code=1, shift=False)],  # XK_Escape
    33: [At1Key(code=2, shift=True)],  # XK_exclam
    49: [At1Key(code=2, shift=False)],  # XK_1
    50: [At1Key(code=3, shift=False)],  # XK_2
    64: [At1Key(code=3, shift=True)],  # XK_at
    35: [At1Key(code=4, shift=True)],  # XK_numbersign
    51: [At1Key(code=4, shift=False)],  # XK_3
    36: [At1Key(code=5, shift=True)],  # XK_dollar
    52: [At1Key(code=5, shift=False)],  # XK_4
    37: [At1Key(code=6, shift=True)],  # XK_percent
    53: [At1Key(code=6, shift=False)],  # XK_5
    54: [At1Key(code=7, shift=False)],  # XK_6
    94: [At1Key(code=7, shift=True)],  # XK_asciicircum
    38: [At1Key(code=8, shift=True)],  # XK_ampersand
    55: [At1Key(code=8, shift=False)],  # XK_7
    42: [At1Key(code=9, shift=True)],  # XK_asterisk
    56: [At1Key(code=9, shift=False)],  # XK_8
    40: [At1Key(code=10, shift=True)],  # XK_parenleft
    57: [At1Key(code=10, shift=False)],  # XK_9
    41: [At1Key(code=11, shift=True)],  # XK_parenright
    48: [At1Key(code=11, shift=False)],  # XK_0
    45: [At1Key(code=12, shift=False)],  # XK_minus
    95: [At1Key(code=12, shift=True)],  # XK_underscore
    43: [At1Key(code=13, shift=True)],  # XK_plus
    61: [At1Key(code=13, shift=False)],  # XK_equal
    65288: [At1Key(code=14, shift=False)],  # XK_BackSpace
    65289: [At1Key(code=15, shift=False)],  # XK_Tab
    81: [At1Key(code=16, shift=True)],  # XK_Q
    113: [At1Key(code=16, shift=False)],  # XK_q
    87: [At1Key(code=17, shift=True)],  # XK_W
    119: [At1Key(code=17, shift=False)],  # XK_w
    69: [At1Key(code=18, shift=True)],  # XK_E
    101: [At1Key(code=18, shift=False)],  # XK_e
    82: [At1Key(code=19, shift=True)],  # XK_R
    114: [At1Key(code=19, shift=False)],  # XK_r
    84: [At1Key(code=20, shift=True)],  # XK_T
    116: [At1Key(code=20, shift=False)],  # XK_t
    89: [At1Key(code=21, shift=True)],  # XK_Y
    121: [At1Key(code=21, shift=False)],  # XK_y
    85: [At1Key(code=22, shift=True)],  # XK_U
    117: [At1Key(code=22, shift=False)],  # XK_u
    73: [At1Key(code=23, shift=True)],  # XK_I
    105: [At1Key(code=23, shift=False)],  # XK_i
    79: [At1Key(code=24, shift=True)],  # XK_O
    111: [At1Key(code=24, shift=False)],  # XK_o
    80: [At1Key(code=25, shift=True)],  # XK_P
    112: [At1Key(code=25, shift=False)],  # XK_p
    91: [At1Key(code=26, shift=False)],  # XK_bracketleft
    123: [At1Key(code=26, shift=True)],  # XK_braceleft
    93: [At1Key(code=27, shift=False)],  # XK_bracketright
    125: [At1Key(code=27, shift=True)],  # XK_braceright
    65293: [At1Key(code=28, shift=False)],  # XK_Return
    65507: [At1Key(code=29, shift=False)],  # XK_Control_L
    65: [At1Key(code=30, shift=True)],  # XK_A
    97: [At1Key(code=30, shift=False)],  # XK_a
    83: [At1Key(code=31, shift=True)],  # XK_S
    115: [At1Key(code=31, shift=False)],  # XK_s
    68: [At1Key(code=32, shift=True)],  # XK_D
    100: [At1Key(code=32, shift=False)],  # XK_d
    70: [At1Key(code=33, shift=True)],  # XK_F
    102: [At1Key(code=33, shift=False)],  # XK_f
    71: [At1Key(code=34, shift=True)],  # XK_G
    103: [At1Key(code=34, shift=False)],  # XK_g
    72: [At1Key(code=35, shift=True)],  # XK_H
    104: [At1Key(code=35, shift=False)],  # XK_h
    74: [At1Key(code=36, shift=True)],  # XK_J
    106: [At1Key(code=36, shift=False)],  # XK_j
    75: [At1Key(code=37, shift=True)],  # XK_K
    107: [At1Key(code=37, shift=False)],  # XK_k
    76: [At1Key(code=38, shift=True)],  # XK_L
    108: [At1Key(code=38, shift=False)],  # XK_l
    58: [At1Key(code=39, shift=True)],  # XK_colon
    59: [At1Key(code=39, shift=False)],  # XK_semicolon
    34: [At1Key(code=40, shift=True)],  # XK_quotedbl
    39: [At1Key(code=40, shift=False)],  # XK_apostrophe
    96: [At1Key(code=41, shift=False)],  # XK_grave
    126: [At1Key(code=41, shift=True)],  # XK_asciitilde
    65505: [At1Key(code=42, shift=False)],  # XK_Shift_L
    92: [At1Key(code=43, shift=False)],  # XK_backslash
    124: [At1Key(code=43, shift=True)],  # XK_bar
    90: [At1Key(code=44, shift=True)],  # XK_Z
    122: [At1Key(code=44, shift=False)],  # XK_z
    88: [At1Key(code=45, shift=True)],  # XK_X
    120: [At1Key(code=45, shift=False)],  # XK_x
    67: [At1Key(code=46, shift=True)],  # XK_C
    99: [At1Key(code=46, shift=False)],  # XK_c
    86: [At1Key(code=47, shift=True)],  # XK_V
    118: [At1Key(code=47, shift=False)],  # XK_v
    66: [At1Key(code=48, shift=True)],  # XK_B
    98: [At1Key(code=48, shift=False)],  # XK_b
    78: [At1Key(code=49, shift=True)],  # XK_N
    110: [At1Key(code=49, shift=False)],  # XK_n
    77: [At1Key(code=50, shift=True)],  # XK_M
    109: [At1Key(code=50, shift=False)],  # XK_m
    44: [At1Key(code=51, shift=False)],  # XK_comma
    60: [At1Key(code=51, shift=True)],  # XK_less
    46: [At1Key(code=52, shift=False)],  # XK_period
    62: [At1Key(code=52, shift=True)],  # XK_greater
    47: [At1Key(code=53, shift=False)],  # XK_slash
    63: [At1Key(code=53, shift=True)],  # XK_question
    65506: [At1Key(code=54, shift=False)],  # XK_Shift_R
    215: [At1Key(code=55, shift=False)],  # XK_multiply
    65513: [At1Key(code=56, shift=False)],  # XK_Alt_L
    32: [At1Key(code=57, shift=False)],  # XK_space
    65509: [At1Key(code=58, shift=False)],  # XK_Caps_Lock
    65470: [At1Key(code=59, shift=False)],  # XK_F1
    65471: [At1Key(code=60, shift=False)],  # XK_F2
    65472: [At1Key(code=61, shift=False)],  # XK_F3
    65473: [At1Key(code=62, shift=False)],  # XK_F4
    65474: [At1Key(code=63, shift=False)],  # XK_F5
    65475: [At1Key(code=64, shift=False)],  # XK_F6
    65476: [At1Key(code=65, shift=False)],  # XK_F7
    65477: [At1Key(code=66, shift=False)],  # XK_F8
    65478: [At1Key(code=67, shift=False)],  # XK_F9
    65479: [At1Key(code=68, shift=False)],  # XK_F10
    65407: [At1Key(code=69, shift=False)],  # XK_Num_Lock
    65300: [At1Key(code=70, shift=False)],  # XK_Scroll_Lock
    65463: [At1Key(code=71, shift=False)],  # XK_KP_7
    65464: [At1Key(code=72, shift=False)],  # XK_KP_8
    65465: [At1Key(code=73, shift=False)],  # XK_KP_9
    65453: [At1Key(code=74, shift=False)],  # XK_KP_Subtract
    65460: [At1Key(code=75, shift=False)],  # XK_KP_4
    65461: [At1Key(code=76, shift=False)],  # XK_KP_5
    65462: [At1Key(code=77, shift=False)],  # XK_KP_6
    65451: [At1Key(code=78, shift=False)],  # XK_KP_Add
    65457: [At1Key(code=79, shift=False)],  # XK_KP_1
    65458: [At1Key(code=80, shift=False)],  # XK_KP_2
    65459: [At1Key(code=81, shift=False)],  # XK_KP_3
    65456: [At1Key(code=82, shift=False)],  # XK_KP_0
    65454: [At1Key(code=83, shift=False)],  # XK_KP_Decimal
    65301: [At1Key(code=84, shift=False)],  # XK_Sys_Req
    65480: [At1Key(code=87, shift=False)],  # XK_F11
    65481: [At1Key(code=88, shift=False)],  # XK_F12
    65421: [At1Key(code=57372, shift=False)],  # XK_KP_Enter
    65508: [At1Key(code=57373, shift=False)],  # XK_Control_R
    65455: [At1Key(code=57397, shift=False)],  # XK_KP_Divide
    65027: [At1Key(code=57400, shift=False)],  # XK_ISO_Level3_Shift
    65514: [At1Key(code=57400, shift=False)],  # XK_Alt_R
    65299: [At1Key(code=57414, shift=False)],  # XK_Pause
    65360: [At1Key(code=57415, shift=False)],  # XK_Home
    65362: [At1Key(code=57416, shift=False)],  # XK_Up
    65365: [At1Key(code=57417, shift=False)],  # XK_Page_Up
    65361: [At1Key(code=57419, shift=False)],  # XK_Left
    65363: [At1Key(code=57421, shift=False)],  # XK_Right
    65367: [At1Key(code=57423, shift=False)],  # XK_End
    65364: [At1Key(code=57424, shift=False)],  # XK_Down
    65366: [At1Key(code=57425, shift=False)],  # XK_Page_Down
    65379: [At1Key(code=57426, shift=False)],  # XK_Insert
    65535: [At1Key(code=57427, shift=False)],  # XK_Delete
    65511: [At1Key(code=57435, shift=False)],  # XK_Meta_L
    65515: [At1Key(code=57435, shift=False)],  # XK_Super_L
    65512: [At1Key(code=57436, shift=False)],  # XK_Meta_R
    65516: [At1Key(code=57436, shift=False)],  # XK_Super_R
    65383: [At1Key(code=57437, shift=False)],  # XK_Menu
    269025071: [At1Key(code=57438, shift=False)],  # XK_XF86_Sleep
}


AT1_TO_WEB = {
    1: "Escape",
    2: "Digit1",
    3: "Digit2",
    4: "Digit3",
    5: "Digit4",
    6: "Digit5",
    7: "Digit6",
    8: "Digit7",
    9: "Digit8",
    10: "Digit9",
    11: "Digit0",
    12: "Minus",
    13: "Equal",
    14: "Backspace",
    15: "Tab",
    16: "KeyQ",
    17: "KeyW",
    18: "KeyE",
    19: "KeyR",
    20: "KeyT",
    21: "KeyY",
    22: "KeyU",
    23: "KeyI",
    24: "KeyO",
    25: "KeyP",
    26: "BracketLeft",
    27: "BracketRight",
    28: "Enter",
    29: "ControlLeft",
    30: "KeyA",
    31: "KeyS",
    32: "KeyD",
    33: "KeyF",
    34: "KeyG",
    35: "KeyH",
    36: "KeyJ",
    37: "KeyK",
    38: "KeyL",
    39: "Semicolon",
    40: "Quote",
    41: "Backquote",
    42: "ShiftLeft",
    43: "Backslash",
    44: "KeyZ",
    45: "KeyX",
    46: "KeyC",
    47: "KeyV",
    48: "KeyB",
    49: "KeyN",
    50: "KeyM",
    51: "Comma",
    52: "Period",
    53: "Slash",
    54: "ShiftRight",
    55: "NumpadMultiply",
    56: "AltLeft",
    57: "Space",
    58: "CapsLock",
    59: "F1",
    60: "F2",
    61: "F3",
    62: "F4",
    63: "F5",
    64: "F6",
    65: "F7",
    66: "F8",
    67: "F9",
    68: "F10",
    69: "NumLock",
    70: "ScrollLock",
    71: "Numpad7",
    72: "Numpad8",
    73: "Numpad9",
    74: "NumpadSubtract",
    75: "Numpad4",
    76: "Numpad5",
    77: "Numpad6",
    78: "NumpadAdd",
    79: "Numpad1",
    80: "Numpad2",
    81: "Numpad3",
    82: "Numpad0",
    83: "NumpadDecimal",
    84: "PrintScreen",
    86: "IntlBackslash",
    87: "F11",
    88: "F12",
    125: "IntlYen",
    57372: "NumpadEnter",
    57373: "ControlRight",
    57397: "NumpadDivide",
    57400: "AltRight",
    57414: "Pause",
    57415: "Home",
    57416: "ArrowUp",
    57417: "PageUp",
    57419: "ArrowLeft",
    57421: "ArrowRight",
    57423: "End",
    57424: "ArrowDown",
    57425: "PageDown",
    57426: "Insert",
    57427: "Delete",
    57435: "MetaLeft",
    57436: "MetaRight",
    57437: "ContextMenu",
    57438: "Power",
}
