diff --git a/kmk/common/macros/rotary_encoder.py b/kmk/common/macros/rotary_encoder.py new file mode 100644 index 0000000..ca6361d --- /dev/null +++ b/kmk/common/macros/rotary_encoder.py @@ -0,0 +1,76 @@ +import math + +from kmk.common.event_defs import (hid_report_event, keycode_down_event, + keycode_up_event) +from kmk.common.keycodes import Media +from kmk.common.rotary_encoder import RotaryEncoder + +VAL_FALSE = False + 1 +VAL_NONE = True + 2 +VAL_TRUE = True + 1 +VOL_UP_PRESS = keycode_down_event(Media.KC_AUDIO_VOL_UP) +VOL_UP_RELEASE = keycode_up_event(Media.KC_AUDIO_VOL_UP) +VOL_DOWN_PRESS = keycode_down_event(Media.KC_AUDIO_VOL_DOWN) +VOL_DOWN_RELEASE = keycode_up_event(Media.KC_AUDIO_VOL_DOWN) + + +class RotaryEncoderMacro: + def __init__(self, pos_pin, neg_pin, slop_history=24, slop_threshold=0.7): + self.encoder = RotaryEncoder(pos_pin, neg_pin) + self.max_history = slop_history + self.history = bytearray(slop_history) + self.history_idx = 0 + self.history_threshold = math.floor(slop_threshold * slop_history) + + def scan(self): + # Anti-slop logic + self.history[self.history_idx] = 0 + + reading = self.encoder.direction() + self.history[self.history_idx] = VAL_NONE if reading is None else reading + 1 + + self.history_idx += 1 + + if self.history_idx >= self.max_history: + self.history_idx = 0 + + nones = 0 + trues = 0 + falses = 0 + + for val in self.history: + if val == VAL_NONE: + nones += 1 + elif val == VAL_TRUE: + trues += 1 + elif val == VAL_FALSE: + falses += 1 + + if nones >= self.history_threshold: + return None + + if trues >= self.history_threshold: + return self.on_increase() + + if falses >= self.history_threshold: + return self.on_decrease() + + def on_decrease(self): + pass + + def on_increase(self): + pass + + +class VolumeRotaryEncoder(RotaryEncoderMacro): + def on_decrease(self): + yield VOL_DOWN_PRESS + yield hid_report_event + yield VOL_DOWN_RELEASE + yield hid_report_event + + def on_increase(self): + yield VOL_UP_PRESS + yield hid_report_event + yield VOL_UP_RELEASE + yield hid_report_event diff --git a/kmk/firmware.py b/kmk/firmware.py index 706b05c..7aaddb6 100644 --- a/kmk/firmware.py +++ b/kmk/firmware.py @@ -19,6 +19,9 @@ class Firmware: logger = logging.getLogger(__name__) logger.setLevel(log_level) + import kmk_keyboard_user + self.encoders = getattr(kmk_keyboard_user, 'encoders', []) + self.hydrated = False self.store = Store(kmk_reducer, log_level=log_level) @@ -58,3 +61,10 @@ class Firmware: if update: self.store.dispatch(update) + + for encoder in self.encoders: + eupdate = encoder.scan() + + if eupdate: + for event in eupdate: + self.store.dispatch(event) diff --git a/upy-unix-stubs/machine/__init__.py b/upy-unix-stubs/machine/__init__.py index 20f4ebf..6199bc0 100644 --- a/upy-unix-stubs/machine/__init__.py +++ b/upy-unix-stubs/machine/__init__.py @@ -11,9 +11,12 @@ class Anything: def __repr__(self): return 'Anything<{}>'.format(self.name) + def init(self, *args, **kwargs): + pass + @property def value(self): - return None + return False class Passthrough: @@ -23,6 +26,10 @@ class Passthrough: class Pin: board = Passthrough() + IN = 'IN' + OUT = 'OUT' + PULL_DOWN = 'PULL_DOWN' + PULL_UP = 'PULL_UP' def __call__(self, *args, **kwargs): return self.board diff --git a/user_keymaps/klardotsh/itsybitsy_m4_express/threethree.py b/user_keymaps/klardotsh/itsybitsy_m4_express/threethree.py index 74f945e..148a2f5 100644 --- a/user_keymaps/klardotsh/itsybitsy_m4_express/threethree.py +++ b/user_keymaps/klardotsh/itsybitsy_m4_express/threethree.py @@ -1,5 +1,6 @@ from kmk.common.consts import DiodeOrientation, UnicodeModes from kmk.common.keycodes import KC +from kmk.common.macros.rotary_encoder import VolumeRotaryEncoder from kmk.common.macros.simple import send_string, simple_key_sequence from kmk.common.macros.unicode import unicode_string_sequence from kmk.common.pins import Pin as P @@ -15,6 +16,10 @@ rows = (P.D12, P.D11, P.D10) diode_orientation = DiodeOrientation.COLUMNS unicode_mode = UnicodeModes.LINUX +encoders = [ + VolumeRotaryEncoder(P.A3, P.A2), +] + emoticons = AttrDict({ # Emojis 'BEER': r'🍺',