kbd improvements

This commit is contained in:
Peter D. Gray 2024-02-08 10:41:02 -05:00
parent ae87b63524
commit 388842988d
No known key found for this signature in database
GPG Key ID: A2DCD558C2BE5D7C
8 changed files with 54 additions and 33 deletions

View File

@ -30,6 +30,7 @@ class FullKeyboard(NumpadBase):
# after full scan, these flags are set for each key
self.is_pressed = bytearray(NUM_ROWS * NUM_COLS)
self._char_reported = set()
# what meta keys are currently pressed
self.active_meta_keys = set()
@ -88,7 +89,6 @@ class FullKeyboard(NumpadBase):
def _wait_any(self):
# wait for any press.
#self.timer.deinit()
self.waiting_for_any = True
for r in self.rows:
@ -102,7 +102,7 @@ class FullKeyboard(NumpadBase):
self._scan_count = 0
self.waiting_for_any = False
def _measure_irq(self, _timer):
def _measure_irq(self, _unused):
# CHALLENGE: Called at high rate (61Hz), but can do memory alloc.
# - sample all keys once, record any that are pressed
if self.waiting_for_any:
@ -143,7 +143,7 @@ class FullKeyboard(NumpadBase):
def process_chg_state(self, new_presses):
# we're done a full scan (mulitple times: NUM_SAMPLES)
# - convert that into ascii-like events in a Q for rest of system
# - not trying to support multiple presses, just one
# - during multiple presses, each reported once, then when "all up", another event
shift_down = self.is_pressed[KEYNUM_SHIFT]
symbol_down = self.is_pressed[KEYNUM_SYMBOL]
status_chg = dict()
@ -175,15 +175,17 @@ class FullKeyboard(NumpadBase):
continue
# indicated key was found to be down and then back up
key = decoder[kn]
if key == '\0':
# - now it is a character, not a key anymore
ch = decoder[kn]
if ch == '\0':
# dead/unused key: do nothing - like SYM+D
#print("KEYNUM %d is no-op (in this state)" % kn)
continue
if key != self.key_pressed:
#print("KEY: event=%d => %c=0x%x" % (kn, key, ord(key)))
self._key_event(key)
if ch not in self._char_reported:
#print("KEY: event=%d => %c=0x%x" % (kn, ch, ord(ch)))
self._char_reported.add(ch)
self._key_event(ch)
self.lp_time = utime.ticks_ms()
@ -205,7 +207,8 @@ class FullKeyboard(NumpadBase):
uasyncio.create_task(dis.async_draw_status(**status_chg))
if not any(self.is_pressed):
if self.key_pressed:
if self._char_reported:
self._char_reported.clear()
self._key_event('')
if utime.ticks_diff(utime.ticks_ms(), self.lp_time) > 250:

View File

@ -4,7 +4,7 @@
#
import pincodes, version, random
from glob import dis
from ux import PressRelease, ux_wait_keyup, ux_show_story, ux_show_pin, ux_show_phish_words
from ux import ux_wait_keyup, ux_wait_keydown, ux_show_story, ux_show_pin, ux_show_phish_words
from callgate import show_logout
from pincodes import pa
from uasyncio import sleep_ms
@ -76,9 +76,9 @@ class LoginUX:
self.shuffle_keys()
self.show_pin(True)
pr = PressRelease('0123456789y'+KEY_ENTER)
while 1:
ch = await pr.wait()
ch = await ux_wait_keydown(None, 10000)
if ch is None: continue
if has_qwerty and not self.is_setting and ch.upper() == self.kill_btn:
# wipe the seed if they press a special key

View File

