From 5476f0cd555abb8d103776dec6c016b192c53b75 Mon Sep 17 00:00:00 2001 From: Zackarias Montell Date: Thu, 6 Jan 2022 14:17:12 +0100 Subject: [PATCH] started breaking out keys --- .gitignore | 0 code.py | 0 config.py | 0 keyboard.py | 31 ++++--- keycodes.py | 261 ++++++++++++++++++++++++++-------------------------- keytypes.py | 115 ++++++++++++++++++++++- tests.py | 0 7 files changed, 263 insertions(+), 144 deletions(-) mode change 100644 => 100755 .gitignore mode change 100755 => 100644 code.py mode change 100755 => 100644 config.py mode change 100755 => 100644 keyboard.py mode change 100755 => 100644 tests.py diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/code.py b/code.py old mode 100755 new mode 100644 diff --git a/config.py b/config.py old mode 100755 new mode 100644 diff --git a/keyboard.py b/keyboard.py old mode 100755 new mode 100644 index 42d7a21..e626db2 --- a/keyboard.py +++ b/keyboard.py @@ -185,8 +185,8 @@ class Keyboard: while True: for pin in self.pins: pin_index = self.pins.index(pin) - keycode = self.keymap[self.held_layer if self.held_layer != - None else self.toggled_layer][pin_index] + key = self.keymap[self.held_layer if self.held_layer != + None else self.toggled_layer][pin_index] previousValue = self.pin_states_last_cycle[pin_index][0] value = pin.value currentlyPressed = value == __PRESSED @@ -195,41 +195,43 @@ class Keyboard: previouslyToggledReleased = previousValue == __TOGGLED_RELEASED previouslyUntoggledPressed = previousValue == __UNTOGGLED_PRESSED previouslyDebounced = previousValue == __DEBOUNCE - if not isinstance(keycode, LayerKey): + if not isinstance(key, LayerKey): if currentlyPressed: if not previouslyPressed: - self.pressed_keys.add(keycode) + self.pressed_keys.add(key.keycode) else: if previouslyPressed: try: - self.pressed_keys.remove(keycode) + self.pressed_keys.remove(key.keycode) # Catch silenly if same keycode is pressed twice then released except KeyError: pass self.pin_states_last_cycle[pin_index] = (value,) continue - # TODO: Always release old key when entering new layer - if type(keycode) is Hold: + # todo: Release all keys not the same as the old layer + if type(key) is Hold: if not currentlyPressed and previouslyDebounced: self.pin_states_last_cycle[pin_index] = ( __UNPRESSED,) if currentlyPressed and not previouslyPressed and not previouslyDebounced: - self.held_layer = keycode.layer + self.held_layer = key.layer self.pin_states_last_cycle[pin_index] = ( - __PRESSED, keycode) + __PRESSED, key) continue if previouslyPressed and not currentlyPressed: self.held_layer = None self.pin_states_last_cycle[pin_index] = ( __UNPRESSED,) continue - if type(keycode) is Toggle: + # todo: Release all keys not the same as the old layer + # todo: Debounce old toggle when pressing new toggle + if type(key) is Toggle: if currentlyPressed and not previouslyToggled and not previouslyToggledReleased and not previouslyUntoggledPressed: - self.toggled_layer = keycode.layer + self.toggled_layer = key.layer self.held_layer = None self.pin_states_last_cycle[pin_index] = ( - __TOGGLED_PRESSED, keycode) + __TOGGLED_PRESSED, key) for i in range(len(self.pin_states_last_cycle)): if i == pin_index or len(self.pin_states_last_cycle[i]) == 1: continue @@ -244,12 +246,12 @@ class Keyboard: continue if not currentlyPressed and previouslyToggled: self.pin_states_last_cycle[pin_index] = ( - __TOGGLED_RELEASED, keycode) + __TOGGLED_RELEASED, key) continue if currentlyPressed and previouslyToggledReleased: self.toggled_layer = 0 self.pin_states_last_cycle[pin_index] = ( - __UNTOGGLED_PRESSED, keycode) + __UNTOGGLED_PRESSED, key) continue if not currentlyPressed and previouslyUntoggledPressed: self.pin_states_last_cycle[pin_index] = ( @@ -272,6 +274,7 @@ class Keyboard: self.led.indicate_boot() self.start() + # todo: add boot mode def send_nkro_report(self): """Sends the USB HID NKRO keyboard report.""" diff --git a/keycodes.py b/keycodes.py index 1e4e7c8..a23ff28 100644 --- a/keycodes.py +++ b/keycodes.py @@ -1,144 +1,147 @@ from micropython import const +from keytypes import Keycode, Modifier + + class SE: # Letters - A = const(4) - B = const(5) - C = const(6) - D = const(7) - E = const(8) - F = const(9) - G = const(10) - H = const(11) - I = const(12) - J = const(13) - K = const(14) - L = const(15) - M = const(16) - N = const(17) - O = const(18) - P = const(19) - Q = const(20) - R = const(21) - S = const(22) - T = const(23) - U = const(24) - V = const(25) - W = const(26) - X = const(27) - Y = const(28) - Z = const(29) - Å = const(47) - Ä = const(52) - Ö = const(51) + A = Keycode(const(4)) + B = Keycode(const(5)) + C = Keycode(const(6)) + D = Keycode(const(7)) + E = Keycode(const(8)) + F = Keycode(const(9)) + G = Keycode(const(10)) + H = Keycode(const(11)) + I = Keycode(const(12)) + J = Keycode(const(13)) + K = Keycode(const(14)) + L = Keycode(const(15)) + M = Keycode(const(16)) + N = Keycode(const(17)) + O = Keycode(const(18)) + P = Keycode(const(19)) + Q = Keycode(const(20)) + R = Keycode(const(21)) + S = Keycode(const(22)) + T = Keycode(const(23)) + U = Keycode(const(24)) + V = Keycode(const(25)) + W = Keycode(const(26)) + X = Keycode(const(27)) + Y = Keycode(const(28)) + Z = Keycode(const(29)) + Å = Keycode(const(47)) + Ä = Keycode(const(52)) + Ö = Keycode(const(51)) # Numbers - ZERO = const(39) - ONE = const(30) - TWO = const(31) - THREE = const(32) - FOUR = const(33) - FIVE = const(34) - SIX = const(35) - SEVEN = const(36) - EIGHT = const(37) - NINE = const(38) + ZERO = Keycode(const(39)) + ONE = Keycode(const(30)) + TWO = Keycode(const(31)) + THREE = Keycode(const(32)) + FOUR = Keycode(const(33)) + FIVE = Keycode(const(34)) + SIX = Keycode(const(35)) + SEVEN = Keycode(const(36)) + EIGHT = Keycode(const(37)) + NINE = Keycode(const(38)) # Signs - HYPHEN = const(56) # - and _ - DOT = const(55) # . and : - COMMA = const(54) # , and ; - PARAGRAPH = const(53) # § and ½ - QUOTE = const(49) # ' and * - UMLAUT = const(48) # ¨ and ~ - TICK = const(46) # ´ and ` - PLUS = const(45) # + and ? - EQUAL = const(103) # = - ANGLE_BRACKET = const(100) # < and > + HYPHEN = Keycode(const(56)) # - and _ + DOT = Keycode(const(55)) # . and : + COMMA = Keycode(const(54)) # , and ; + PARAGRAPH = Keycode(const(53)) # § and ½ + QUOTE = Keycode(const(49)) # ' and * + UMLAUT = Keycode(const(48)) # ¨ and ~ + TICK = Keycode(const(46)) # ´ and ` + PLUS = Keycode(const(45)) # + and ? + EQUAL = Keycode(const(103)) # = + ANGLE_BRACKET = Keycode(const(100)) # < and > # Function keys - F1 = const(58) - F2 = const(59) - F3 = const(60) - F4 = const(61) - F5 = const(62) - F6 = const(63) - F7 = const(64) - F8 = const(65) - F9 = const(66) - F10 = const(67) - F11 = const(68) - F12 = const(69) - PRINTSCREEN = const(70) - CAPSLOCK = const(57) - ESCAPE = const(41) - SCROLLLOCK = const(71) - PAUSEBREAK = const(72) - INSERT = const(73) - MENU = const(101) + F1 = Keycode(const(58)) + F2 = Keycode(const(59)) + F3 = Keycode(const(60)) + F4 = Keycode(const(61)) + F5 = Keycode(const(62)) + F6 = Keycode(const(63)) + F7 = Keycode(const(64)) + F8 = Keycode(const(65)) + F9 = Keycode(const(66)) + F10 = Keycode(const(67)) + F11 = Keycode(const(68)) + F12 = Keycode(const(69)) + PRINTSCREEN = Keycode(const(70)) + CAPSLOCK = Keycode(const(57)) + ESCAPE = Keycode(const(41)) + SCROLLLOCK = Keycode(const(71)) + PAUSEBREAK = Keycode(const(72)) + INSERT = Keycode(const(73)) + MENU = Keycode(const(101)) # Function keys tested in gnome - TOUCHPAD_TOGGLE = const(112) - TOUCHPAD_ON = const(113) - TOUCHPAD_OFF = const(114) - MIC_MUTE = const(111) - POWER = const(102) - SETTINGS = const(104) - HELP = const(117) + TOUCHPAD_TOGGLE = Keycode(const(112)) + TOUCHPAD_ON = Keycode(const(113)) + TOUCHPAD_OFF = Keycode(const(114)) + MIC_MUTE = Keycode(const(111)) + POWER = Keycode(const(102)) + SETTINGS = Keycode(const(104)) + HELP = Keycode(const(117)) # Spacing - TAB = const(43) - SPACE = const(44) - ENTER = const(40) + TAB = Keycode(const(43)) + SPACE = Keycode(const(44)) + ENTER = Keycode(const(40)) # Navigation - BACKSPACE = const(42) - DELETE = const(76) - HOME = const(74) - END = const(77) - PAGEUP = const(75) - PAGEDOWN = const(78) - RIGHT = const(79) - LEFT = const(80) - UP = const(81) - DOWN = const(82) + BACKSPACE = Keycode(const(42)) + DELETE = Keycode(const(76)) + HOME = Keycode(const(74)) + END = Keycode(const(77)) + PAGEUP = Keycode(const(75)) + PAGEDOWN = Keycode(const(78)) + RIGHT = Keycode(const(79)) + LEFT = Keycode(const(80)) + UP = Keycode(const(81)) + DOWN = Keycode(const(82)) # Modifiers - LEFT_CTRL = const(0x0100) - LEFT_SHIFT = const(0x0200) - LEFT_ALT = const(0x0400) - LEFT_SUPER = const(0x0800) - RIGHT_CTRL = const(0x1000) - RIGHT_SHIFT = const(0x2000) - RIGHT_ALT = const(0x4000) + LEFT_CTRL = Modifier(const(0x0100)) + LEFT_SHIFT = Modifier(const(0x0200)) + LEFT_ALT = Modifier(const(0x0400)) + LEFT_SUPER = Modifier(const(0x0800)) + RIGHT_CTRL = Modifier(const(0x1000)) + RIGHT_SHIFT = Modifier(const(0x2000)) + RIGHT_ALT = Modifier(const(0x4000)) # Others - XF86_LAUNCH_5 = const(105) - XF86_LAUNCH_6 = const(106) - XF86_LAUNCH_7 = const(107) - XF86_LAUNCH_8 = const(108) - XF86_LAUNCH_9 = const(109) - XF86_OPEN = const(116) - SUN_FRONT = const(119) - SUN_PROPS = const(118) + XF86_LAUNCH_5 = Keycode(const(105)) + XF86_LAUNCH_6 = Keycode(const(106)) + XF86_LAUNCH_7 = Keycode(const(107)) + XF86_LAUNCH_8 = Keycode(const(108)) + XF86_LAUNCH_9 = Keycode(const(109)) + XF86_OPEN = Keycode(const(116)) + SUN_FRONT = Keycode(const(119)) + SUN_PROPS = Keycode(const(118)) # Numpad - NUM_DOT = const(99) - NUM_0 = const(98) - NUM_1 = const(89) - NUM_2 = const(90) - NUM_3 = const(91) - NUM_4 = const(92) - NUM_5 = const(93) - NUM_6 = const(94) - NUM_7 = const(95) - NUM_8 = const(96) - NUM_9 = const(97) - NUM_ENTER = const(88) - NUM_PLUS = const(87) # + - NUM_MINUS = const(86) # - - NUM_ASTERISK = const(85) # * - NUM_SLASH = const(84) # / - NUMLOCK = const(83) + NUM_DOT = Keycode(const(99)) + NUM_0 = Keycode(const(98)) + NUM_1 = Keycode(const(89)) + NUM_2 = Keycode(const(90)) + NUM_3 = Keycode(const(91)) + NUM_4 = Keycode(const(92)) + NUM_5 = Keycode(const(93)) + NUM_6 = Keycode(const(94)) + NUM_7 = Keycode(const(95)) + NUM_8 = Keycode(const(96)) + NUM_9 = Keycode(const(97)) + NUM_ENTER = Keycode(const(88)) + NUM_PLUS = Keycode(const(87)) # + + NUM_MINUS = Keycode(const(86)) # - + NUM_ASTERISK = Keycode(const(85)) # * + NUM_SLASH = Keycode(const(84)) # / + NUMLOCK = Keycode(const(83)) # Need fix - #SE_MUTE = const(-226) # Mute - #SE_VU = const(-233) # Volume up - #SE_VD = const(-234) # Volume down + # SE_MUTE = const(-226) # Mute + # SE_VU = const(-233) # Volume up + # SE_VD = const(-234) # Volume down # - #SE_RR = const(-179) # Rewind - #SE_FF = const(-180) # Fast forward - #SE_NT = const(-181) # Next track - #SE_PT = const(-182) # Prev track - #SE_ST = const(-183) # Stop track - #SE_PP = const(-205) # Play/pause \ No newline at end of file + # SE_RR = const(-179) # Rewind + # SE_FF = const(-180) # Fast forward + # SE_NT = const(-181) # Next track + # SE_PT = const(-182) # Prev track + # SE_ST = const(-183) # Stop track + # SE_PP = const(-205) # Play/pause diff --git a/keytypes.py b/keytypes.py index a2eab54..461f515 100644 --- a/keytypes.py +++ b/keytypes.py @@ -1,8 +1,121 @@ +from keyboard import Keyboard +from micropython import const -class LayerKey: + +class KeyState: + """Interpretations of hardware pin state""" + PRESSED = const(0) + """Key is pressed""" + UNPRESSED = const(1) + """Key is not pressed""" + PRESSED_TOGGLED_ON = const(2) + """Key is pressed and is emulating a toggle key in ON state that is not released until the physical key is released, then pressed again""" + UNPRESSED_TOGGLED_ON = const(3) + """Key is unpressed and is emulating a toggle key in ON state that is not released unit the physical key is pressed again""" + PRESSED_TOGGLED_OFF = const(4) + """Key is pressed and is emulating a toggle key in OFF state""" + DEBOUNCE = const(5) + """Further state changes of any kind are ignored until key has been physically released released""" + + +class KeyEvent: + """Interpretations of KeyStates as single events""" + NONE: int = const(0) + """No new event has occurred""" + PRESSED: int = const(1) + """The key was pressed""" + RELEASED: int = const(2) + """The key was released""" + SOFT_RELEASE: int = const(3) + """The key was released programatically, and not by an actual physical release of a button.""" + + +class Key: + index: int + + def __init__(self): + pass + + def set_index(self, index) -> None: + assert 0 <= index + self.index = index + + def handle(self, keyboard): + assert self.index is not None + + +class Keycode(Key): + keycode: int + + def __init__(self, keycode: int): + super().__init__() + self.keycode = keycode + + def __interpret_hardware_changes(self, keyboard: Keyboard) -> tuple[KeyState, KeyState]: + """Interprets the changes to hardware pins as current and previous KeyState""" + current = keyboard.pins[self.index].value + previous = self.pin_states_last_cycle[self.index][0] + return (current, previous) + + def __interpret_event(self, states: tuple[KeyState, KeyState]) -> KeyEvent: + """Interprets the current and previous KeyState as a KeyEvent""" + current, previous = states + if previous == KeyState.UNPRESSED: + if current == KeyState.UNPRESSED: + return KeyEvent.NONE + if current == KeyState.PRESSED: + return KeyEvent.PRESSED + if previous == KeyState.PRESSED: + if current == KeyState.PRESSED: + return KeyEvent.NONE + if current == KeyState.UNPRESSED: + return KeyEvent.RELEASED + else: + raise NotImplementedError() + + def react(self, keyboard: Keyboard, event: KeyEvent) -> None: + if event == KeyEvent.NONE: + return + if event == KeyEvent.PRESSED: + keyboard.pressed_keys.add(self.keycode) + if event == KeyEvent.RELEASED: + try: + keyboard.pressed_keys.remove(self.keycode) + except KeyError: + # silently pass errors when same keycode has been issued twice + pass + keyboard.pin_states_last_cycle[self.index] = () + + def handle(self, keyboard): + super().handle() + states = self.__interpret_hardware_changes(keyboard) + event = self.__interpret_event(states) + self.react(keyboard, event) + + if not isinstance(key, LayerKey): + if currentlyPressed: + if not previouslyPressed: + self.pressed_keys.add(key.keycode) + else: + if previouslyPressed: + try: + self.pressed_keys.remove(key.keycode) + # Catch silenly if same keycode is pressed twice then released + except KeyError: + pass + self.pin_states_last_cycle[pin_index] = (value,) + + +class Modifier(Keycode): + def __init__(self, keycode: int): + super().__init__(keycode) + + +class LayerKey(Key): layer: int def __init__(self, layer: int): + super().__init__() self.layer = layer diff --git a/tests.py b/tests.py old mode 100755 new mode 100644