Skip to content

Commit c3d4553

Browse files
committed
add some features from TMK
1 parent cf04472 commit c3d4553

File tree

4 files changed

+484
-0
lines changed

4 files changed

+484
-0
lines changed

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,34 @@ A hand-wired keybaord powered by Python
127127
If you have a different configuration of raws and columns, you must change `ROWS` and `COLS` in the code.
128128
129129
130+
## To be a productive keyboard
131+
As you may notice, this is a 60% keyboard and it lacks a lot of keys (F1~F12, arrow keys).
132+
However we can add [features like TMK's layers and composite keys](https://github.com/tmk/tmk_keyboard/blob/master/tmk_core/doc/keymap.md) to make the small keyboard much more powerful.
133+
Inspired by [Toward a more useful keyboard](https://github.com/jasonrudolph/keyboard), we can optimize the keyboard to keep our fingers at the home row, which may help us being more productive.
134+
135+
Here we introduce one feature which is holding a key down to activate a alternate function.
136+
137+
### Using <kbd>D</kbd> for Navigation
138+
139+
140+
![](img/d-for-navigation.png)
141+
142+
+ <kbd>d</kbd> + <kbd>h</kbd> as <kbd>←</kbd>
143+
+ <kbd>d</kbd> + <kbd>j</kbd> as <kbd>↓</kbd>
144+
+ <kbd>d</kbd> + <kbd>k</kbd> as <kbd>↑</kbd>
145+
+ <kbd>d</kbd> + <kbd>l</kbd> as <kbd>→</kbd>
146+
+ <kbd>d</kbd> + <kbd>u</kbd> as <kbd>PageUp</kbd>
147+
+ <kbd>d</kbd> + <kbd>n</kbd> as <kbd>PageDown</kbd>
148+
149+
To apply the navigation <kbd>d</kbd>, copy `keyboard.py`, `keycodes.py` and `matrix.py` to `CIRCUITPY`, and then modify `code.py` to import the new keyboard
150+
151+
```python
152+
# code.py
153+
154+
from keyboard import main
155+
156+
main()
157+
```
158+
159+
### Next - Using <kbd>;</kbd> as <kbd>Ctrl</kbd>
160+
Todo

keyboard.py

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import time
2+
import usb_hid
3+
4+
import adafruit_ble
5+
from adafruit_ble.advertising import Advertisement
6+
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
7+
from adafruit_ble.services.standard.hid import HIDService
8+
from adafruit_hid.keyboard import keyboard
9+
10+
from keycodes import *
11+
from matrix import Matrix, LAYOUT
12+
13+
14+
___ = TRANSPARENT
15+
L1 = LAYER_TAP(1)
16+
L2D = LAYER_TAP(2, D)
17+
PGUP = PAGEUP
18+
PGDN = PAGEDOWN
19+
20+
KEYMAP = (
21+
# layer 0
22+
LAYOUT(
23+
ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, '-', '=', BACKSPACE,
24+
TAB, Q, W, E, R, T, Y, U, I, O, P, '[', ']', '|',
25+
CAPS, A, S,L2D, F, G, H, J, K, L,';', '"', ENTER,
26+
LSHIFT, Z, X, C, V, B, N, M,',','.','/', RSHIFT,
27+
LCTRL, LGUI, LALT, SPACE, RALT, MENU, L1, RCTRL
28+
),
29+
30+
# layer 1
31+
LAYOUT(
32+
'`', F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, DEL,
33+
___,___, UP,___,___,___,___,___,___,___,___, ___, ___, ___,
34+
___,LEFT,DOWN,RIGHT,___,___,___,___,___,___,___,___, ___,
35+
___,___,___,___,___,___,___,___,___,___,___, ___, ___,
36+
___,___,___, ___, ___, ___, ___, ___
37+
),
38+
39+
# layer 2
40+
LAYOUT(
41+
'`', F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, DEL,
42+
___,___,___,___,___,___,___,PGUP,___,___,___, ___, ___, ___,
43+
___,___,___,___,___,___,LEFT,DOWN,UP,RIGHT,___,___, ___,
44+
___,___,___,___,___,___,PGDN,___,___,___,___, ___, ___,
45+
___,___,___, ___, ___, ___, ___, ___
46+
)
47+
)
48+
49+
50+
class Kbd:
51+
keymap = KEYMAP
52+
53+
def __init__(self):
54+
self.layers = 1
55+
56+
def keycode(self, key):
57+
for layer in range(len(self.keymap) - 1, -1, -1):
58+
if (self.layers >> layer) & 1:
59+
id = ord(self.keymap[layer][key])
60+
if id == ord(TRANSPARENT):
61+
continue
62+
return KEYCODE(id) if id < 128 else id
63+
return 0
64+
65+
def run(self):
66+
hid = HIDService()
67+
advertisement = ProvideServicesAdvertisement(hid)
68+
advertisement.appearance = 961
69+
ble = adafruit_ble.BLERadio()
70+
if ble.connected:
71+
for c in ble.connections:
72+
c.disconnect()
73+
ble.start_advertising(advertisement)
74+
advertising = True
75+
ble_keyboard = Keyboard(hid.devices)
76+
77+
matrix = Matrix()
78+
usb_keyboard = Keyboard(usb_hid.devices)
79+
80+
keys = {}
81+
pending_keys = []
82+
while True:
83+
_, released_keys, new_keys = matrix.scan()
84+
t = time.monotonic_ns()
85+
if released_keys:
86+
print('< {}'.format(released_keys))
87+
for key in released_keys:
88+
keycode = keys[key][0]
89+
dt = (t - keys[key][1]) // 1000000
90+
print('dt({}) = {}'.format(key, dt))
91+
if 0 < keycode and keycode < 0xE8:
92+
usb_keyboard.release(keycode)
93+
if ble.connected:
94+
advertising = False
95+
ble_keyboard.release(keycode)
96+
elif keycode & 0xF000 == 0xF000:
97+
if key in pending_keys:
98+
pending_keys.remove(key)
99+
key = keycode & 0xFF
100+
code = KEYCODE(key)
101+
if dt < 500 and code:
102+
usb_keyboard.press(code)
103+
usb_keyboard.release(code)
104+
if ble.connected:
105+
advertising = False
106+
ble_keyboard.press(code)
107+
ble_keyboard.release(code)
108+
109+
else:
110+
self.layers &= ~(1 << ((keycode >> 8) & 0xF))
111+
print('layers {}'.format(self.layers))
112+
if new_keys:
113+
print('> {}'.format(new_keys))
114+
for key in new_keys:
115+
while pending_keys:
116+
pending_key = pending_keys.pop(0)
117+
pending_keycode = keys[pending_key][0]
118+
if pending_keycode & 0xF000 == 0xF000:
119+
self.layers |= 1 << ((pending_keycode >> 8) & 0xF)
120+
print('layers {}'.format(self.layers))
121+
122+
keycode = self.keycode(key)
123+
keys[key] = (keycode, t)
124+
print('keycode {}'.format(keycode))
125+
126+
if 0 < keycode and keycode < 0xFF:
127+
usb_keyboard.press(keycode)
128+
if ble.connected:
129+
advertising = False
130+
ble_keyboard.press(keycode)
131+
elif keycode & 0xF000 == 0xF000:
132+
# LAYER_TAP
133+
pending_keys.append(key)
134+
elif keycode & 0xF000 == 0xE000:
135+
# LAYER_MODS
136+
pass
137+
elif keycode & 0xF000 == 0xD000:
138+
# MODS_TAP
139+
pass
140+
141+
if not ble.connected and not advertising:
142+
ble.start_advertising(advertisement)
143+
advertising = True
144+
145+
time.sleep(0.01)
146+
147+
148+
def main():
149+
kbd = Kbd()
150+
kbd.run()
151+
152+
153+
if __name__ == '__main__':
154+
main()

0 commit comments

Comments
 (0)