restructured
This commit is contained in:
4
keyboards/macropad_rev1/default/keymap.py
Executable file → Normal file
4
keyboards/macropad_rev1/default/keymap.py
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
from nmlkpy.keycodes import SE
|
||||
from nmlkpy.keytypes import Keycode, Modifier
|
||||
from nmlkpy.key_codes.se import SE
|
||||
from nmlkpy.key_types.keycode import Keycode, Modifier
|
||||
from nmlkpy.layer_manager import LayerManager
|
||||
|
||||
lm = LayerManager(5)
|
||||
|
||||
0
keyboards/macropad_rev1/default/pinouts.py
Executable file → Normal file
0
keyboards/macropad_rev1/default/pinouts.py
Executable file → Normal file
0
nmlkpy/__init__.py
Executable file → Normal file
0
nmlkpy/__init__.py
Executable file → Normal file
0
nmlkpy/boot.py
Executable file → Normal file
0
nmlkpy/boot.py
Executable file → Normal file
0
nmlkpy/keycodes.py → nmlkpy/key_codes/se.py
Executable file → Normal file
0
nmlkpy/keycodes.py → nmlkpy/key_codes/se.py
Executable file → Normal file
93
nmlkpy/key_types/base.py
Normal file
93
nmlkpy/key_types/base.py
Normal file
@@ -0,0 +1,93 @@
|
||||
from micropython import const
|
||||
|
||||
|
||||
class KeyEvent:
|
||||
"""Interpretations of KeyStates as single events"""
|
||||
NO_EVENT: 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_RELEASED: int = const(3)
|
||||
"""The key was released programatically, and not by an actual physical release of a button."""
|
||||
PRESSED_TOGGLED_ON = const(4)
|
||||
"""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"""
|
||||
RELEASED_TOGGLED_ON = const(5)
|
||||
"""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(6)
|
||||
"""Key is pressed and is emulating a toggle key in OFF state"""
|
||||
|
||||
|
||||
def _event_to_string(event: int) -> str:
|
||||
if event == KeyEvent.NO_EVENT:
|
||||
return "NO EVENT"
|
||||
if event == KeyEvent.PRESSED_:
|
||||
return "PRESSED"
|
||||
if event == KeyEvent.RELEASED:
|
||||
return "RELEASED"
|
||||
if event == KeyEvent.SOFT_RELEASED:
|
||||
return "SOFT_RELEASED"
|
||||
if event == KeyEvent.PRESSED_TOGGLED_ON:
|
||||
return "PRESSED TOGGLED ON"
|
||||
if event == KeyEvent.RELEASED_TOGGLED_ON:
|
||||
return "RELEASED TOGGLED ON"
|
||||
if event == KeyEvent.PRESSED_TOGGLED_OFF:
|
||||
return "PRESSED TOGGLED OFF"
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class KeyEvents:
|
||||
current: int
|
||||
previous: int
|
||||
|
||||
def __init__(self):
|
||||
self.current = KeyEvent.RELEASED
|
||||
self.previous = KeyEvent.RELEASED
|
||||
|
||||
def shift(self, next):
|
||||
self.previous = self.current
|
||||
self.current = next
|
||||
|
||||
|
||||
class KeyBase:
|
||||
events: KeyEvents
|
||||
allowed_events: list[KeyEvent]
|
||||
key_index: int
|
||||
layer_index: int
|
||||
|
||||
def __init__(self, allowed_events: list[int]):
|
||||
self.allowed_events = allowed_events
|
||||
self.events = KeyEvents()
|
||||
self.key_index = None
|
||||
self.layer_index = None
|
||||
|
||||
def enrich(self, key_index: int, layer_index: int):
|
||||
self.key_index = key_index
|
||||
self.layer_index = layer_index
|
||||
|
||||
def _validate_next_event(self, next_event: int):
|
||||
if next_event is None or next_event not in self.allowed_events:
|
||||
raise Exception(
|
||||
f"KeyEvent with value of {next_event} is not a valid event for this type of key")
|
||||
|
||||
def _set_event(self, next_event: int) -> bool:
|
||||
"""Sets previous state if new state is valid
|
||||
Returns: A boolean that determines if the state was updated or not"""
|
||||
self._validate_next_event(next_event)
|
||||
if next_event is KeyEvent.NO_EVENT:
|
||||
return False
|
||||
print(
|
||||
f"[{self.key_index}] next: {_event_to_string(next_event)}, current: {_event_to_string(self.events.current)}, previous: {_event_to_string(self.events.previous)}")
|
||||
self.events.shift(next_event)
|
||||
return True
|
||||
|
||||
def handle(self, keyboard):
|
||||
raise NotImplementedError()
|
||||
|
||||
def self_test(self, keymap: list[list[object]]):
|
||||
raise NotImplementedError()
|
||||
|
||||
def soft_release(self, keyboard):
|
||||
"""Release key programatically and wait until it's released physically before registrating additional key presses"""
|
||||
raise NotImplementedError()
|
||||
106
nmlkpy/key_types/keycode.py
Normal file
106
nmlkpy/key_types/keycode.py
Normal file
@@ -0,0 +1,106 @@
|
||||
from .base import KeyBase, KeyEvent
|
||||
from ..pin import PinEvent
|
||||
|
||||
_VALID_KEYCODES = range(0, 255)
|
||||
_VALID_MODIFIERS = [0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000]
|
||||
|
||||
|
||||
class KeycodeBase(KeyBase):
|
||||
"""Basic press and release functionality that appends a keycode to the report when active"""
|
||||
keycode: int
|
||||
|
||||
def __init__(self, keycode: int):
|
||||
allowed_events = [KeyEvent.NO_EVENT,
|
||||
KeyEvent.PRESSED_,
|
||||
KeyEvent.RELEASED,
|
||||
KeyEvent.SOFT_RELEASED]
|
||||
super().__init__(allowed_events)
|
||||
self.keycode = keycode
|
||||
|
||||
def self_test(self, keymap):
|
||||
raise NotImplementedError
|
||||
|
||||
def soft_release(self, keyboard):
|
||||
if self.events.current != KeyEvent.PRESSED_:
|
||||
return
|
||||
self._set_event(KeyEvent.SOFT_RELEASED)
|
||||
|
||||
def _consume_next_event(self, pin) -> bool:
|
||||
"""Returns: a boolean representing if the event property was updated with a new event or not"""
|
||||
next_pin_event = pin.read_event()
|
||||
current_key_event, previous_key_event = self.events.current, self.events.previous
|
||||
next_key_event = None
|
||||
|
||||
if current_key_event == KeyEvent.SOFT_RELEASED:
|
||||
if previous_key_event == KeyEvent.RELEASED:
|
||||
print(1)
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
print(2)
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
if previous_key_event == KeyEvent.PRESSED_ or next_pin_event == PinEvent.PRESSED:
|
||||
print(3)
|
||||
return self._set_event(KeyEvent.SOFT_RELEASED)
|
||||
print(4)
|
||||
return self._set_event(KeyEvent.SOFT_RELEASED)
|
||||
|
||||
if current_key_event == KeyEvent.NO_EVENT:
|
||||
if next_pin_event == PinEvent.NO_EVENT:
|
||||
next_key_event = KeyEvent.NO_EVENT
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
next_key_event = KeyEvent.RELEASED
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
next_key_event = KeyEvent.PRESSED_
|
||||
if current_key_event == KeyEvent.RELEASED:
|
||||
if next_pin_event == PinEvent.NO_EVENT:
|
||||
next_key_event = KeyEvent.NO_EVENT
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
next_key_event = KeyEvent.NO_EVENT
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
next_key_event = KeyEvent.PRESSED_
|
||||
if current_key_event == KeyEvent.PRESSED_:
|
||||
if next_pin_event == PinEvent.NO_EVENT:
|
||||
next_key_event = KeyEvent.NO_EVENT
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
next_key_event = KeyEvent.RELEASED
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
next_key_event = KeyEvent.NO_EVENT
|
||||
|
||||
return self._set_event(next_key_event)
|
||||
|
||||
def _handle_event(self, keyboard) -> None:
|
||||
current = self.events.current
|
||||
if current == KeyEvent.PRESSED_:
|
||||
keyboard.add_keycode_to_report(self.keycode)
|
||||
return
|
||||
if current == KeyEvent.RELEASED:
|
||||
keyboard.remove_keycode_from_report(self.keycode)
|
||||
return
|
||||
if current == KeyEvent.SOFT_RELEASED:
|
||||
keyboard.remove_keycode_from_report(self.keycode)
|
||||
return
|
||||
|
||||
raise NotImplementedError()
|
||||
|
||||
def handle(self, keyboard, pin):
|
||||
if not self._consume_next_event(pin):
|
||||
return
|
||||
self._handle_event(keyboard)
|
||||
|
||||
|
||||
class Keycode(KeycodeBase):
|
||||
def __init__(self, keycode):
|
||||
super().__init__(keycode)
|
||||
|
||||
def self_test(self, keymap):
|
||||
if not self.keycode in _VALID_KEYCODES:
|
||||
raise Exception("Keycode is not valid")
|
||||
|
||||
|
||||
class Modifier(KeycodeBase):
|
||||
def __init__(self, keycode):
|
||||
super().__init__(keycode)
|
||||
|
||||
def self_test(self, keymap):
|
||||
if not self.keycode in _VALID_MODIFIERS:
|
||||
raise Exception("Keycode is not valid")
|
||||
177
nmlkpy/key_types/layer.py
Normal file
177
nmlkpy/key_types/layer.py
Normal file
@@ -0,0 +1,177 @@
|
||||
from .base import KeyEvent, KeyBase
|
||||
from ..pin import PinEvent, Pin
|
||||
|
||||
|
||||
class LayerKeyBase(KeyBase):
|
||||
layer_to_switch_to: int
|
||||
|
||||
def __init__(self, layer: int, allowed_events):
|
||||
super().__init__(allowed_events)
|
||||
self.layer_to_switch_to = layer
|
||||
|
||||
def self_test(self, keymap: list[list[KeyBase]]):
|
||||
key_on_layer_to_switch_to = keymap[self.layer_to_switch_to][self.key_index]
|
||||
if key_on_layer_to_switch_to is self:
|
||||
return
|
||||
raise Exception(
|
||||
f"Toggle layer key must have an identical Toggle layer key on layer[{self.layer_to_switch_to}] key[{self.key_index}]")
|
||||
|
||||
def _release_all_other_keys(self, keyboard):
|
||||
for layer in keyboard.keymap:
|
||||
for key in layer:
|
||||
if key is self:
|
||||
continue
|
||||
key.soft_release(keyboard)
|
||||
|
||||
def _release_all_other_non_toggle_keys(self, keyboard):
|
||||
for layer in keyboard.keymap:
|
||||
for key in layer:
|
||||
if key is self or isinstance(key, Toggle):
|
||||
continue
|
||||
key.soft_release(keyboard)
|
||||
|
||||
|
||||
class Toggle(LayerKeyBase):
|
||||
def __init__(self, layer: int):
|
||||
allowed_events = [
|
||||
KeyEvent.NO_EVENT,
|
||||
KeyEvent.PRESSED_TOGGLED_ON,
|
||||
KeyEvent.RELEASED_TOGGLED_ON,
|
||||
KeyEvent.PRESSED_TOGGLED_OFF,
|
||||
KeyEvent.RELEASED,
|
||||
KeyEvent.SOFT_RELEASED]
|
||||
super().__init__(layer, allowed_events)
|
||||
|
||||
def _consume_next_event(self, pin: Pin) -> bool:
|
||||
"""Returns: a boolean representing if the event property was updated with a new event or not"""
|
||||
next_pin_event = pin.read_event()
|
||||
current_key_event, previous_key_event = self.events.current, self.events.previous
|
||||
|
||||
# First handle if key is in soft release mode
|
||||
if current_key_event == KeyEvent.SOFT_RELEASED:
|
||||
if previous_key_event == KeyEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
if previous_key_event == KeyEvent.RELEASED_TOGGLED_ON:
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
else:
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
|
||||
# After that all no events from the pin is handled in the same way
|
||||
if next_pin_event == PinEvent.NO_EVENT:
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
|
||||
# Then handle each event transition emulating a trigger key
|
||||
if current_key_event == KeyEvent.RELEASED:
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
return self._set_event(KeyEvent.PRESSED_TOGGLED_ON)
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
if current_key_event == KeyEvent.PRESSED_TOGGLED_ON:
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.RELEASED_TOGGLED_ON)
|
||||
if current_key_event == KeyEvent.RELEASED_TOGGLED_ON:
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
return self._set_event(KeyEvent.PRESSED_TOGGLED_OFF)
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
if current_key_event == KeyEvent.PRESSED_TOGGLED_OFF:
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
|
||||
raise NotImplementedError()
|
||||
|
||||
def _handle_event(self, keyboard, pin):
|
||||
current = self.events.current
|
||||
if current == KeyEvent.PRESSED_TOGGLED_ON:
|
||||
keyboard.layer.toggle(self.layer_to_switch_to)
|
||||
self._release_all_other_keys(keyboard)
|
||||
return
|
||||
if current == KeyEvent.RELEASED_TOGGLED_ON:
|
||||
return
|
||||
if current == KeyEvent.PRESSED_TOGGLED_OFF:
|
||||
keyboard.layer.release_toggled()
|
||||
self._release_all_other_keys(keyboard)
|
||||
return
|
||||
if current == KeyEvent.RELEASED:
|
||||
return
|
||||
|
||||
raise NotImplementedError()
|
||||
|
||||
def handle(self, keyboard, pin: Pin):
|
||||
if not self._consume_next_event(pin):
|
||||
return
|
||||
self._handle_event(keyboard, pin)
|
||||
|
||||
def soft_release(self, keyboard):
|
||||
pressed = self.events.current not in [
|
||||
KeyEvent.RELEASED,
|
||||
KeyEvent.PRESSED_TOGGLED_OFF,
|
||||
KeyEvent.SOFT_RELEASED
|
||||
]
|
||||
if not pressed:
|
||||
return
|
||||
self._set_event(KeyEvent.SOFT_RELEASED)
|
||||
|
||||
|
||||
class Hold(LayerKeyBase):
|
||||
def __init__(self, layer: int):
|
||||
allowed_events = [KeyEvent.NO_EVENT,
|
||||
KeyEvent.SOFT_RELEASED,
|
||||
KeyEvent.PRESSED_, KeyEvent.RELEASED]
|
||||
super().__init__(layer, allowed_events)
|
||||
|
||||
def soft_release(self, keyboard):
|
||||
if self.events.current != KeyEvent.PRESSED_:
|
||||
return
|
||||
keyboard.layer.release_held()
|
||||
|
||||
def handle(self, keyboard, pin):
|
||||
if not self._consume_next_event(pin):
|
||||
return
|
||||
self._handle_event(keyboard)
|
||||
|
||||
def _consume_next_event(self, pin: Pin) -> bool:
|
||||
next_pin_event = pin.read_event()
|
||||
current_key_event, previous_key_event = self.events.current, self.events.previous
|
||||
|
||||
# handle soft release
|
||||
if current_key_event == KeyEvent.SOFT_RELEASED:
|
||||
if previous_key_event == KeyEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
|
||||
# handle no-event's
|
||||
if next_pin_event == PinEvent.NO_EVENT:
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
|
||||
# handle events
|
||||
if current_key_event == KeyEvent.RELEASED:
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
return self._set_event(KeyEvent.PRESSED_)
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
if current_key_event == KeyEvent.PRESSED_:
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
|
||||
def _handle_event(self, keyboard):
|
||||
current = self.events.current
|
||||
|
||||
if current == KeyEvent.PRESSED_:
|
||||
keyboard.layer.hold(self.layer_to_switch_to)
|
||||
self._release_all_other_non_toggle_keys(keyboard)
|
||||
return
|
||||
if current == KeyEvent.RELEASED:
|
||||
keyboard.layer.release_held()
|
||||
self._release_all_other_non_toggle_keys(keyboard)
|
||||
return
|
||||
|
||||
raise NotImplementedError()
|
||||
10
nmlkpy/keyboard.py
Executable file → Normal file
10
nmlkpy/keyboard.py
Executable file → Normal file
@@ -1,14 +1,14 @@
|
||||
from adafruit_mcp230xx.digital_inout import DigitalInOut
|
||||
|
||||
from micropython import const
|
||||
from adafruit_mcp230xx.mcp23017 import MCP23017
|
||||
from .tests import test_keymap
|
||||
from .key_types.base import KeyBase
|
||||
from .pin import Pin
|
||||
import digitalio
|
||||
import busio
|
||||
from .tests import test_keymap
|
||||
import usb_hid
|
||||
import pwmio
|
||||
import time
|
||||
from micropython import const
|
||||
from .keytypes import KeyBase
|
||||
from .pin import Pin
|
||||
|
||||
|
||||
__RED = (255, 0, 0)
|
||||
|
||||
@@ -1,373 +0,0 @@
|
||||
from micropython import const
|
||||
from .pin import Pin, PinEvent
|
||||
|
||||
_VALID_KEYCODES = range(0, 255)
|
||||
_VALID_MODIFIERS = [0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000]
|
||||
|
||||
|
||||
class KeyEvent:
|
||||
"""Interpretations of KeyStates as single events"""
|
||||
NO_EVENT: 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_RELEASED: int = const(3)
|
||||
"""The key was released programatically, and not by an actual physical release of a button."""
|
||||
PRESSED_TOGGLED_ON = const(4)
|
||||
"""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"""
|
||||
RELEASED_TOGGLED_ON = const(5)
|
||||
"""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(6)
|
||||
"""Key is pressed and is emulating a toggle key in OFF state"""
|
||||
|
||||
|
||||
def _event_to_string(event: int) -> str:
|
||||
if event == KeyEvent.NO_EVENT:
|
||||
return "NO EVENT"
|
||||
if event == KeyEvent.PRESSED_:
|
||||
return "PRESSED"
|
||||
if event == KeyEvent.RELEASED:
|
||||
return "RELEASED"
|
||||
if event == KeyEvent.SOFT_RELEASED:
|
||||
return "SOFT_RELEASED"
|
||||
if event == KeyEvent.PRESSED_TOGGLED_ON:
|
||||
return "PRESSED TOGGLED ON"
|
||||
if event == KeyEvent.RELEASED_TOGGLED_ON:
|
||||
return "RELEASED TOGGLED ON"
|
||||
if event == KeyEvent.PRESSED_TOGGLED_OFF:
|
||||
return "PRESSED TOGGLED OFF"
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class KeyEvents:
|
||||
current: int
|
||||
previous: int
|
||||
|
||||
def __init__(self):
|
||||
self.current = KeyEvent.RELEASED
|
||||
self.previous = KeyEvent.RELEASED
|
||||
|
||||
def shift(self, next):
|
||||
self.previous = self.current
|
||||
self.current = next
|
||||
|
||||
|
||||
class KeyBase:
|
||||
events: KeyEvents
|
||||
allowed_events: list[KeyEvent]
|
||||
key_index: int
|
||||
layer_index: int
|
||||
|
||||
def __init__(self, allowed_events: list[int]):
|
||||
self.allowed_events = allowed_events
|
||||
self.events = KeyEvents()
|
||||
self.key_index = None
|
||||
self.layer_index = None
|
||||
|
||||
def enrich(self, key_index: int, layer_index: int):
|
||||
self.key_index = key_index
|
||||
self.layer_index = layer_index
|
||||
|
||||
def _validate_next_event(self, next_event: int):
|
||||
if next_event is None or next_event not in self.allowed_events:
|
||||
raise Exception(
|
||||
f"KeyEvent with value of {next_event} is not a valid event for this type of key")
|
||||
|
||||
def _set_event(self, next_event: int) -> bool:
|
||||
"""Sets previous state if new state is valid
|
||||
Returns: A boolean that determines if the state was updated or not"""
|
||||
self._validate_next_event(next_event)
|
||||
if next_event is KeyEvent.NO_EVENT:
|
||||
return False
|
||||
print(
|
||||
f"[{self.key_index}] next: {_event_to_string(next_event)}, current: {_event_to_string(self.events.current)}, previous: {_event_to_string(self.events.previous)}")
|
||||
self.events.shift(next_event)
|
||||
return True
|
||||
|
||||
def handle(self, keyboard):
|
||||
raise NotImplementedError()
|
||||
|
||||
def self_test(self, keymap: list[list[object]]):
|
||||
raise NotImplementedError()
|
||||
|
||||
def soft_release(self, keyboard):
|
||||
"""Release key programatically and wait until it's released physically before registrating additional key presses"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class KeycodeBase(KeyBase):
|
||||
"""Basic press and release functionality that appends a keycode to the report when active"""
|
||||
keycode: int
|
||||
|
||||
def __init__(self, keycode: int):
|
||||
allowed_events = [KeyEvent.NO_EVENT,
|
||||
KeyEvent.PRESSED_,
|
||||
KeyEvent.RELEASED,
|
||||
KeyEvent.SOFT_RELEASED]
|
||||
super().__init__(allowed_events)
|
||||
self.keycode = keycode
|
||||
|
||||
def self_test(self, keymap):
|
||||
raise NotImplementedError
|
||||
|
||||
def soft_release(self, keyboard):
|
||||
if self.events.current != KeyEvent.PRESSED_:
|
||||
return
|
||||
self._set_event(KeyEvent.SOFT_RELEASED)
|
||||
|
||||
def _consume_next_event(self, pin) -> bool:
|
||||
"""Returns: a boolean representing if the event property was updated with a new event or not"""
|
||||
next_pin_event = pin.read_event()
|
||||
current_key_event, previous_key_event = self.events.current, self.events.previous
|
||||
next_key_event = None
|
||||
|
||||
if current_key_event == KeyEvent.SOFT_RELEASED:
|
||||
if previous_key_event == KeyEvent.RELEASED:
|
||||
print(1)
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
print(2)
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
if previous_key_event == KeyEvent.PRESSED_ or next_pin_event == PinEvent.PRESSED:
|
||||
print(3)
|
||||
return self._set_event(KeyEvent.SOFT_RELEASED)
|
||||
print(4)
|
||||
return self._set_event(KeyEvent.SOFT_RELEASED)
|
||||
|
||||
if current_key_event == KeyEvent.NO_EVENT:
|
||||
if next_pin_event == PinEvent.NO_EVENT:
|
||||
next_key_event = KeyEvent.NO_EVENT
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
next_key_event = KeyEvent.RELEASED
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
next_key_event = KeyEvent.PRESSED_
|
||||
if current_key_event == KeyEvent.RELEASED:
|
||||
if next_pin_event == PinEvent.NO_EVENT:
|
||||
next_key_event = KeyEvent.NO_EVENT
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
next_key_event = KeyEvent.NO_EVENT
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
next_key_event = KeyEvent.PRESSED_
|
||||
if current_key_event == KeyEvent.PRESSED_:
|
||||
if next_pin_event == PinEvent.NO_EVENT:
|
||||
next_key_event = KeyEvent.NO_EVENT
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
next_key_event = KeyEvent.RELEASED
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
next_key_event = KeyEvent.NO_EVENT
|
||||
|
||||
return self._set_event(next_key_event)
|
||||
|
||||
def _handle_event(self, keyboard) -> None:
|
||||
current = self.events.current
|
||||
if current == KeyEvent.PRESSED_:
|
||||
keyboard.add_keycode_to_report(self.keycode)
|
||||
return
|
||||
if current == KeyEvent.RELEASED:
|
||||
keyboard.remove_keycode_from_report(self.keycode)
|
||||
return
|
||||
if current == KeyEvent.SOFT_RELEASED:
|
||||
keyboard.remove_keycode_from_report(self.keycode)
|
||||
return
|
||||
|
||||
raise NotImplementedError()
|
||||
|
||||
def handle(self, keyboard, pin):
|
||||
if not self._consume_next_event(pin):
|
||||
return
|
||||
self._handle_event(keyboard)
|
||||
|
||||
|
||||
class Keycode(KeycodeBase):
|
||||
def __init__(self, keycode):
|
||||
super().__init__(keycode)
|
||||
|
||||
def self_test(self, keymap):
|
||||
if not self.keycode in _VALID_KEYCODES:
|
||||
raise Exception("Keycode is not valid")
|
||||
|
||||
|
||||
class Modifier(KeycodeBase):
|
||||
def __init__(self, keycode):
|
||||
super().__init__(keycode)
|
||||
|
||||
def self_test(self, keymap):
|
||||
if not self.keycode in _VALID_MODIFIERS:
|
||||
raise Exception("Keycode is not valid")
|
||||
|
||||
|
||||
class LayerKeyBase(KeyBase):
|
||||
layer_to_switch_to: int
|
||||
|
||||
def __init__(self, layer: int, allowed_events):
|
||||
super().__init__(allowed_events)
|
||||
self.layer_to_switch_to = layer
|
||||
|
||||
def self_test(self, keymap: list[list[KeyBase]]):
|
||||
key_on_layer_to_switch_to = keymap[self.layer_to_switch_to][self.key_index]
|
||||
if key_on_layer_to_switch_to is self:
|
||||
return
|
||||
raise Exception(
|
||||
f"Toggle layer key must have an identical Toggle layer key on layer[{self.layer_to_switch_to}] key[{self.key_index}]")
|
||||
|
||||
def _release_all_other_keys(self, keyboard):
|
||||
for layer in keyboard.keymap:
|
||||
for key in layer:
|
||||
if key is self:
|
||||
continue
|
||||
key.soft_release(keyboard)
|
||||
|
||||
def _release_all_other_non_toggle_keys(self, keyboard):
|
||||
for layer in keyboard.keymap:
|
||||
for key in layer:
|
||||
if key is self or isinstance(key, Toggle):
|
||||
continue
|
||||
key.soft_release(keyboard)
|
||||
|
||||
|
||||
class Toggle(LayerKeyBase):
|
||||
def __init__(self, layer: int):
|
||||
allowed_events = [
|
||||
KeyEvent.NO_EVENT,
|
||||
KeyEvent.PRESSED_TOGGLED_ON,
|
||||
KeyEvent.RELEASED_TOGGLED_ON,
|
||||
KeyEvent.PRESSED_TOGGLED_OFF,
|
||||
KeyEvent.RELEASED,
|
||||
KeyEvent.SOFT_RELEASED]
|
||||
super().__init__(layer, allowed_events)
|
||||
|
||||
def _consume_next_event(self, pin: Pin) -> bool:
|
||||
"""Returns: a boolean representing if the event property was updated with a new event or not"""
|
||||
next_pin_event = pin.read_event()
|
||||
current_key_event, previous_key_event = self.events.current, self.events.previous
|
||||
|
||||
# First handle if key is in soft release mode
|
||||
if current_key_event == KeyEvent.SOFT_RELEASED:
|
||||
if previous_key_event == KeyEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
if previous_key_event == KeyEvent.RELEASED_TOGGLED_ON:
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
else:
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
|
||||
# After that all no events from the pin is handled in the same way
|
||||
if next_pin_event == PinEvent.NO_EVENT:
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
|
||||
# Then handle each event transition emulating a trigger key
|
||||
if current_key_event == KeyEvent.RELEASED:
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
return self._set_event(KeyEvent.PRESSED_TOGGLED_ON)
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
if current_key_event == KeyEvent.PRESSED_TOGGLED_ON:
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.RELEASED_TOGGLED_ON)
|
||||
if current_key_event == KeyEvent.RELEASED_TOGGLED_ON:
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
return self._set_event(KeyEvent.PRESSED_TOGGLED_OFF)
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
if current_key_event == KeyEvent.PRESSED_TOGGLED_OFF:
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
|
||||
raise NotImplementedError()
|
||||
|
||||
def _handle_event(self, keyboard, pin):
|
||||
current = self.events.current
|
||||
if current == KeyEvent.PRESSED_TOGGLED_ON:
|
||||
keyboard.layer.toggle(self.layer_to_switch_to)
|
||||
self._release_all_other_keys(keyboard)
|
||||
return
|
||||
if current == KeyEvent.RELEASED_TOGGLED_ON:
|
||||
return
|
||||
if current == KeyEvent.PRESSED_TOGGLED_OFF:
|
||||
keyboard.layer.release_toggled()
|
||||
self._release_all_other_keys(keyboard)
|
||||
return
|
||||
if current == KeyEvent.RELEASED:
|
||||
return
|
||||
|
||||
raise NotImplementedError()
|
||||
|
||||
def handle(self, keyboard, pin: Pin):
|
||||
if not self._consume_next_event(pin):
|
||||
return
|
||||
self._handle_event(keyboard, pin)
|
||||
|
||||
def soft_release(self, keyboard):
|
||||
pressed = self.events.current not in [
|
||||
KeyEvent.RELEASED,
|
||||
KeyEvent.PRESSED_TOGGLED_OFF,
|
||||
KeyEvent.SOFT_RELEASED
|
||||
]
|
||||
if not pressed:
|
||||
return
|
||||
self._set_event(KeyEvent.SOFT_RELEASED)
|
||||
|
||||
|
||||
class Hold(LayerKeyBase):
|
||||
def __init__(self, layer: int):
|
||||
allowed_events = [KeyEvent.NO_EVENT,
|
||||
KeyEvent.SOFT_RELEASED,
|
||||
KeyEvent.PRESSED_, KeyEvent.RELEASED]
|
||||
super().__init__(layer, allowed_events)
|
||||
|
||||
def soft_release(self, keyboard):
|
||||
if self.events.current != KeyEvent.PRESSED_:
|
||||
return
|
||||
keyboard.layer.release_held()
|
||||
|
||||
def handle(self, keyboard, pin):
|
||||
if not self._consume_next_event(pin):
|
||||
return
|
||||
self._handle_event(keyboard)
|
||||
|
||||
def _consume_next_event(self, pin: Pin) -> bool:
|
||||
next_pin_event = pin.read_event()
|
||||
current_key_event, previous_key_event = self.events.current, self.events.previous
|
||||
|
||||
# handle soft release
|
||||
if current_key_event == KeyEvent.SOFT_RELEASED:
|
||||
if previous_key_event == KeyEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
|
||||
# handle no-event's
|
||||
if next_pin_event == PinEvent.NO_EVENT:
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
|
||||
# handle events
|
||||
if current_key_event == KeyEvent.RELEASED:
|
||||
if next_pin_event == PinEvent.PRESSED:
|
||||
return self._set_event(KeyEvent.PRESSED_)
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
if current_key_event == KeyEvent.PRESSED_:
|
||||
if next_pin_event == PinEvent.RELEASED:
|
||||
return self._set_event(KeyEvent.RELEASED)
|
||||
return self._set_event(KeyEvent.NO_EVENT)
|
||||
|
||||
def _handle_event(self, keyboard):
|
||||
current = self.events.current
|
||||
|
||||
if current == KeyEvent.PRESSED_:
|
||||
keyboard.layer.hold(self.layer_to_switch_to)
|
||||
self._release_all_other_non_toggle_keys(keyboard)
|
||||
return
|
||||
if current == KeyEvent.RELEASED:
|
||||
keyboard.layer.release_held()
|
||||
self._release_all_other_non_toggle_keys(keyboard)
|
||||
return
|
||||
|
||||
raise NotImplementedError()
|
||||
2
nmlkpy/layer_manager.py
Executable file → Normal file
2
nmlkpy/layer_manager.py
Executable file → Normal file
@@ -1,4 +1,4 @@
|
||||
from .keytypes import Hold, Toggle
|
||||
from .key_types.layer import Hold, Toggle
|
||||
|
||||
|
||||
class LayerManager:
|
||||
|
||||
0
nmlkpy/pin.py
Executable file → Normal file
0
nmlkpy/pin.py
Executable file → Normal file
0
nmlkpy/tests.py
Executable file → Normal file
0
nmlkpy/tests.py
Executable file → Normal file
Reference in New Issue
Block a user