started to rebuild soft release functionality

This commit is contained in:
2022-01-14 13:03:04 +01:00
parent cf0ceeb15c
commit b4f61cf8e7
5 changed files with 95 additions and 126 deletions

View File

@@ -6,7 +6,7 @@ lm = LayerManager(5)
keymap = [[
lm.hold(1), lm.toggle(2), lm.toggle(3), lm.toggle(4),
lm.toggle(0), Keycode(SE.B), Keycode(SE.C), Keycode(SE.D),
lm.hold(2), Keycode(SE.B), Keycode(SE.C), Keycode(SE.D),
Keycode(SE.LEFT), Keycode(SE.DOWN), Keycode(
SE.UP), Keycode(SE.RIGHT),
Keycode(SE.ENTER), Keycode(SE.J), Keycode(

View File

@@ -9,13 +9,11 @@ class KeyEvent:
"""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)
PRESSED_TOGGLED_ON = const(3)
"""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)
RELEASED_TOGGLED_ON = const(4)
"""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)
PRESSED_TOGGLED_OFF = const(5)
"""Key is pressed and is emulating a toggle key in OFF state"""
@@ -26,8 +24,6 @@ def _event_to_string(event: int) -> str:
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:
@@ -37,13 +33,52 @@ def _event_to_string(event: int) -> str:
raise NotImplementedError()
class SoftRelease:
_NOT_QUEUED = 0
_QUEUED = 1
_HANDLED = 2
_state: int
def __init__(self):
self._state = self._NOT_QUEUED
def is_not_queued(self) -> bool:
return self._state == self._NOT_QUEUED
def is_queued(self) -> bool:
return self._state == self._QUEUED
def is_handled(self) -> bool:
return self._state == self._HANDLED
def reset(self):
self._state = self._NOT_QUEUED
def queue(self):
self._state = self._QUEUED
def mark_as_handled(self):
self._state = self._HANDLED
def __str__(self):
if self._state == self._NOT_QUEUED:
return "Not queued"
if self._state == self._QUEUED:
return "Queued"
if self._state == self._HANDLED:
return "Handled"
raise NotImplementedError()
class KeyEvents:
current: int
previous: int
soft_release: SoftRelease
def __init__(self):
self.current = KeyEvent.RELEASED
self.previous = KeyEvent.RELEASED
self.soft_release = SoftRelease()
def shift(self, next):
self.previous = self.current
@@ -53,32 +88,24 @@ class KeyEvents:
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:
def _set_event(self, next_event: int, index: int = 99) -> 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)}")
f"[{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

View File

@@ -10,10 +10,11 @@ class KeycodeBase(KeyBase):
keycode: int
def __init__(self, keycode: int):
allowed_events = [KeyEvent.NO_EVENT,
KeyEvent.PRESSED_,
KeyEvent.RELEASED,
KeyEvent.SOFT_RELEASED]
allowed_events = [
KeyEvent.NO_EVENT,
KeyEvent.PRESSED_,
KeyEvent.RELEASED
]
super().__init__(allowed_events)
self.keycode = keycode
@@ -21,62 +22,37 @@ class KeycodeBase(KeyBase):
raise NotImplementedError
def soft_release(self, keyboard):
if self.events.current != KeyEvent.PRESSED_:
return
self._set_event(KeyEvent.SOFT_RELEASED)
self.events.soft_release.queue()
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
current_key_event = self.events.current
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_
return self._set_event(KeyEvent.PRESSED_)
return self._set_event(KeyEvent.NO_EVENT)
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(KeyEvent.RELEASED)
return self._set_event(KeyEvent.NO_EVENT)
return self._set_event(next_key_event)
raise NotImplementedError()
def _handle_event(self, keyboard) -> None:
current = self.events.current
if self.events.soft_release.is_queued():
pass
if self.events.soft_release.is_handled():
pass
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:
if current == KeyEvent.SOFT_RELEASE_HANDLED:
keyboard.remove_keycode_from_report(self.keycode)
return

View File

@@ -10,11 +10,8 @@ class LayerKeyBase(KeyBase):
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}]")
# to be implemented, can not use enrichment of indexes
pass
def _release_all_other_keys(self, keyboard):
for layer in keyboard.keymap:
@@ -38,56 +35,44 @@ class Toggle(LayerKeyBase):
KeyEvent.PRESSED_TOGGLED_ON,
KeyEvent.RELEASED_TOGGLED_ON,
KeyEvent.PRESSED_TOGGLED_OFF,
KeyEvent.RELEASED,
KeyEvent.SOFT_RELEASED]
KeyEvent.RELEASED
]
super().__init__(layer, allowed_events)
def soft_release(self, keyboard):
self.events.soft_release.queue()
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
current_key_event = self.events.current
# 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)
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)
return self._set_event(KeyEvent.NO_EVENT)
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)
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)
return self._set_event(KeyEvent.NO_EVENT)
raise NotImplementedError()
def _handle_event(self, keyboard, pin):
current = self.events.current
if self.events.soft_release.is_queued():
pass
if self.events.soft_release.is_handled():
pass
if current == KeyEvent.PRESSED_TOGGLED_ON:
keyboard.layer.toggle(self.layer_to_switch_to)
self._release_all_other_keys(keyboard)
@@ -108,28 +93,18 @@ class Toggle(LayerKeyBase):
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]
allowed_events = [
KeyEvent.NO_EVENT,
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()
self.events.soft_release.queue()
def handle(self, keyboard, pin):
if not self._consume_next_event(pin):
@@ -138,30 +113,18 @@ class Hold(LayerKeyBase):
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 self.events.current == 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 self.events.current == KeyEvent.PRESSED_:
if next_pin_event == PinEvent.RELEASED:
return self._set_event(KeyEvent.RELEASED)
return self._set_event(KeyEvent.NO_EVENT)
raise NotImplementedError()
def _handle_event(self, keyboard):
current = self.events.current

View File

@@ -154,9 +154,12 @@ class Keyboard:
print("Done initializing keyboard")
def _initialize_keymap(self, keymap: list[list[KeyBase]]) -> list[list[KeyBase]]:
for layer in keymap:
for key in layer:
key.enrich(layer.index(key), keymap.index(layer))
# keys cannot be enriched like that since they share state
# for layer_index in range(len(keymap)):
# layer = keymap[layer_index]
# for key_index in range(len(layer)):
# key = layer[key_index]
# key.enrich(key_index, layer_index)
test_keymap(keymap, True)
return keymap