from .keymap_delta import KeymapDelta, LayerDelta from .pinstate_manager import PinManager from .key_types.base import KeyBase from .pin import Pin # Needs to be built in a way where every "key type" only has to know how to modify it's own state # it cannot be passed a pin or keyboard instance # this is to help keep order in what can access what # layer manager should be able to figure out what needs to happen to the state after a loop is run. # # Keys # Keys have one way communication from KeymapManager to key and are allowed to return a result # all keys changes together create a delta that is handled by the manager # the manager defines an interface for changes that can happen to the state # - Pressed # - unpressed # - Layer was changed # When a delta is applied the manager can figure out what to do for that state index # state # Keys state is stored and managed in the manager # One single layer of state removes the issue of when layers are changing # each state is a class that can be consumed from different aspects, keycode, toggle, hold etc # Where the state presents itself in the way that is asked # Pins # Can be asked for their current event # Pins state is a class that holds current and last, can give you the delta to figure out what to change _LAYERS_HOLD_NONE = None _LAYERS_TOGGLE_NONE = 0 class LayerManager: number_of_layers: int = None current_hold_layer: int = None current_toggle_layer: int = None def __init__(self, number_of_layers: int) -> None: assert number_of_layers is not None assert number_of_layers > 0 self.number_of_layers = number_of_layers self.current_hold_layer = _LAYERS_HOLD_NONE self.current_toggle_layer = _LAYERS_TOGGLE_NONE def get_current_layer(self) -> int: return self.current_hold_layer if self.current_hold_layer is not _LAYERS_HOLD_NONE else self.current_toggle_layer def step(self, changes: LayerDelta): hold_layer = self.current_hold_layer for layer in changes.get_hold_layers_to_remove(): if layer.get_layer() == hold_layer: hold_layer = _LAYERS_HOLD_NONE for layer in changes.get_hold_layers_to_apply(): hold_layer = layer.get_layer() self.current_hold_layer = hold_layer toggle_layer = self.current_toggle_layer for layer in changes.get_toggle_layers_to_remove(): if layer.get_layer() == toggle_layer: toggle_layer = _LAYERS_TOGGLE_NONE for layer in changes.get_toggle_layers_to_apply(): toggle_layer = layer.get_layer() self.current_toggle_layer = toggle_layer class KeymapReport: keymap_changes: KeymapDelta = None current_layer: int = None def __init__(self, keymap_changes: KeymapDelta, current_layer: int) -> None: assert keymap_changes is not None assert current_layer is not None self.keymap_changes = keymap_changes self.current_layer = current_layer class KeymapManager: keymap: list[list[KeyBase]] = None pin_manager: PinManager = None layer_manager: LayerManager = None keys_state: list[object] = None keycodes_currently_pressed: set = None def __init__(self, keymap: list[list[KeyBase]], pins: list[Pin]): self.keymap = keymap self.pin_manager = PinManager(pins) self.layer_manager = LayerManager(len(keymap)) self.keys_state = [None for key in keymap[0]] self.keycodes_currently_pressed = set() def add_to_pressed_keycodes(self, keycode: int): self.keycodes_currently_pressed.add(keycode) def remove_from_pressed_keycodes(self, keycode: int): try: self.keycodes_currently_pressed.remove(keycode) except KeyError: pass def createReport(self, keymap_changes: KeymapDelta, layer_changes: LayerDelta) -> KeymapReport: old_layer = self.layer_manager.get_current_layer() self.layer_manager.step(layer_changes) new_layer = self.layer_manager.get_current_layer() layer_has_changed = new_layer != old_layer if layer_has_changed: delta = KeymapDelta() for keycode in self.keycodes_currently_pressed: delta.unpress(keycode) self.keycodes_currently_pressed.clear() keymap_changes.merge_deltas(delta) [self.add_to_pressed_keycodes(keycode) for keycode in keymap_changes.get_to_press()] [self.remove_from_pressed_keycodes( keycode) for keycode in keymap_changes.get_to_unpress()] return KeymapReport(keymap_changes, new_layer) def step(self) -> KeymapReport: self.pin_manager.step() pin_changes = self.pin_manager.get_state_delta() keymap_changes = KeymapDelta() layer_changes = LayerDelta() current_layer_index = self.layer_manager.get_current_layer() for pin_index in range(len(pin_changes)): pin_state = pin_changes[pin_index] if pin_state is None: continue key = self.keymap[current_layer_index][pin_index] custom_state = self.keys_state[pin_index] key_changes = key.calculate_changes(pin_state, custom_state) keymap_changes.merge_deltas(key_changes.keymap_delta) layer_changes.merge_deltas(key_changes.layer_delta) self.keys_state[pin_index] = key_changes.special_state return self.createReport(keymap_changes, layer_changes)