Skip to content

Commit 5c661fa

Browse files
committed
Add support for keypad pipe and backslash. make pylint compliant.
1 parent 97befbc commit 5c661fa

2 files changed

Lines changed: 80 additions & 44 deletions

File tree

CircuitPython_NeXT_Keyboard_RP2040/code.py

Lines changed: 72 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@
55
import rp2pio
66
import usb_hid
77
from adafruit_hid.consumer_control import ConsumerControl
8-
from adafruit_hid.consumer_control_code import ConsumerControlCode
98
from adafruit_hid.keyboard import Keyboard
109
from adafruit_pioasm import Program
1110
from adafruit_ticks import ticks_add, ticks_less, ticks_ms
1211

13-
from next_keycode import cc_value, is_cc, next_modifiers, next_scancodes
12+
from next_keycode import (
13+
cc_value,
14+
is_cc,
15+
next_modifiers,
16+
next_scancodes,
17+
shifted_codes,
18+
shift_modifiers,
19+
)
1420

1521
NEXT_SERIAL_BUS_FREQUENCY = (
1622
18958 # 455kHz/24 https://journal.spencerwnelson.com/entries/nextkb.html
@@ -19,18 +25,19 @@
1925
pio_program = Program(
2026
"""
2127
top:
28+
set pins, 1
2229
pull block ; wait for send request
2330
out x, 1 ; trigger receive?
2431
out y, 7 ; get count of bits to transmit (minus 1)
2532
26-
set pins, 1
27-
bitloop:
33+
bitloop:
2834
out pins, 1 [7] ; send next bit
2935
jmp y--, bitloop [7] ; loop if bits left to send
3036
3137
set pins, 1 ; idle the bus after last bit
3238
jmp !x, top ; to top if no scancode expected
3339
40+
set pins, 1 ; mark bus as idle so keyboard will send
3441
set y, 19 ; 20 bits to receive
3542
3643
wait 0, pin 0 [7] ; wait for falling edge plus half bit time
@@ -42,6 +49,7 @@
4249
"""
4350
)
4451

52+
4553
def pack_message(bitcount, data, trigger_receive=False):
4654
if bitcount > 24:
4755
raise ValueError("too many bits in message")
@@ -76,7 +84,7 @@ def is_make(report):
7684

7785

7886
def is_mod_report(report):
79-
return not (report & 1)
87+
return not report & 1
8088

8189

8290
# keycode bits are backwards compared to other information sources
@@ -107,64 +115,85 @@ def modifiers(report):
107115
**pio_program.pio_kwargs,
108116
)
109117

118+
110119
class KeyboardHandler:
111120
def __init__(self):
112121
self.old_modifiers = 0
113122
self.cc = ConsumerControl(usb_hid.devices)
114123
self.kbd = Keyboard(usb_hid.devices)
115124

116125
def set_key_state(self, key, state):
117-
print("set_key_state", key, state)
118126
if state:
119-
self.kbd.press(key)
127+
if isinstance(key, tuple):
128+
old_report_modifier = self.kbd.report_modifier[0]
129+
self.kbd.report_modifier[0] = 0
130+
self.kbd.press(*key)
131+
self.kbd.release_all()
132+
self.kbd.report_modifier[0] = old_report_modifier
133+
else:
134+
self.kbd.press(key)
120135
else:
121-
self.kbd.release(key)
136+
if isinstance(key, tuple):
137+
pass
138+
else:
139+
self.kbd.release(key)
122140

123-
def handle_report(self, value):
124-
if value == 1536:
141+
def handle_report(self, report_value):
142+
if report_value == 1536: # the "nothing happened" report
125143
return
126144

127-
if is_mod_report(value):
128-
mods = modifiers(value)
129-
changes = self.old_modifiers ^ mods
130-
self.old_modifiers = mods
131-
for i in range(7):
132-
bit = 1 << i
133-
if changes & bit: # Modifier key pressed or released
134-
self.set_key_state(next_modifiers[i], mods & bit)
135-
else:
136-
code = next_scancodes.get(keycode(value))
137-
make = is_make(value)
138-
if code:
139-
if is_cc(code):
140-
if make:
141-
self.cc.send(cc_value(code))
142-
else:
143-
self.set_key_state(code, make)
145+
# Handle modifier changes
146+
mods = modifiers(report_value)
147+
changes = self.old_modifiers ^ mods
148+
self.old_modifiers = mods
149+
for i in range(7):
150+
bit = 1 << i
151+
if changes & bit: # Modifier key pressed or released
152+
self.set_key_state(next_modifiers[i], mods & bit)
153+
154+
# Handle key press/release
155+
code = next_scancodes.get(keycode(report_value))
156+
if mods & shift_modifiers:
157+
code = shifted_codes.get(keycode(report_value), code)
158+
make = is_make(report_value)
159+
if code:
160+
if is_cc(code):
161+
if make:
162+
self.cc.send(cc_value(code))
163+
else:
164+
self.set_key_state(code, make)
144165

145166

146167
handler = KeyboardHandler()
147168

148169
recv_buf = array.array("I", [0])
149170

150-
sm.write(RESET)
151171
time.sleep(0.1)
152-
sm.write(set_leds(0))
172+
sm.write(RESET)
153173
time.sleep(0.1)
154174

175+
for _ in range(4):
176+
sm.write(set_leds(3))
177+
time.sleep(0.1)
178+
sm.write(set_leds(0))
179+
time.sleep(0.1)
180+
155181
print("Keyboard ready!")
156182

157-
while True:
158-
sm.write(QUERY)
159-
deadline = ticks_add(ticks_ms(), 100)
160-
while ticks_less(ticks_ms(), deadline):
161-
if sm.in_waiting:
162-
sm.readinto(recv_buf)
163-
value = recv_buf[0]
164-
handler.handle_report(value)
165-
break
166-
else:
167-
print("keyboard did not respond - resetting")
168-
sm.restart()
169-
sm.write(RESET)
170-
time.sleep(0.1)
183+
try:
184+
while True:
185+
sm.write(QUERY)
186+
deadline = ticks_add(ticks_ms(), 100)
187+
while ticks_less(ticks_ms(), deadline):
188+
if sm.in_waiting:
189+
sm.readinto(recv_buf)
190+
value = recv_buf[0]
191+
handler.handle_report(value)
192+
break
193+
else:
194+
print("keyboard did not respond - resetting")
195+
sm.restart()
196+
sm.write(RESET)
197+
time.sleep(0.1)
198+
finally: # Release all keys before e.g., code is reloaded
199+
handler.kbd.release_all()

CircuitPython_NeXT_Keyboard_RP2040/next_keycode.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66

77
def is_cc(value):
8-
return value & MASK_CC
8+
return isinstance(value, int) and (value & MASK_CC)
99

1010

1111
def cc_value(value):
@@ -22,6 +22,8 @@ def cc_value(value):
2222
K.CONTROL,
2323
]
2424

25+
shift_modifiers = (1<<4) | (1<<5)
26+
2527
next_scancodes = {
2628
3: K.BACKSLASH,
2729
4: K.RIGHT_BRACKET,
@@ -101,3 +103,8 @@ def cc_value(value):
101103
25: C.BRIGHTNESS_INCREMENT | MASK_CC,
102104
1: C.BRIGHTNESS_DECREMENT | MASK_CC,
103105
}
106+
107+
shifted_codes = {
108+
39: K.BACKSLASH, # already shifted
109+
40: (K.BACKSLASH,), # will temporarily undo shift
110+
}

0 commit comments

Comments
 (0)