def ux_clear_keys(no_aborts=False): # flush any pending keypresses from glob import numpad try: while 1: ch = numpad.get_nowait() if not no_aborts and ch == numpad.ABORT_KEY: raise AbortInteraction() except QueueEmpty: return
async def wait(self): from glob import numpad armed = None while 1: # two values here: # - (ms) time to wait before first key-repeat # - (ms) time between 2nd and Nth repeated events # - these values approved by @nvk rep_delay = 200 if not self.num_repeats else 20 so_far = 0 while numpad.empty(): if self.last_key and numpad.key_pressed == self.last_key: if so_far >= rep_delay: self.num_repeats += 1 return self.last_key await sleep_ms(1) so_far += 1 ch = numpad.get_nowait() if ch == numpad.ABORT_KEY: raise AbortInteraction() self.num_repeats = 0 if len(ch) > 1: # multipress: cancel press/release cycle and be a keyup # for other keys. armed = None continue if ch == '': self.last_key = None if armed: return armed elif ch in self.need_release: # no key-repeat on these ones armed = ch else: self.last_key = ch return ch
def ux_poll_once(expected='x'): # non-blocking check if key is pressed # - ignore and suppress any key not in expected # - responds to key down only # - eats any existing key presses from glob import numpad while 1: try: ch = numpad.key_pressed while not ch: ch = numpad.get_nowait() if ch == numpad.ABORT_KEY: raise AbortInteraction() except QueueEmpty: return None for c in ch: if c in expected: return c
async def interact(self): import glob from glob import numpad from actions import login_now from uasyncio import sleep_ms # Replace some drawing functions orig_fullscreen = glob.dis.fullscreen orig_progress_bar = glob.dis.progress_bar orig_progress_bar_show = glob.dis.progress_bar_show glob.dis.fullscreen = self.hack_fullscreen glob.dis.progress_bar = self.hack_progress_bar glob.dis.progress_bar_show = self.hack_progress_bar # get ready ourselves glob.dis.set_brightness(0) # dimest, but still readable self.draw_background() # Kill time, waiting for user input self.digits = '' self.test_restart = False while not self.test_restart: self.show() gc.collect() try: # Poll for an event, no block ch = numpad.get_nowait() if ch == 'x': self.digits = '' elif ch == 'y': if len(self.digits) == LOCAL_PIN_LENGTH: glob.hsm_active.local_pin_entered(self.digits) self.digits = '' elif ch == numpad.ABORT_KEY: # important to eat these and fully suppress them pass elif ch: if len(self.digits) < LOCAL_PIN_LENGTH: # allow only 6 digits self.digits += ch[0] if len(self.digits) == LOCAL_PIN_LENGTH: # send it, even if they didn't press OK yet glob.hsm_active.local_pin_entered(self.digits) # do immediate screen update continue except QueueEmpty: await sleep_ms(100) except BaseException as exc: # just in case, keep going sys.print_exception(exc) continue # do the interactions, but don't let user actually press anything req = UserAuthorizedAction.active_request if req and not req.ux_done: try: await req.interact() except AbortInteraction: pass # This code only reachable on the simulator and modified devices under test, # and when the "boot_to_hsm" feature is used and successfully unlock near # boottime. from actions import goto_top_menu glob.hsm_active = None goto_top_menu() # restore normal operation of UX from display import Display glob.dis.fullscreen = orig_fullscreen glob.dis.progress_bar = orig_progress_bar glob.dis.progress_bar_show = orig_progress_bar_show return