#
# This file is part of Facedancer.
#
""" Helpers for HID keyboards. """
import string
from enum import IntEnum, IntFlag
# Table mapping ASCII codes to their equivalent HID keycodes.
# From the Adafruit HID library; https://github.com/adafruit/Adafruit_CircuitPython_HID/.
# Used under copyright exemption (as these are facts, rather than implementation).
#
# Like their table; the most significant bit is used to indicate whether we should press shift.
#
_ASCII_TO_KEYCODE = (
b'\x00' # NUL
b'\x00' # SOH
b'\x00' # STX
b'\x00' # ETX
b'\x00' # EOT
b'\x00' # ENQ
b'\x00' # ACK
b'\x00' # BEL \a
b'\x2a' # BS BACKSPACE \b (called DELETE in the usb.org document)
b'\x2b' # TAB \t
b'\x28' # LF \n (called Return or ENTER in the usb.org document)
b'\x00' # VT \v
b'\x00' # FF \f
b'\x00' # CR \r
b'\x00' # SO
b'\x00' # SI
b'\x00' # DLE
b'\x00' # DC1
b'\x00' # DC2
b'\x00' # DC3
b'\x00' # DC4
b'\x00' # NAK
b'\x00' # SYN
b'\x00' # ETB
b'\x00' # CAN
b'\x00' # EM
b'\x00' # SUB
b'\x29' # ESC
b'\x00' # FS
b'\x00' # GS
b'\x00' # RS
b'\x00' # US
b'\x2c' # SPACE
b'\x9e' # ! x1e|SHIFT_FLAG (shift 1)
b'\xb4' # " x34|SHIFT_FLAG (shift ')
b'\xa0' # # x20|SHIFT_FLAG (shift 3)
b'\xa1' # $ x21|SHIFT_FLAG (shift 4)
b'\xa2' # % x22|SHIFT_FLAG (shift 5)
b'\xa4' # & x24|SHIFT_FLAG (shift 7)
b'\x34' # '
b'\xa6' # ( x26|SHIFT_FLAG (shift 9)
b'\xa7' # ) x27|SHIFT_FLAG (shift 0)
b'\xa5' # * x25|SHIFT_FLAG (shift 8)
b'\xae' # + x2e|SHIFT_FLAG (shift =)
b'\x36' # ,
b'\x2d' # -
b'\x37' # .
b'\x38' # /
b'\x27' # 0
b'\x1e' # 1
b'\x1f' # 2
b'\x20' # 3
b'\x21' # 4
b'\x22' # 5
b'\x23' # 6
b'\x24' # 7
b'\x25' # 8
b'\x26' # 9
b'\xb3' # : x33|SHIFT_FLAG (shift ;)
b'\x33' # ;
b'\xb6' # < x36|SHIFT_FLAG (shift ,)
b'\x2e' # =
b'\xb7' # > x37|SHIFT_FLAG (shift .)
b'\xb8' # ? x38|SHIFT_FLAG (shift /)
b'\x9f' # @ x1f|SHIFT_FLAG (shift 2)
b'\x84' # A x04|SHIFT_FLAG (shift a)
b'\x85' # B x05|SHIFT_FLAG (etc.)
b'\x86' # C x06|SHIFT_FLAG
b'\x87' # D x07|SHIFT_FLAG
b'\x88' # E x08|SHIFT_FLAG
b'\x89' # F x09|SHIFT_FLAG
b'\x8a' # G x0a|SHIFT_FLAG
b'\x8b' # H x0b|SHIFT_FLAG
b'\x8c' # I x0c|SHIFT_FLAG
b'\x8d' # J x0d|SHIFT_FLAG
b'\x8e' # K x0e|SHIFT_FLAG
b'\x8f' # L x0f|SHIFT_FLAG
b'\x90' # M x10|SHIFT_FLAG
b'\x91' # N x11|SHIFT_FLAG
b'\x92' # O x12|SHIFT_FLAG
b'\x93' # P x13|SHIFT_FLAG
b'\x94' # Q x14|SHIFT_FLAG
b'\x95' # R x15|SHIFT_FLAG
b'\x96' # S x16|SHIFT_FLAG
b'\x97' # T x17|SHIFT_FLAG
b'\x98' # U x18|SHIFT_FLAG
b'\x99' # V x19|SHIFT_FLAG
b'\x9a' # W x1a|SHIFT_FLAG
b'\x9b' # X x1b|SHIFT_FLAG
b'\x9c' # Y x1c|SHIFT_FLAG
b'\x9d' # Z x1d|SHIFT_FLAG
b'\x2f' # [
b'\x31' # \ backslash
b'\x30' # ]
b'\xa3' # ^ x23|SHIFT_FLAG (shift 6)
b'\xad' # _ x2d|SHIFT_FLAG (shift -)
b'\x35' # `
b'\x04' # a
b'\x05' # b
b'\x06' # c
b'\x07' # d
b'\x08' # e
b'\x09' # f
b'\x0a' # g
b'\x0b' # h
b'\x0c' # i
b'\x0d' # j
b'\x0e' # k
b'\x0f' # l
b'\x10' # m
b'\x11' # n
b'\x12' # o
b'\x13' # p
b'\x14' # q
b'\x15' # r
b'\x16' # s
b'\x17' # t
b'\x18' # u
b'\x19' # v
b'\x1a' # w
b'\x1b' # x
b'\x1c' # y
b'\x1d' # z
b'\xaf' # { x2f|SHIFT_FLAG (shift [)
b'\xb1' # | x31|SHIFT_FLAG (shift \)
b'\xb0' # } x30|SHIFT_FLAG (shift ])
b'\xb5' # ~ x35|SHIFT_FLAG (shift `)
b'\x4c' # DEL DELETE (called Forward Delete in usb.org document)
)
[docs]
class KeyboardModifiers(IntFlag):
MOD_LEFT_CTRL = 0x01
MOD_LEFT_SHIFT = 0x02
MOD_LEFT_ALT = 0x04
MOD_LEFT_META = 0x08
MOD_RIGHT_CTRL = 0x10
MOD_RIGHT_SHIFT = 0x20
MOD_RIGHT_ALT = 0x40
MOD_RIGHT_META = 0x80
[docs]
class KeyboardKeys(IntEnum):
NONE = 0x00 # No key pressed
ERR_OVF = 0x01 # Keyboard Error Roll Over - used for all slots if too many keys are pressed ("Phantom key")
A = 0x04 # Keyboard a and A
B = 0x05 # Keyboard b and B
C = 0x06 # Keyboard c and C
D = 0x07 # Keyboard d and D
E = 0x08 # Keyboard e and E
F = 0x09 # Keyboard f and F
G = 0x0a # Keyboard g and G
H = 0x0b # Keyboard h and H
I = 0x0c # Keyboard i and I
J = 0x0d # Keyboard j and J
K = 0x0e # Keyboard k and K
L = 0x0f # Keyboard l and L
M = 0x10 # Keyboard m and M
N = 0x11 # Keyboard n and N
O = 0x12 # Keyboard o and O
P = 0x13 # Keyboard p and P
Q = 0x14 # Keyboard q and Q
R = 0x15 # Keyboard r and R
S = 0x16 # Keyboard s and S
T = 0x17 # Keyboard t and T
U = 0x18 # Keyboard u and U
V = 0x19 # Keyboard v and V
W = 0x1a # Keyboard w and W
X = 0x1b # Keyboard x and X
Y = 0x1c # Keyboard y and Y
Z = 0x1d # Keyboard z and Z
NUM_1 = 0x1e # Keyboard 1 and !
NUM_2 = 0x1f # Keyboard 2 and @
NUM_3 = 0x20 # Keyboard 3 and #
NUM_4 = 0x21 # Keyboard 4 and $
NUM_5 = 0x22 # Keyboard 5 and %
NUM_6 = 0x23 # Keyboard 6 and ^
NUM_7 = 0x24 # Keyboard 7 and &
NUM_8 = 0x25 # Keyboard 8 and *
NUM_9 = 0x26 # Keyboard 9 and (
NUM_0 = 0x27 # Keyboard 0 and )
ENTER = 0x28 # Keyboard Return (ENTER)
ESC = 0x29 # Keyboard ESCAPE
BACKSPACE = 0x2a # Keyboard DELETE (Backspace)
TAB = 0x2b # Keyboard Tab
SPACE = 0x2c # Keyboard Spacebar
MINUS = 0x2d # Keyboard - and _
EQUAL = 0x2e # Keyboard = and +
LEFTBRACE = 0x2f # Keyboard [ and {
RIGHTBRACE = 0x30 # Keyboard ] and }
BACKSLASH = 0x31 # Keyboard \ and |
HASHTILDE = 0x32 # Keyboard Non-US # and ~
SEMICOLON = 0x33 # Keyboard ; and :
APOSTROPHE = 0x34 # Keyboard ' and "
GRAVE = 0x35 # Keyboard ` and ~
COMMA = 0x36 # Keyboard, and <
DOT = 0x37 # Keyboard . and >
SLASH = 0x38 # Keyboard / and ?
CAPSLOCK = 0x39 # Keyboard Caps Lock
F1 = 0x3a # Keyboard F1
F2 = 0x3b # Keyboard F2
F3 = 0x3c # Keyboard F3
F4 = 0x3d # Keyboard F4
F5 = 0x3e # Keyboard F5
F6 = 0x3f # Keyboard F6
F7 = 0x40 # Keyboard F7
F8 = 0x41 # Keyboard F8
F9 = 0x42 # Keyboard F9
F10 = 0x43 # Keyboard F10
F11 = 0x44 # Keyboard F11
F12 = 0x45 # Keyboard F12
SYSRQ = 0x46 # Keyboard Print Screen
SCROLLLOCK = 0x47 # Keyboard Scroll Lock
PAUSE = 0x48 # Keyboard Pause
INSERT = 0x49 # Keyboard Insert
HOME = 0x4a # Keyboard Home
PAGEUP = 0x4b # Keyboard Page Up
DELETE = 0x4c # Keyboard Delete Forward
END = 0x4d # Keyboard End
PAGEDOWN = 0x4e # Keyboard Page Down
RIGHT = 0x4f # Keyboard Right Arrow
LEFT = 0x50 # Keyboard Left Arrow
DOWN = 0x51 # Keyboard Down Arrow
UP = 0x52 # Keyboard Up Arrow
NUMLOCK = 0x53 # Keyboard Num Lock and Clear
KPSLASH = 0x54 # Keypad /
KPASTERISK = 0x55 # Keypad *
KPMINUS = 0x56 # Keypad -
KPPLUS = 0x57 # Keypad +
KPENTER = 0x58 # Keypad ENTER
KP1 = 0x59 # Keypad 1 and End
KP2 = 0x5a # Keypad 2 and Down Arrow
KP3 = 0x5b # Keypad 3 and PageDn
KP4 = 0x5c # Keypad 4 and Left Arrow
KP5 = 0x5d # Keypad 5
KP6 = 0x5e # Keypad 6 and Right Arrow
KP7 = 0x5f # Keypad 7 and Home
KP8 = 0x60 # Keypad 8 and Up Arrow
KP9 = 0x61 # Keypad 9 and Page Up
KP0 = 0x62 # Keypad 0 and Insert
KPDOT = 0x63 # Keypad . and Delete
COMPOSE = 0x65 # Keyboard Application
POWER = 0x66 # Keyboard Power
KPEQUAL = 0x67 # Keypad =
F13 = 0x68 # Keyboard F13
F14 = 0x69 # Keyboard F14
F15 = 0x6a # Keyboard F15
F16 = 0x6b # Keyboard F16
F17 = 0x6c # Keyboard F17
F18 = 0x6d # Keyboard F18
F19 = 0x6e # Keyboard F19
F20 = 0x6f # Keyboard F20
F21 = 0x70 # Keyboard F21
F22 = 0x71 # Keyboard F22
F23 = 0x72 # Keyboard F23
F24 = 0x73 # Keyboard F24
OPEN = 0x74 # Keyboard Execute
HELP = 0x75 # Keyboard Help
PROPS = 0x76 # Keyboard Menu
FRONT = 0x77 # Keyboard Select
STOP = 0x78 # Keyboard Stop
AGAIN = 0x79 # Keyboard Again
UNDO = 0x7a # Keyboard Undo
CUT = 0x7b # Keyboard Cut
COPY = 0x7c # Keyboard Copy
PASTE = 0x7d # Keyboard Paste
FIND = 0x7e # Keyboard Find
MUTE = 0x7f # Keyboard Mute
VOLUMEUP = 0x80 # Keyboard Volume Up
VOLUMEDOWN = 0x81 # Keyboard Volume Down
KPCOMMA = 0x85 # Keypad Comma
RO = 0x87 # Keyboard International1
KATAKANAHIRAGANA = 0x88 # Keyboard International2
YEN = 0x89 # Keyboard International3
HENKAN = 0x8a # Keyboard International4
MUHENKAN = 0x8b # Keyboard International5
KPJPCOMMA = 0x8c # Keyboard International6
HANGEUL = 0x90 # Keyboard LANG1
HANJA = 0x91 # Keyboard LANG2
KATAKANA = 0x92 # Keyboard LANG3
HIRAGANA = 0x93 # Keyboard LANG4
ZENKAKUHANKAKU = 0x94 # Keyboard LANG5
#SYSRQ = 0x9a # Keyboard SysReq/Attention
KEYPAD_00 = 0xb0 # Keypad 00
KEYPAD_000 = 0xb1 # Keypad 000
KPLEFTPAREN = 0xb6 # Keypad (
KPRIGHTPAREN = 0xb7 # Keypad )
LEFTCTRL = 0xe0 # Keyboard Left Control
LEFTSHIFT = 0xe1 # Keyboard Left Shift
LEFTALT = 0xe2 # Keyboard Left Alt
LEFTMETA = 0xe3 # Keyboard Left GUI
RIGHTCTRL = 0xe4 # Keyboard Right Control
RIGHTSHIFT = 0xe5 # Keyboard Right Shift
RIGHTALT = 0xe6 # Keyboard Right Alt
RIGHTMETA = 0xe7 # Keyboard Right GUI
MEDIA_PLAYPAUSE = 0xe8
MEDIA_STOPCD = 0xe9
MEDIA_PREVIOUSSONG = 0xea
MEDIA_NEXTSONG = 0xeb
MEDIA_EJECTCD = 0xec
MEDIA_VOLUMEUP = 0xed
MEDIA_VOLUMEDOWN = 0xee
MEDIA_MUTE = 0xef
MEDIA_WWW = 0xf0
MEDIA_BACK = 0xf1
MEDIA_FORWARD = 0xf2
MEDIA_STOP = 0xf3
MEDIA_FIND = 0xf4
MEDIA_SCROLLUP = 0xf5
MEDIA_SCROLLDOWN = 0xf6
MEDIA_EDIT = 0xf7
MEDIA_SLEEP = 0xf8
MEDIA_COFFEE = 0xf9
MEDIA_REFRESH = 0xfa
MEDIA_CALC = 0xfb
[docs]
@classmethod
def get_scancode_for_ascii(cls, letter_or_code):
""" Returns the (modifiers, scancode) used to type a given ASCII letter. """
# Look up the relevant ASCII code in our table.
ascii_code = letter_or_code if isinstance(letter_or_code, int) else ord(letter_or_code)
composite = _ASCII_TO_KEYCODE[ascii_code]
# The Adafruit table uses bits [6:0] to indicate keycode; and bit [7] to indicate
# if shift is necessary.
modifiers = KeyboardModifiers.MOD_LEFT_SHIFT if (composite & 0x80) else 0
scancode = composite & 0x7F
return (modifiers, scancode)