@ -14,7 +14,7 @@ from ustruct import pack, unpack
from ubinascii import unhexlify as a2b_hex
from ubinascii import b2a_base64, a2b_base64
from ux import ux_show_story, ux_wait_keyup
from ux import ux_show_story, ux_wait_keydown
from utils import B2A, problem_file_line, parse_addr_fmt_str
from public_constants import AF_CLASSIC
from charcodes import KEY_ENTER, KEY_CANCEL
@ -322,7 +322,6 @@ class NFCHandler:
# - user can press OK during this period if they know they are done
min_delay = (3000 if write_mode else 1000)
first = True
while 1:
if dis.has_lcd:
phase = (phase + 1) % 2
@ -334,12 +333,7 @@ class NFCHandler:
dis.show()
# wait for key or 250ms animation delay
try:
ch = await asyncio.wait_for_ms(ux_wait_keyup(flush=first), 250)
except asyncio.TimeoutError:
ch = None
first = False
ch = await ux_wait_keydown(KEY_ENTER+KEY_CANCEL+'xy', 250)
if self.last_edge:
self.last_edge = 0

View File

@ -43,6 +43,11 @@ class NumpadBase:
self._changes.put_nowait(key)
self._changes.put_nowait('')
def clear_pressed(self):
# clear any key that is down right now, but don't generate
# a key-up event for it either
self.key_pressed = ''
def _key_event(self, key):
if key != self.key_pressed:
# annouce change

View File

@ -206,6 +206,7 @@ class QRScanner:
break
except asyncio.CancelledError:
print('scan cancel')
return None
finally:
# Problem: another valid scan can come in just as we are trying

View File

@ -122,6 +122,32 @@ async def ux_wait_keyup(expected=None, flush=False):
armed = ch
async def ux_wait_keydown(allowed, timeout_ms):
# Wait for PRESS (not press+release) of any key. Return it and arrange so
# that the later release doesn't cause confusion.
# - no key repeat here
from glob import numpad
for t in range(timeout_ms):
if numpad.empty():
await sleep_ms(1)
continue
ch = numpad.get_nowait()
if ch == numpad.ABORT_KEY:
raise AbortInteraction()
if ch == '' or (allowed and (ch not in allowed)):
# keyup or unwanted
continue
numpad.clear_pressed()
return ch
# timeout
return None
def ux_poll_key():
# non-blocking check if any key is pressed
# - responds to key down only

View File

@ -59,6 +59,7 @@ class PressRelease:
self.last_key = ch
return ch
async def ux_confirm(msg):
# confirmation screen, with stock title and Y=of course.
from ux import ux_show_story

View File

@ -755,7 +755,7 @@ class QRScannerInteraction:
# - CANCEL to abort
# - returns a string, BBQr object or None.
from glob import dis, SCAN
from ux import ux_wait_keyup
from ux import ux_wait_keydown
frames = [ 1, 2, 3, 4, 5, 4, 3, 2 ]
if not SCAN:
@ -780,10 +780,7 @@ class QRScannerInteraction:
ph = (ph + 1) % len(frames)
# wait for key or 250ms animation delay
try:
ch = await asyncio.wait_for_ms(ux_wait_keyup(), 250)
except asyncio.TimeoutError:
ch = None
ch = await ux_wait_keydown(KEY_CANCEL, 250)
if ch == KEY_CANCEL:
data = None
@ -1063,7 +1060,7 @@ async def show_bbqr_codes(type_code, data, msg, already_hex=False):
# - TODO this code needs better home
from bbqr import TYPE_LABELS, int2base36
from glob import PSRAM, dis
from ux import ux_wait_keyup
from ux import ux_wait_keyup, ux_wait_keydown
import uqr
PAYLOAD_PER_V40 = 2144 # if HEX encoded, active payload (max) per v40 QR
@ -1137,13 +1134,7 @@ async def show_bbqr_codes(type_code, data, msg, already_hex=False):
return
# wait for key or animation delay
try:
ch = await asyncio.wait_for_ms(ux_wait_keyup(flush=True), ms_per_each)
except asyncio.CancelledError:
# during testing
return
except asyncio.TimeoutError:
ch = None
ch = await ux_wait_keydown(None, ms_per_each)
if ch: return