diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 4c2b8cd..0000000 --- a/.gitmodules +++ /dev/null @@ -1,8 +0,0 @@ -[submodule "upy-lib"] - path = vendor/upy-lib - url = https://github.com/kmkfw/micropython-lib.git - ignore = dirty -[submodule "micropython"] - path = vendor/micropython - url = https://github.com/kmkfw/micropython.git - ignore = dirty diff --git a/LICENSE.md b/LICENSE.md index 2fb2e74..ad610ae 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,3 +1,14 @@ +Almost all of KMK is licensed under the GPLv3. There are a couple of +exceptions: + +- `kmk/string.py` is copied directly from + [micropython-lib](https://github.com/micropython/micropython-lib) and is + under the MIT license, copyrighted by the micropython-lib contributors +- Hardware schematics are licensed under individual terms per schematic + +Files/components not listed above or containing its own copyright header in the +file itself are licensed under GPLv3 as follows: + ### GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 diff --git a/Makefile b/Makefile index 9af964a..22a01e9 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ fix-isort: devdeps clean: clean-build-log @echo "===> Cleaning build artifacts" - @rm -rf .submodules .circuitpy-deps .micropython-deps .devdeps build + @rm -rf .devdeps build clean-build-log: @echo "===> Clearing previous .build.log" @@ -57,38 +57,6 @@ powerwash: clean test: lint -.submodules: .gitmodules submodules.toml - @echo "===> Pulling dependencies, this may take several minutes" - @echo "===> Pulling dependencies, this may take several minutes" >> .build.log - @git submodule sync 2>&1 >> .build.log - @git submodule update --init --recursive 2>&1 >> .build.log - @rsync -ah vendor/ build/ - @touch .submodules - -.micropython-deps: .submodules - @echo "===> Building micropython/mpy-cross" - @echo "===> Building micropython/mpy-cross" >> .build.log - @pipenv run $(MAKE) -C build/micropython/mpy-cross 2>&1 >> .build.log - @touch .micropython-deps - -submodules: .submodules -micropython-deps: .micropython-deps - -build/micropython/ports/unix/micropython: micropython-deps build/micropython/ports/unix/modules/.kmk_frozen - @echo "===> Building MicroPython for Unix" - @echo "===> Building MicroPython for Unix" >> .build.log - @pipenv run $(MAKE) -j4 -C build/micropython/ports/unix 2>&1 >> .build.log - -micropython-build-unix: build/micropython/ports/unix/micropython - -build/micropython/ports/unix/modules/.kmk_frozen: upy-freeze.txt submodules.toml - @echo "===> Preparing vendored dependencies for bundling into MicroPython for Unix" - @echo "===> Preparing vendored dependencies for bundling into MicroPython for Unix" >> .build.log - @rm -rf build/micropython/ports/unix/modules/* - @cat upy-freeze.txt | egrep -v '(^#|^\s*$|^\s*\t*#)' | grep MICROPY | cut -d'|' -f2- | \ - xargs -I '{}' rsync -ah {} build/micropython/ports/unix/modules/ - @touch $@ - reset-bootloader: @echo "===> Rebooting your board to bootloader (safe to ignore file not found errors)" @-timeout -k 5s 10s $(PIPENV) run ampy -p /dev/ttyACM0 -d ${AMPY_DELAY} -b ${AMPY_BAUD} run util/bootloader.py @@ -101,8 +69,6 @@ ifdef MOUNTPOINT $(MOUNTPOINT)/kmk/.copied: $(shell find kmk/ -name "*.py" | xargs -0) @echo "===> Copying KMK source folder" @rsync -rh kmk $(MOUNTPOINT)/ - @cat upy-freeze.txt | egrep -v '(^#|^\s*$|^\s*\t*#)' | grep CIRCUITPY | cut -d'|' -f2- | \ - xargs -I '{}' rsync -h {} $(MOUNTPOINT)/ @touch $(MOUNTPOINT)/kmk/.copied @sync diff --git a/README.md b/README.md index 61f9d42..c158c0c 100644 --- a/README.md +++ b/README.md @@ -76,11 +76,10 @@ out the Windows Subsystem for Linux if you're on Windows. ## License, Copyright, and Legal -This project, and all source code within (even if the file is missing headers), -is licensed +Most files in this project are licensed [GPLv3](https://tldrlegal.com/license/gnu-general-public-license-v3-(gpl-3)) - -while the tl;dr is linked, the full license text is included in `LICENSE.md` at -the top of this source tree. +see `LICENSE.md` at the top of this source tree for exceptions and the full +license text. When contributing for the first time, you'll need to sign a Contributor Licensing Agreement which is based on the Free Software Foundation's CLA. The diff --git a/bin/micropython.sh b/bin/micropython.sh deleted file mode 100755 index 154dd23..0000000 --- a/bin/micropython.sh +++ /dev/null @@ -1,6 +0,0 @@ -if [ ! -f build/micropython/ports/unix/micropython ]; then - echo "Run make micropython-build-unix" - exit 1 -fi - -build/micropython/ports/unix/micropython $@ diff --git a/docs/tapdance.md b/docs/tapdance.md new file mode 100644 index 0000000..0f79078 --- /dev/null +++ b/docs/tapdance.md @@ -0,0 +1,61 @@ +# Tap Dance + +Tap dance is a way to allow a single physical key to work as multple logical +keys / actions without using layers. With basic tap dance, you can trigger these +"nested" keys or macros through a series of taps of the physical key within a +given timeout. + +The resulting "logical" action works just like any other key - it can be pressed +and immediately released, or it can be held. For example, let's take a key +`KC.TD(KC.A, KC.B)`. If the tap dance key is tapped and released once quickly, +the letter "a" will be sent. If it is tapped and released twice quickly, the +letter "b" will be sent. If it is tapped once and held, the letter "a" will be +held down until the tap dance key is released. If it is tapped and released once +quickly, then tapped and held (both actions within the timeout window), the +letter "b" will be held down until the tap dance key is released. + +To use this, you may want to define a `tap_time` value in your keyboard +configuration. This is an integer in milliseconds, and defaults to `300`. + +You'll then want to create a sequence of keys using `KC.TD(KC.SOMETHING, +KC.SOMETHING_ELSE, MAYBE_THIS_IS_A_MACRO, WHATEVER_YO)`, and place it in your +keymap somewhere. The only limits on how many keys can go in the sequence are, +theoretically, the amount of RAM your MCU/board has, and how fast you can mash +the physical key. Here's your chance to use all that button-mash video game +experience you've built up over the years. + +**NOTE**: Currently our basic tap dance implementation has some limitations that +are planned to be worked around "eventually", but for now are noteworthy: + +- The behavior of momentary layer switching within a tap dance sequence is + currently "undefined" at best, and will probably crash your keyboard. For now, + we strongly recommend avoiding `KC.MO` (or any other layer switch keys that + use momentary switch behavior - `KC.LM`, `KC.LT`, and `KC.TT`) + +- Super fancy stuff like sending a keypress only when the leader key is released + (perhaps based on how long the leader key was held) is **unsupported** - an + example usecase might be "tap for Home, hold for Shift" + +Here's an example of all this in action: + +```python +# user_keymaps/some_silly_example.py +from kmk.boards.klarank import Firmware +from kmk.keycodes import KC +from kmk.macros.simple import send_string + +keyboard = Firmware() + +keyboard.tap_time = 750 + +EXAMPLE_TD = KC.TD( + KC.A, # Tap once for "a" + KC.B, # Tap twice for "b" + # Tap three times to send a raw string via macro + send_string('macros in a tap dance? I think yes'), + # Tap four times to toggle layer index 1 + KC.TG(1), +) + +keyboard.keymap = [[ ...., EXAMPLE_TD, ....], ....] +``` diff --git a/kmk/firmware.py b/kmk/firmware.py index b7d05d4..aaf8651 100644 --- a/kmk/firmware.py +++ b/kmk/firmware.py @@ -64,6 +64,7 @@ class Firmware: split_offsets = () split_flip = False split_side = None + split_type = None split_master_left = True is_master = None uart = None @@ -78,14 +79,14 @@ class Firmware: def _send_key(self, key): if not getattr(key, 'no_press', None): - self._state.force_keycode_down(key) + self._state.add_key(key) self._send_hid() if not getattr(key, 'no_release', None): - self._state.force_keycode_up(key) + self._state.remove_key(key) self._send_hid() - def _handle_update(self, update): + def _handle_matrix_report(self, update=None): ''' Bulk processing of update code for each cycle :param update: @@ -97,24 +98,6 @@ class Firmware: update[2], ) - if self._state.hid_pending: - self._send_hid() - - if self.debug_enabled: - print('New State: {}'.format(self._state._to_dict())) - - self._state.process_timeouts() - - for key in self._state.pending_keys: - self._send_key(key) - self._state.pending_key_handled() - - if self._state.macro_pending: - for key in self._state.macro_pending(self): - self._send_key(key) - - self._state.resolve_macro() - def _send_to_master(self, update): if self.split_master_left: update[1] += self.split_offsets[update[0]] @@ -189,19 +172,45 @@ class Firmware: print("Firin' lazers. Keyboard is booted.") while True: + state_changed = False + if self.split_type is not None and self._master_half: update = self._receive_from_slave() if update is not None: - self._handle_update(update) + self._handle_matrix_report(update) + state_changed = True update = self.matrix.scan_for_changes() if update is not None: if self._master_half(): - self._handle_update(update) - + self._handle_matrix_report(update) + state_changed = True else: # This keyboard is a slave, and needs to send data to master self._send_to_master(update) + if self._state.hid_pending: + self._send_hid() + + old_timeouts_len = len(self._state.timeouts) + self._state.process_timeouts() + new_timeouts_len = len(self._state.timeouts) + + if old_timeouts_len != new_timeouts_len: + state_changed = True + + if self._state.macros_pending: + # Blindly assume macros are going to change state, which is almost + # always a safe assumption + state_changed = True + for macro in self._state.macros_pending: + for key in macro(self): + self._send_key(key) + + self._state.resolve_macro() + + if self.debug_enabled and state_changed: + print('New State: {}'.format(self._state._to_dict())) + gc.collect() diff --git a/kmk/internal_state.py b/kmk/internal_state.py index 555fe39..5d5d429 100644 --- a/kmk/internal_state.py +++ b/kmk/internal_state.py @@ -1,5 +1,6 @@ from kmk.consts import LeaderMode -from kmk.keycodes import FIRST_KMK_INTERNAL_KEYCODE, Keycodes, RawKeycodes +from kmk.keycodes import (FIRST_KMK_INTERNAL_KEYCODE, Keycodes, RawKeycodes, + TapDanceKeycode) from kmk.kmktime import sleep_ms, ticks_diff, ticks_ms from kmk.util import intify_coordinate @@ -12,8 +13,7 @@ GESC_TRIGGERS = { class InternalState: keys_pressed = set() coord_keys_pressed = {} - pending_keys = [] - macro_pending = None + macros_pending = [] leader_pending = None leader_last_len = 0 hid_pending = False @@ -28,6 +28,9 @@ class InternalState: 'leader': None, } timeouts = {} + tapping = False + tap_dance_counts = {} + tap_side_effects = {} def __init__(self, config): self.config = config @@ -45,6 +48,7 @@ class InternalState: 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): @@ -57,6 +61,9 @@ class InternalState: 'leader_mode_history': self.leader_mode_history, 'leader_mode': self.config.leader_mode, 'start_time': self.start_time, + 'tapping': self.tapping, + 'tap_dance_counts': self.tap_dance_counts, + 'timeouts': self.timeouts, } return ret @@ -76,14 +83,26 @@ class InternalState: return layer_key def set_timeout(self, after_ticks, callback): - timeout_key = ticks_ms() + after_ticks + if after_ticks is False: + # We allow passing False as an implicit "run this on the next process timeouts cycle" + timeout_key = ticks_ms() + else: + timeout_key = ticks_ms() + after_ticks + self.timeouts[timeout_key] = callback return self def process_timeouts(self): + if not self.timeouts: + return self + current_time = ticks_ms() - for k, v in self.timeouts.items(): + # cast this to a tuple to ensure that if a callback itself sets + # timeouts, we do not handle them on the current cycle + timeouts = tuple(self.timeouts.items()) + + for k, v in timeouts: if k <= current_time: v() del self.timeouts[k] @@ -103,45 +122,52 @@ class InternalState: print('No key accessible for col, row: {}, {}'.format(row, col)) return self - if is_pressed: - self.keys_pressed.add(kc_changed) - self.coord_keys_pressed[int_coord] = kc_changed + if self.tapping and not isinstance(kc_changed, TapDanceKeycode): + self._process_tap_dance(kc_changed, is_pressed) else: - self.keys_pressed.discard(kc_changed) - self.keys_pressed.discard(self.coord_keys_pressed[int_coord]) - self.coord_keys_pressed[int_coord] = None + if is_pressed: + self.coord_keys_pressed[int_coord] = kc_changed + self.add_key(kc_changed) + 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 - if kc_changed.code >= FIRST_KMK_INTERNAL_KEYCODE: - self._process_internal_key_event( - kc_changed, - is_pressed, - ) + if self.config.leader_mode % 2 == 1: + self._process_leader_mode() + + return self + + 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 - if self.config.leader_mode % 2 == 1: - self._process_leader_mode() - return self - def force_keycode_up(self, keycode): - self.keys_pressed.discard(keycode) - self.hid_pending = True - return self - - def force_keycode_down(self, keycode): + 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) - self.hid_pending = True + + if keycode.code >= FIRST_KMK_INTERNAL_KEYCODE: + self._process_internal_key_event(keycode, True) + else: + self.hid_pending = True return self - def pending_key_handled(self): - popped = self.pending_keys.pop() - - if self.config.debug_enabled: - print('Popped pending key: {}'.format(popped)) + def tap_key(self, keycode): + self.add_key(keycode) + # On the next cycle, we'll remove the key. This is way more clean than + # the `pending_keys` implementation that we used to rely on in + # firmware.py + self.set_timeout(False, lambda: self.remove_key(keycode)) return self @@ -153,7 +179,7 @@ class InternalState: if self.config.debug_enabled: print('Macro complete!') - self.macro_pending = None + self.macros_pending.pop() return self def _process_internal_key_event(self, changed_key, is_pressed): @@ -214,7 +240,7 @@ class InternalState: ticks_diff(ticks_ms(), self.start_time['lt']) < self.config.tap_time ): self.hid_pending = True - self.pending_keys.append(changed_key.kc) + self.tap_key(changed_key.kc) self._layer_mo(changed_key, is_pressed) self.start_time['lt'] = None @@ -274,10 +300,10 @@ class InternalState: def _kc_macro(self, changed_key, is_pressed): if is_pressed: if changed_key.keyup: - self.macro_pending = changed_key.keyup + self.macros_pending.append(changed_key.keyup) else: if changed_key.keydown: - self.macro_pending = changed_key.keydown + self.macros_pending.append(changed_key.keydown) return self @@ -318,6 +344,68 @@ class InternalState: 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 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. + for k, v in self.tap_dance_counts.items(): + if v: + self._end_tap_dance(k) + + return self + + if ( + changed_key not in self.tap_dance_counts or + not self.tap_dance_counts[changed_key] + ): + self.tap_dance_counts[changed_key] = 1 + self.set_timeout(self.config.tap_time, lambda: self._end_tap_dance(changed_key)) + self.tapping = True + else: + self.tap_dance_counts[changed_key] += 1 + + if changed_key not in self.tap_side_effects: + self.tap_side_effects[changed_key] = None + else: + if ( + self.tap_side_effects[changed_key] is not None or + self.tap_dance_counts[changed_key] == len(changed_key.codes) + ): + self._end_tap_dance(changed_key) + + return self + + def _end_tap_dance(self, td_key): + v = self.tap_dance_counts[td_key] - 1 + + if v >= 0: + if td_key in self.keys_pressed: + key_to_press = td_key.codes[v] + self.add_key(key_to_press) + self.tap_side_effects[td_key] = key_to_press + self.hid_pending = True + else: + if self.tap_side_effects[td_key]: + self.remove_key(self.tap_side_effects[td_key]) + self.tap_side_effects[td_key] = None + self.hid_pending = True + self._cleanup_tap_dance(td_key) + else: + self.tap_key(td_key.codes[v]) + self._cleanup_tap_dance(td_key) + + return self + + def _cleanup_tap_dance(self, td_key): + self.tap_dance_counts[td_key] = 0 + self.tapping = any(count > 0 for count in self.tap_dance_counts.values()) + return self + def _begin_leader_mode(self): if self.config.leader_mode % 2 == 0: self.keys_pressed.discard(Keycodes.KMK.KC_LEAD) @@ -333,7 +421,7 @@ class InternalState: lmh = tuple(self.leader_mode_history) if lmh in self.config.leader_dictionary: - self.macro_pending = self.config.leader_dictionary[lmh].keydown + self.macros_pending.append(self.config.leader_dictionary[lmh].keydown) return self._exit_leader_mode() diff --git a/kmk/keycodes.py b/kmk/keycodes.py index b0dea09..55d4443 100644 --- a/kmk/keycodes.py +++ b/kmk/keycodes.py @@ -80,6 +80,7 @@ class RawKeycodes: KC_MACRO = 1110 KC_MACRO_SLEEP_MS = 1111 + KC_TAP_DANCE = 1113 # These shouldn't have all the fancy shenanigans Keycode allows @@ -184,6 +185,13 @@ class Macro: return self.keyup() if self.keyup else None +class TapDanceKeycode: + code = RawKeycodes.KC_TAP_DANCE + + def __init__(self, *codes): + self.codes = codes + + class KeycodeCategory(type): @classmethod def to_dict(cls): @@ -364,7 +372,7 @@ class ShiftedKeycodes(KeycodeCategory): KC_DOUBLE_QUOTE = KC_DQUO = KC_DQT = Modifiers.KC_LSHIFT(Common.KC_QUOTE) KC_LEFT_ANGLE_BRACKET = KC_LABK = Modifiers.KC_LSHIFT(Common.KC_COMMA) KC_RIGHT_ANGLE_BRACKET = KC_RABK = Modifiers.KC_LSHIFT(Common.KC_DOT) - KC_QUESTION = KC_QUES = Modifiers.KC_LSHIFT(Common.KC_DOT) + KC_QUESTION = KC_QUES = Modifiers.KC_LSHIFT(Common.KC_SLSH) class FunctionKeys(KeycodeCategory): @@ -551,6 +559,13 @@ class KMK(KeycodeCategory): def KC_MACRO_SLEEP_MS(ms): return MacroSleepKeycode(RawKeycodes.KC_MACRO_SLEEP_MS, ms) + @staticmethod + def KC_TAP_DANCE(*args): + return TapDanceKeycode(*args) + + +KMK.KC_TD = KMK.KC_TAP_DANCE + class Layers(KeycodeCategory): @staticmethod diff --git a/kmk/macros/simple.py b/kmk/macros/simple.py index 9fb1734..2bbf2d0 100644 --- a/kmk/macros/simple.py +++ b/kmk/macros/simple.py @@ -1,6 +1,5 @@ -import string - from kmk.keycodes import Keycodes, Macro, char_lookup, lookup_kc_with_cache +from kmk.string import ascii_letters, digits def simple_key_sequence(seq): @@ -18,7 +17,7 @@ def send_string(message): if char in char_lookup: kc = char_lookup[char] - elif char in string.ascii_letters + string.digits: + elif char in ascii_letters + digits: kc = lookup_kc_with_cache(char) if char.isupper(): diff --git a/kmk/string.py b/kmk/string.py new file mode 100644 index 0000000..bab4454 --- /dev/null +++ b/kmk/string.py @@ -0,0 +1,51 @@ +# This file copied from micropython-lib +# https://github.com/micropython/micropython-lib +# +# The MIT License (MIT) +# +# Copyright (c) 2013, 2014 micropython-lib contributors +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# Some strings for ctype-style character classification +whitespace = ' \t\n\r\v\f' +ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz' +ascii_uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +ascii_letters = ascii_lowercase + ascii_uppercase +digits = '0123456789' +hexdigits = digits + 'abcdef' + 'ABCDEF' +octdigits = '01234567' +punctuation = """!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~""" +printable = digits + ascii_letters + punctuation + whitespace + + +def translate(s, map): + import io + sb = io.StringIO() + for c in s: + v = ord(c) + if v in map: + v = map[v] + if isinstance(v, int): + sb.write(chr(v)) + elif v is not None: + sb.write(v) + else: + sb.write(c) + return sb.getvalue() diff --git a/main.py b/main.py deleted file mode 100644 index a29d7d9..0000000 --- a/main.py +++ /dev/null @@ -1,3 +0,0 @@ -from kmk_keyboard import main - -main() diff --git a/submodules.toml b/submodules.toml deleted file mode 100644 index 79e0cde..0000000 --- a/submodules.toml +++ /dev/null @@ -1,3 +0,0 @@ -[submodules] -"vendor/micropython" = "65a49fa" -"vendor/upy-lib" = "451b1c0" diff --git a/upy-freeze.txt b/upy-freeze.txt deleted file mode 100644 index 1e1b44a..0000000 --- a/upy-freeze.txt +++ /dev/null @@ -1,4 +0,0 @@ -# CircuitPython provides collections, don't overwrite it -MICROPY|vendor/upy-lib/collections/collections - -MICROPYCIRCUITPY|vendor/upy-lib/string/string.py diff --git a/upy-unix-stubs/digitalio.py b/upy-unix-stubs/digitalio.py deleted file mode 100644 index b293fa2..0000000 --- a/upy-unix-stubs/digitalio.py +++ /dev/null @@ -1,3 +0,0 @@ -class DigitalInOut: - def __init__(self, *args, **kwargs): - pass diff --git a/upy-unix-stubs/machine/__init__.py b/upy-unix-stubs/machine/__init__.py deleted file mode 100644 index 6199bc0..0000000 --- a/upy-unix-stubs/machine/__init__.py +++ /dev/null @@ -1,38 +0,0 @@ -class Anything: - ''' - A stub class which will repr as a provided name - ''' - def __init__(self, name): - self.name = name - - def __call__(self, *args, **kwargs): - return self - - def __repr__(self): - return 'Anything<{}>'.format(self.name) - - def init(self, *args, **kwargs): - pass - - @property - def value(self): - return False - - -class Passthrough: - def __getattr__(self, attr): - return Anything(attr) - - -class Pin: - board = Passthrough() - IN = 'IN' - OUT = 'OUT' - PULL_DOWN = 'PULL_DOWN' - PULL_UP = 'PULL_UP' - - def __call__(self, *args, **kwargs): - return self.board - - def __getattr__(self, attr): - return getattr(self.board, attr) diff --git a/upy-unix-stubs/pyb/USB_HID.py b/upy-unix-stubs/pyb/USB_HID.py deleted file mode 100644 index e69de29..0000000 diff --git a/upy-unix-stubs/pyb/__init__.py b/upy-unix-stubs/pyb/__init__.py deleted file mode 100644 index 9b894c1..0000000 --- a/upy-unix-stubs/pyb/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -try: - from collections import namedtuple -except ImportError: - from ucollections import namedtuple - -HIDMode = namedtuple('HIDMode', ( - 'subclass', - 'protocol', - 'max_packet_length', - 'polling_interval', - 'report_descriptor', -)) - -hid_keyboard = HIDMode(0, 0, 0, 0, bytearray(0)) diff --git a/upy-unix-stubs/pyb/delay.py b/upy-unix-stubs/pyb/delay.py deleted file mode 100644 index e69de29..0000000 diff --git a/upy-unix-stubs/usb_hid.py b/upy-unix-stubs/usb_hid.py deleted file mode 100644 index 1b2034a..0000000 --- a/upy-unix-stubs/usb_hid.py +++ /dev/null @@ -1 +0,0 @@ -devices = [] diff --git a/user_keymaps/klardotsh/klarank_featherm4.py b/user_keymaps/klardotsh/klarank_featherm4.py index 2cb1843..cff7814 100644 --- a/user_keymaps/klardotsh/klarank_featherm4.py +++ b/user_keymaps/klardotsh/klarank_featherm4.py @@ -9,9 +9,7 @@ keyboard = Firmware() keyboard.debug_enabled = True keyboard.unicode_mode = UnicodeModes.LINUX - -_______ = KC.TRNS -xxxxxxx = KC.NO +keyboard.tap_time = 750 emoticons = cuss({ # Emojis @@ -56,6 +54,16 @@ keyboard.leader_dictionary = { glds('cel'): emoticons.CELEBRATORY_GLITTER, } +_______ = KC.TRNS +xxxxxxx = KC.NO +HELLA_TD = KC.TD( + KC.A, + KC.B, + send_string('macros in a tap dance? I think yes'), + KC.TG(1), +) + + keyboard.keymap = [ [ [KC.GESC, KC.QUOT, KC.COMM, KC.DOT, KC.P, KC.Y, KC.F, KC.G, KC.C, KC.R, KC.L, KC.BSPC], @@ -79,10 +87,10 @@ keyboard.keymap = [ ], [ - [KC.GRV, KC.EXLM, KC.AT, KC.HASH, KC.DLR, KC.PERC, KC.CIRC, KC.AMPR, KC.ASTR, KC.LPRN, KC.RPRN, KC.SLSH], - [KC.TAB, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, KC.MINS], - [KC.LGUI, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx], - [KC.LCTL, KC.DBG, xxxxxxx, xxxxxxx, _______, _______, xxxxxxx, xxxxxxx, KC.MUTE, KC.VOLD, KC.VOLU, xxxxxxx], + [KC.GRV, KC.EXLM, KC.AT, KC.HASH, KC.DLR, KC.PERC, KC.CIRC, KC.AMPR, KC.ASTR, KC.LPRN, KC.RPRN, KC.SLSH], + [KC.TAB, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, KC.MINS], + [KC.LGUI, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx], + [KC.LCTL, KC.DBG, HELLA_TD, xxxxxxx, _______, _______, xxxxxxx, xxxxxxx, KC.MUTE, KC.VOLD, KC.VOLU, xxxxxxx], ], ] diff --git a/vendor/micropython b/vendor/micropython deleted file mode 160000 index 65a49fa..0000000 --- a/vendor/micropython +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 65a49fa3c80e7432ccb35b9f34e5c4c0a62b933d diff --git a/vendor/upy-lib b/vendor/upy-lib deleted file mode 160000 index 451b1c0..0000000 --- a/vendor/upy-lib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 451b1c07567de85062ef35b672b2101647285e9a