started breaking out keys

This commit is contained in:
2022-01-06 14:17:12 +01:00
parent 38c5b6e78b
commit 5476f0cd55
7 changed files with 263 additions and 144 deletions

0
.gitignore vendored Normal file → Executable file
View File

0
code.py Executable file → Normal file
View File

0
config.py Executable file → Normal file
View File

31
keyboard.py Executable file → Normal file
View File

@@ -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."""

View File

@@ -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
# 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

View File

@@ -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

0
tests.py Executable file → Normal file
View File