Checkpoint alpha: Reflow macros and keycodes into a consistent structure. Most internal state functionality largely untouched (just moved)
This commit is contained in:
		| @@ -1,19 +1,13 @@ | ||||
| from kmk.consts import LeaderMode | ||||
| from kmk.keycodes import (FIRST_KMK_INTERNAL_KEYCODE, Keycodes, RawKeycodes, | ||||
|                           TapDanceKeycode) | ||||
| from kmk.kmktime import sleep_ms, ticks_diff, ticks_ms | ||||
| from kmk.keycodes import KC | ||||
| from kmk.kmktime import ticks_ms | ||||
| from kmk.types import TapDanceKeyMeta | ||||
| from kmk.util import intify_coordinate | ||||
|  | ||||
| GESC_TRIGGERS = { | ||||
|     Keycodes.Modifiers.KC_LSHIFT, Keycodes.Modifiers.KC_RSHIFT, | ||||
|     Keycodes.Modifiers.KC_LGUI, Keycodes.Modifiers.KC_RGUI, | ||||
| } | ||||
|  | ||||
|  | ||||
| class InternalState: | ||||
|     keys_pressed = set() | ||||
|     coord_keys_pressed = {} | ||||
|     macros_pending = [] | ||||
|     leader_pending = None | ||||
|     leader_last_len = 0 | ||||
|     hid_pending = False | ||||
| @@ -34,22 +28,6 @@ class InternalState: | ||||
|  | ||||
|     def __init__(self, config): | ||||
|         self.config = config | ||||
|         self.internal_key_handlers = { | ||||
|             RawKeycodes.KC_DF: self._layer_df, | ||||
|             RawKeycodes.KC_MO: self._layer_mo, | ||||
|             RawKeycodes.KC_LM: self._layer_lm, | ||||
|             RawKeycodes.KC_LT: self._layer_lt, | ||||
|             RawKeycodes.KC_TG: self._layer_tg, | ||||
|             RawKeycodes.KC_TO: self._layer_to, | ||||
|             RawKeycodes.KC_TT: self._layer_tt, | ||||
|             Keycodes.KMK.KC_GESC.code: self._kc_gesc, | ||||
|             RawKeycodes.KC_UC_MODE: self._kc_uc_mode, | ||||
|             RawKeycodes.KC_MACRO: self._kc_macro, | ||||
|             Keycodes.KMK.KC_LEAD.code: self._kc_lead, | ||||
|             Keycodes.KMK.KC_NO.code: self._kc_no, | ||||
|             Keycodes.KMK.KC_DEBUG.code: self._kc_debug_mode, | ||||
|             RawKeycodes.KC_TAP_DANCE: self._kc_tap_dance, | ||||
|         } | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return 'InternalState({})'.format(self._to_dict()) | ||||
| @@ -74,7 +52,7 @@ class InternalState: | ||||
|         for layer in self.reversed_active_layers: | ||||
|             layer_key = self.config.keymap[layer][row][col] | ||||
|  | ||||
|             if not layer_key or layer_key == Keycodes.KMK.KC_TRNS: | ||||
|             if not layer_key or layer_key == KC.TRNS: | ||||
|                 continue | ||||
|  | ||||
|             if self.config.debug_enabled: | ||||
| @@ -122,16 +100,16 @@ class InternalState: | ||||
|             print('No key accessible for col, row: {}, {}'.format(row, col)) | ||||
|             return self | ||||
|  | ||||
|         if self.tapping and not isinstance(kc_changed, TapDanceKeycode): | ||||
|             self._process_tap_dance(kc_changed, is_pressed) | ||||
|         return self.process_key(kc_changed, is_pressed, int_coord, (row, col)) | ||||
|  | ||||
|     def process_key(self, key, is_pressed, coord_int=None, coord_raw=None): | ||||
|         if self.tapping and not isinstance(key.meta, TapDanceKeyMeta): | ||||
|             self._process_tap_dance(key, is_pressed) | ||||
|         else: | ||||
|             if is_pressed: | ||||
|                 self.coord_keys_pressed[int_coord] = kc_changed | ||||
|                 self.add_key(kc_changed) | ||||
|                 key.on_press(self, coord_int, coord_raw) | ||||
|             else: | ||||
|                 self.remove_key(kc_changed) | ||||
|                 self.keys_pressed.discard(self.coord_keys_pressed.get(int_coord, None)) | ||||
|                 self.coord_keys_pressed[int_coord] = None | ||||
|                 key.on_release(self, coord_int, coord_raw) | ||||
|  | ||||
|             if self.config.leader_mode % 2 == 1: | ||||
|                 self._process_leader_mode() | ||||
| @@ -140,27 +118,11 @@ class InternalState: | ||||
|  | ||||
|     def remove_key(self, keycode): | ||||
|         self.keys_pressed.discard(keycode) | ||||
|  | ||||
|         if keycode.code >= FIRST_KMK_INTERNAL_KEYCODE: | ||||
|             self._process_internal_key_event(keycode, False) | ||||
|         else: | ||||
|             self.hid_pending = True | ||||
|  | ||||
|         return self | ||||
|         return self.process_key(keycode, False) | ||||
|  | ||||
|     def add_key(self, keycode): | ||||
|         # TODO Make this itself a macro keycode with a keyup handler | ||||
|         #      rather than handling this inline here. Gross. | ||||
|         if keycode.code == Keycodes.KMK.KC_MACRO_SLEEP_MS: | ||||
|             sleep_ms(keycode.ms) | ||||
|         else: | ||||
|             self.keys_pressed.add(keycode) | ||||
|  | ||||
|             if keycode.code >= FIRST_KMK_INTERNAL_KEYCODE: | ||||
|                 self._process_internal_key_event(keycode, True) | ||||
|             else: | ||||
|                 self.hid_pending = True | ||||
|         return self | ||||
|         self.keys_pressed.add(keycode) | ||||
|         return self.process_key(keycode, True) | ||||
|  | ||||
|     def tap_key(self, keycode): | ||||
|         self.add_key(keycode) | ||||
| @@ -175,13 +137,6 @@ class InternalState: | ||||
|         self.hid_pending = False | ||||
|         return self | ||||
|  | ||||
|     def resolve_macro(self): | ||||
|         if self.config.debug_enabled: | ||||
|             print('Macro complete!') | ||||
|  | ||||
|         self.macros_pending.pop() | ||||
|         return self | ||||
|  | ||||
|     def _process_internal_key_event(self, changed_key, is_pressed): | ||||
|         # Since the key objects can be chained into new objects | ||||
|         # with, for example, no_press set, always check against | ||||
| @@ -192,164 +147,9 @@ class InternalState: | ||||
|             changed_key, is_pressed, | ||||
|         ) | ||||
|  | ||||
|     def _layer_df(self, changed_key, is_pressed): | ||||
|         """Switches the default layer""" | ||||
|         if is_pressed: | ||||
|             self.active_layers[0] = changed_key.layer | ||||
|             self.reversed_active_layers = list(reversed(self.active_layers)) | ||||
|  | ||||
|         return self | ||||
|  | ||||
|     def _layer_mo(self, changed_key, is_pressed): | ||||
|         """Momentarily activates layer, switches off when you let go""" | ||||
|         if is_pressed: | ||||
|             self.active_layers.append(changed_key.layer) | ||||
|         else: | ||||
|             self.active_layers = [ | ||||
|                 layer for layer in self.active_layers | ||||
|                 if layer != changed_key.layer | ||||
|             ] | ||||
|  | ||||
|         self.reversed_active_layers = list(reversed(self.active_layers)) | ||||
|  | ||||
|         return self | ||||
|  | ||||
|     def _layer_lm(self, changed_key, is_pressed): | ||||
|         """As MO(layer) but with mod active""" | ||||
|         self.hid_pending = True | ||||
|  | ||||
|         if is_pressed: | ||||
|             # Sets the timer start and acts like MO otherwise | ||||
|             self.start_time['lm'] = ticks_ms() | ||||
|             self.keys_pressed.add(changed_key.kc) | ||||
|         else: | ||||
|             self.keys_pressed.discard(changed_key.kc) | ||||
|             self.start_time['lm'] = None | ||||
|  | ||||
|         return self._layer_mo(changed_key, is_pressed) | ||||
|  | ||||
|     def _layer_lt(self, changed_key, is_pressed): | ||||
|         """Momentarily activates layer if held, sends kc if tapped""" | ||||
|         if is_pressed: | ||||
|             # Sets the timer start and acts like MO otherwise | ||||
|             self.start_time['lt'] = ticks_ms() | ||||
|             self._layer_mo(changed_key, is_pressed) | ||||
|         else: | ||||
|             # On keyup, check timer, and press key if needed. | ||||
|             if self.start_time['lt'] and ( | ||||
|                 ticks_diff(ticks_ms(), self.start_time['lt']) < self.config.tap_time | ||||
|             ): | ||||
|                 self.hid_pending = True | ||||
|                 self.tap_key(changed_key.kc) | ||||
|  | ||||
|             self._layer_mo(changed_key, is_pressed) | ||||
|             self.start_time['lt'] = None | ||||
|         return self | ||||
|  | ||||
|     def _layer_tg(self, changed_key, is_pressed): | ||||
|         """Toggles the layer (enables it if not active, and vise versa)""" | ||||
|         if is_pressed: | ||||
|             if changed_key.layer in self.active_layers: | ||||
|                 self.active_layers = [ | ||||
|                     layer for layer in self.active_layers | ||||
|                     if layer != changed_key.layer | ||||
|                 ] | ||||
|             else: | ||||
|                 self.active_layers.append(changed_key.layer) | ||||
|  | ||||
|             self.reversed_active_layers = list(reversed(self.active_layers)) | ||||
|  | ||||
|         return self | ||||
|  | ||||
|     def _layer_to(self, changed_key, is_pressed): | ||||
|         """Activates layer and deactivates all other layers""" | ||||
|         if is_pressed: | ||||
|             self.active_layers = [changed_key.layer] | ||||
|             self.reversed_active_layers = list(reversed(self.active_layers)) | ||||
|  | ||||
|         return self | ||||
|  | ||||
|     def _layer_tt(self, changed_key, is_pressed): | ||||
|         """Momentarily activates layer if held, toggles it if tapped repeatedly""" | ||||
|         # TODO Make this work with tap dance to function more correctly, but technically works. | ||||
|         if is_pressed: | ||||
|             if self.start_time['tt'] is None: | ||||
|                 # Sets the timer start and acts like MO otherwise | ||||
|                 self.start_time['tt'] = ticks_ms() | ||||
|                 return self._layer_mo(changed_key, is_pressed) | ||||
|             elif ticks_diff(ticks_ms(), self.start_time['tt']) < self.config.tap_time: | ||||
|                 self.start_time['tt'] = None | ||||
|                 return self.tg(changed_key, is_pressed) | ||||
|         elif ( | ||||
|             self.start_time['tt'] is None or | ||||
|             ticks_diff(ticks_ms(), self.start_time['tt']) >= self.config.tap_time | ||||
|         ): | ||||
|             # On first press, works like MO. On second press, does nothing unless let up within | ||||
|             # time window, then acts like TG. | ||||
|             self.start_time['tt'] = None | ||||
|             return self._layer_mo(changed_key, is_pressed) | ||||
|  | ||||
|         return self | ||||
|  | ||||
|     def _kc_uc_mode(self, changed_key, is_pressed): | ||||
|         if is_pressed: | ||||
|             self.config.unicode_mode = changed_key.mode | ||||
|  | ||||
|         return self | ||||
|  | ||||
|     def _kc_macro(self, changed_key, is_pressed): | ||||
|         if is_pressed: | ||||
|             if changed_key.keyup: | ||||
|                 self.macros_pending.append(changed_key.keyup) | ||||
|         else: | ||||
|             if changed_key.keydown: | ||||
|                 self.macros_pending.append(changed_key.keydown) | ||||
|  | ||||
|         return self | ||||
|  | ||||
|     def _kc_lead(self, changed_key, is_pressed): | ||||
|         if is_pressed: | ||||
|             self._begin_leader_mode() | ||||
|  | ||||
|         return self | ||||
|  | ||||
|     def _kc_gesc(self, changed_key, is_pressed): | ||||
|         self.hid_pending = True | ||||
|  | ||||
|         if is_pressed: | ||||
|             if GESC_TRIGGERS.intersection(self.keys_pressed): | ||||
|                 # if Shift is held, KC_GRAVE will become KC_TILDE on OS level | ||||
|                 self.keys_pressed.add(Keycodes.Common.KC_GRAVE) | ||||
|                 return self | ||||
|  | ||||
|             # else return KC_ESC | ||||
|             self.keys_pressed.add(Keycodes.Common.KC_ESCAPE) | ||||
|             return self | ||||
|  | ||||
|         self.keys_pressed.discard(Keycodes.Common.KC_ESCAPE) | ||||
|         self.keys_pressed.discard(Keycodes.Common.KC_GRAVE) | ||||
|         return self | ||||
|  | ||||
|     def _kc_no(self, changed_key, is_pressed): | ||||
|         return self | ||||
|  | ||||
|     def _kc_debug_mode(self, changed_key, is_pressed): | ||||
|         if is_pressed: | ||||
|             if self.config.debug_enabled: | ||||
|                 print('Disabling debug mode, bye!') | ||||
|             else: | ||||
|                 print('Enabling debug mode. Welcome to the jungle.') | ||||
|  | ||||
|             self.config.debug_enabled = not self.config.debug_enabled | ||||
|  | ||||
|         return self | ||||
|  | ||||
|     def _kc_tap_dance(self, changed_key, is_pressed): | ||||
|         return self._process_tap_dance(changed_key, is_pressed) | ||||
|  | ||||
|     def _process_tap_dance(self, changed_key, is_pressed): | ||||
|         if is_pressed: | ||||
|             if not isinstance(changed_key, TapDanceKeycode): | ||||
|             if not isinstance(changed_key.meta, TapDanceKeyMeta): | ||||
|                 # If we get here, changed_key is not a TapDanceKeycode and thus | ||||
|                 # the user kept typing elsewhere (presumably).  End ALL of the | ||||
|                 # currently outstanding tap dance runs. | ||||
| @@ -408,7 +208,7 @@ class InternalState: | ||||
|  | ||||
|     def _begin_leader_mode(self): | ||||
|         if self.config.leader_mode % 2 == 0: | ||||
|             self.keys_pressed.discard(Keycodes.KMK.KC_LEAD) | ||||
|             self.keys_pressed.discard(KC.LEAD) | ||||
|             # All leader modes are one number higher when activating | ||||
|             self.config.leader_mode += 1 | ||||
|  | ||||
| @@ -421,7 +221,7 @@ class InternalState: | ||||
|         lmh = tuple(self.leader_mode_history) | ||||
|  | ||||
|         if lmh in self.config.leader_dictionary: | ||||
|             self.macros_pending.append(self.config.leader_dictionary[lmh].keydown) | ||||
|             self.process_key(self.config.leader_dictionary[lmh], True) | ||||
|  | ||||
|         return self._exit_leader_mode() | ||||
|  | ||||
| @@ -438,15 +238,15 @@ class InternalState: | ||||
|         for key in keys_pressed: | ||||
|             if ( | ||||
|                 self.config.leader_mode == LeaderMode.ENTER_ACTIVE and | ||||
|                 key == Keycodes.Common.KC_ENT | ||||
|                 key == KC.ENT | ||||
|             ): | ||||
|                 self._handle_leader_sequence() | ||||
|                 break | ||||
|             elif key == Keycodes.Common.KC_ESC or key == Keycodes.KMK.KC_GESC: | ||||
|             elif key == KC.ESC or key == KC.GESC: | ||||
|                 # Clean self and turn leader mode off. | ||||
|                 self._exit_leader_mode() | ||||
|                 break | ||||
|             elif key == Keycodes.KMK.KC_LEAD: | ||||
|             elif key == KC.LEAD: | ||||
|                 break | ||||
|             else: | ||||
|                 # Add key if not needing to escape | ||||
|   | ||||
		Reference in New Issue
	
	Block a user