Files
macropad/keytypes.py

130 lines
4.1 KiB
Python

from keyboard import Keyboard
from micropython import const
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
class Toggle(LayerKey):
def __init__(self, layer: int):
super().__init__(layer)
class Hold(LayerKey):
def __init__(self, layer: int):
super().__init__(layer)