-
Notifications
You must be signed in to change notification settings - Fork 487
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[do not merge] Add nullbitsco tidbit board with pin mapping; doc updates; hex composer #915
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
https://nullbits.co/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
https://nullbits.co/tidbit/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import board | ||
|
||
from kmk.kmk_keyboard import KMKKeyboard as _KMKKeyboard | ||
from kmk.quickpin.pro_micro.bitc_promicro import pinout as pins | ||
|
||
from kmk.scanners import DiodeOrientation | ||
from kmk.modules.encoder import EncoderHandler | ||
|
||
|
||
encoder_pinout = [ | ||
(pins[13], pins[14], None), # enc 0, button mapped in matrix | ||
(pins[10], pins[11], None), # enc 1 (optional) | ||
(pins[5], pins[4], None), # enc 2 (optional) | ||
(pins[0], pins[1], None), # enc 3 (optional) | ||
] | ||
|
||
|
||
class KMKKeyboard(_KMKKeyboard): | ||
"""" | ||
Create a nullbits tidbit keyboard. | ||
optional constructor arguments: | ||
|
||
active_encoders=[0, 2] to list installed encoder positions (first=0) | ||
then declare keyboard.encoders.map = [(KC.<left> , KC.<right>, None), (...)] | ||
enable_rgb=False (default True) to add rgb module (requires neopixel.py) | ||
landscape_layout=True to orient USB port top right rather than left (default) | ||
""" | ||
# led = digitalio.DigitalInOut(board.D21) | ||
# led.direction = digitalio.Direction.OUTPUT | ||
# led.value = False | ||
row_pins = ( | ||
pins[15], | ||
pins[9], | ||
pins[8], | ||
pins[7], | ||
pins[6], | ||
) | ||
col_pins = ( | ||
pins[19], | ||
pins[18], | ||
pins[17], | ||
pins[16], | ||
) | ||
pixel_pin = pins[12] | ||
diode_orientation = DiodeOrientation.ROW2COL | ||
i2c = board.I2C #TODO ?? | ||
|
||
def __init__(self, active_encoders=[], landscape_layout=False): | ||
super().__init__() | ||
|
||
if landscape_layout: | ||
self.coord_mapping = [ | ||
row * len(self.col_pins) + col | ||
for col in range(len(self.col_pins)) | ||
for row in reversed(range(len(self.row_pins))) | ||
] | ||
|
||
if active_encoders: | ||
self.encoders = EncoderHandler() | ||
self.encoders.pins = tuple([encoder_pinout[i] for i in active_encoders]) | ||
self.modules.append(self.encoders) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from kb import KMKKeyboard | ||
from kmk.keys import KC | ||
|
||
# add active_encoders=[0, 2] to constructor if first and third encoders installed | ||
keyboard = KMKKeyboard() | ||
|
||
XXXXX = KC.NO | ||
|
||
keyboard.keymap = [ | ||
[ | ||
XXXXX, KC.PSLS, KC_PAST, KC_PMNS, | ||
KC_P7, KC_P8, KC_P9, KC_PPLS, | ||
KC_P4, KC_P5, KC_P6, KC_PPLS, | ||
KC_P1, KC_P2, KC_P3, KC_PENT, | ||
KC_P0, KC_P0, KC_PDOT, KC_PENT, | ||
] | ||
] | ||
|
||
if __name__ == '__main__': | ||
keyboard.go() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
from kb import KMKKeyboard | ||
from kmk.keys import KC, make_key | ||
from kmk.modules.holdtap import HoldTap | ||
from kmk.modules.layers import Layers | ||
from kmk.modules.hex_compose import HexCompose | ||
from kmk.modules.tapdance import TapDance | ||
from kmk.modules.oneshot import OneShot | ||
from kmk.extensions.rgb import RGB, AnimationModes | ||
from kmk.consts import UnicodeMode | ||
|
||
from kmk.handlers.sequences import unicode_string_sequence | ||
|
||
keyboard = KMKKeyboard(active_encoders=[0], landscape_layout=True) | ||
|
||
keyboard.unicode_mode = UnicodeMode.RALT | ||
|
||
keyboard.modules += [ | ||
Layers(), | ||
OneShot(), | ||
HoldTap(), | ||
TapDance(), | ||
HexCompose(encoding='utf8') | ||
] | ||
|
||
rgb = RGB( | ||
pixel_pin=keyboard.pixel_pin, | ||
num_pixels=8, | ||
animation_mode=AnimationModes.BREATHING, | ||
animation_speed=3, | ||
breathe_center=2, | ||
) | ||
keyboard.extensions.append(rgb) | ||
|
||
|
||
def set_backlight(hsv): | ||
rgb.hue, rgb.sat, rgb.val = hsv | ||
|
||
|
||
XXXXX = KC.NO | ||
_____ = KC.TRANSPARENT | ||
|
||
SPC_ENTER = KC.HT(KC.SPACE, KC.ENTER) | ||
SHFT_CTL = KC.TD(KC.LSHIFT, KC.LCTL) | ||
|
||
OS_NUM = KC.OS(KC.MO(2), tap_time=None) | ||
OS_ALPHA = KC.OS(KC.MO(4), tap_time=None) | ||
OS_SYM = KC.OS(KC.MO(6), tap_time=None) | ||
|
||
TO_HEX = KC.TO(0) | ||
TO_NUM = KC.TO(2) | ||
TO_ALPHA = KC.TO(4) | ||
|
||
colors = dict( | ||
hex=(180,255,50), | ||
num=(265,255,50), | ||
alpha=(95,255,50) | ||
) | ||
set_backlight(colors['hex']) | ||
TO_HEX.after_press_handler(lambda *_: set_backlight(colors['hex'])) | ||
TO_NUM.after_press_handler(lambda *_: set_backlight(colors['num'])) | ||
TO_ALPHA.after_press_handler(lambda *_: set_backlight(colors['alpha'])) | ||
|
||
# encoder direction does left/right or up/down with alt | ||
keyboard.encoders.map = [ | ||
[(KC.LEFT, KC.RIGHT, XXXXX)], | ||
[(KC.UP, KC.DOWN, XXXXX)], | ||
] * 4 | ||
|
||
# encoder button cycles modes (hex, numpad, alpha) | ||
keyboard.keymap = [ | ||
# ----------------------------------------------------------- | ||
# 0: hex | ||
[ | ||
KC.HEX7, KC.HEX8, KC.HEX9, TO_NUM, XXXXX, | ||
KC.HEX4, KC.HEX5, KC.HEX6, KC.HEXA, KC.HEXB, | ||
KC.HEX1, KC.HEX2, KC.HEX3, KC.HEXC, KC.HEXD, | ||
KC.LT(1, OS_SYM), KC.HEX0, SPC_ENTER, KC.HEXE, KC.HEXF, | ||
], | ||
# 1: hex alt | ||
[ | ||
XXXXX, XXXXX, XXXXX, XXXXX, XXXXX, | ||
XXXXX, XXXXX, XXXXX, OS_ALPHA, XXXXX, | ||
XXXXX, XXXXX, XXXXX, XXXXX, XXXXX, | ||
XXXXX, OS_NUM, XXXXX, XXXXX, KC.BSPC | ||
], | ||
# ----------------------------------------------------------- | ||
# 2: numpad | ||
[ | ||
KC.N7, KC.N8, KC.N9, TO_ALPHA, XXXXX, | ||
KC.N4, KC.N5, KC.N6, KC.SLSH, KC.ASTR, | ||
KC.N1, KC.N2, KC.N3, KC.MINUS, KC.PLUS, | ||
KC.LT(3, OS_SYM), KC.N0, SPC_ENTER, KC.EQUAL, KC.BSPC, | ||
], | ||
# 3: numpad alt | ||
[ | ||
KC.HOME, KC.UP, KC.PGUP, XXXXX, XXXXX, | ||
KC.LEFT, KC.COMMA, KC.RIGHT, OS_ALPHA, XXXXX, | ||
KC.END, KC.DOWN, KC.PGDN, XXXXX, XXXXX, | ||
XXXXX, KC.DOT, KC.TAB, XXXXX, KC.ESC, | ||
], | ||
# ----------------------------------------------------------- | ||
# 4: alpha | ||
[ | ||
KC.S, KC.T, KC.U, TO_HEX, XXXXX, | ||
KC.I, KC.L, KC.N, KC.O, KC.R, | ||
KC.A, KC.C, KC.D, KC.E, KC.H, | ||
KC.LT(5, OS_SYM), SHFT_CTL, SPC_ENTER, KC.COMM, KC.BSPC, | ||
], | ||
# 5: alpha alt | ||
[ | ||
KC.X, KC.Y, KC.Z, XXXXX, XXXXX, | ||
KC.M, KC.P, KC.Q, KC.V, KC.W, | ||
KC.B, KC.F, KC.G, KC.J, KC.K, | ||
XXXXX, OS_NUM, KC.TAB, KC.DOT, KC.ESC, | ||
], | ||
# ----------------------------------------------------------- | ||
# 6: symbols | ||
[ | ||
KC.QUOT, KC.LPRN, KC.RPRN, XXXXX, XXXXX, | ||
KC.DLR, KC.PERC, KC.AMPR, KC.LBRC, KC.RBRC, | ||
KC.EXLM, KC.DQT, KC.HASH, KC.SCLN, KC.EQUAL, | ||
KC.MO(7), KC.SLSH, SPC_ENTER, KC.COMM, KC.DOT, | ||
], | ||
# 7: symbols alt | ||
[ | ||
KC.GRV, KC.ASTR, KC.UNDS, XXXXX, XXXXX, | ||
KC.BSLS, KC.PIPE, KC.CIRC, KC.LCBR, KC.RCBR, | ||
KC.TILD, KC.AT, KC.MINUS, KC.COLN, KC.PLUS, | ||
XXXXX, KC.QUES, KC.TAB, KC.LABK, KC.RABK, | ||
], | ||
] | ||
|
||
|
||
if __name__ == '__main__': | ||
keyboard.go() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
from kmk.modules import Module | ||
from kmk.keys import KC, make_key | ||
from kmk.handlers.sequences import unicode_string_sequence | ||
|
||
|
||
_ascii7_keys = [] | ||
for c in range(64, 96): | ||
_ascii7_keys.append(KC.LCTRL(KC.get(chr(c)))) | ||
for c in range(32, 127): | ||
k = KC.get(chr(c)) | ||
_ascii7_keys.append(KC.LSHIFT(k) if 65 <= c <= 90 else k) | ||
_ascii7_keys.append(KC.DEL) | ||
|
||
assert len(_ascii7_keys) == 128, "Failed to enumerate 7-bit ascii keys" | ||
|
||
|
||
def _utf8_length(first_byte): | ||
# utf8 encodes length in first byte see https://en.wikipedia.org/wiki/UTF-8 | ||
length = 0 | ||
if first_byte & 0x80 == 0: # 0xxx xxxx | ||
length = 1 | ||
elif first_byte & 0xe0 == 0xc0: # 110x xxxx | ||
length = 2 | ||
elif first_byte & 0xf0 == 0xe0: # 1110 xxxx | ||
length = 3 | ||
elif first_byte & 0xf8 == 0xf0: # 1111 0xxx | ||
length = 4 | ||
return length or None | ||
|
||
|
||
class HexCompose(Module): | ||
def __init__(self, encoding='utf8'): | ||
self.encoding = encoding | ||
self._hex_keys = [ | ||
make_key( | ||
names=(f'HEX{digit:x}'.upper(), ), | ||
meta=digit, | ||
) | ||
for digit in range(16) | ||
] | ||
self.reset() | ||
|
||
def reset(self): | ||
self._bytes_needed = 1 # ascii always needs 1, uft8 sets dynamically | ||
self._hi_nibble = None # two hex digits => one byte | ||
self._bytes = b'' | ||
|
||
def during_bootup(self, keyboard): | ||
self.reset() | ||
|
||
def before_matrix_scan(self, keyboard): | ||
return | ||
|
||
def after_matrix_scan(self, keyboard): | ||
return | ||
|
||
def before_hid_send(self, keyboard): | ||
return | ||
|
||
def after_hid_send(self, keyboard): | ||
return | ||
|
||
def on_powersave_enable(self, keyboard): | ||
return | ||
|
||
def on_powersave_disable(self, keyboard): | ||
return | ||
|
||
def process_key(self, keyboard, key, is_pressed, int_coord): | ||
if key not in self._hex_keys: | ||
self.reset() | ||
return key | ||
elif not is_pressed: | ||
return None | ||
|
||
digit = key.meta | ||
print("HexCompose: got hex key", digit) | ||
|
||
# half way thru a byte? | ||
if self._hi_nibble is None: | ||
self._hi_nibble = digit << 4 | ||
return None | ||
|
||
# otherwise add a byte | ||
self._bytes += bytes([self._hi_nibble + digit]) | ||
self._hi_nibble = None | ||
|
||
# validate length and continuation for utf-8 | ||
if self.encoding == 'utf8': | ||
if len(self._bytes) == 1: | ||
self._bytes_needed = _utf8_length(self._bytes[0]) | ||
# valid starting byte? | ||
if not self._bytes_needed: | ||
print(f'HexCompose: invalid utf-8 length coding from {self._bytes}') | ||
self.reset() | ||
return None | ||
else: | ||
# valid continuation byte? | ||
if self._bytes[-1] & 0xc0 != 0x80: | ||
print(f'HexCompose: invalid utf-8 continuation in {self._bytes}') | ||
self.reset() | ||
return None | ||
|
||
if len(self._bytes) != self._bytes_needed: | ||
return None | ||
|
||
print('HexCompose: completed bytes', self._bytes) | ||
character = self._bytes.decode(self.encoding)[0] | ||
c = ord(character) | ||
if c < 128: | ||
composed_key = _ascii7_keys[c] | ||
print('HexCompose: sending ascii7', composed_key) | ||
else: | ||
composed_key = unicode_string_sequence(character) | ||
print('HexCompose: sending unicode for', character, composed_key) | ||
|
||
self.reset() | ||
|
||
return composed_key |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These will all need to be converted from QMK syntax (underscore) to KMK (dot):