3 """Utilities related to user input."""
7 from typing import List
9 import readchar # type: ignore
14 def single_keystroke_response(
15 valid_responses: List[str],
18 default_response: str = None,
19 timeout_seconds: int = None,
21 """Get a single keystroke response to a prompt."""
23 def _handle_timeout(signum, frame) -> None:
24 raise exceptions.TimeoutError()
26 def _single_keystroke_response_internal(
27 valid_responses: List[str], timeout_seconds=None
29 os_special_keystrokes = [3, 26] # ^C, ^Z
30 if timeout_seconds is not None:
31 signal.signal(signal.SIGALRM, _handle_timeout)
32 signal.alarm(timeout_seconds)
36 response = readchar.readchar()
37 if response in valid_responses:
39 if ord(response) in os_special_keystrokes:
43 if timeout_seconds is not None:
46 if prompt is not None:
50 response = _single_keystroke_response_internal(
51 valid_responses, timeout_seconds
53 except exceptions.TimeoutError:
54 if default_response is not None:
55 response = default_response
56 if prompt is not None:
61 def yn_response(prompt: str = None, *, timeout_seconds=None) -> str:
62 """Get a Y/N response to a prompt."""
64 return single_keystroke_response(
65 ["y", "n", "Y", "N"], prompt=prompt, timeout_seconds=timeout_seconds
69 def keystroke_helper() -> None:
70 """Misc util to watch keystrokes and report what they were."""
72 print("Watching for keystrokes; ^C to quit.")
74 key = readchar.readkey()
76 print(f'That was "{key}" ({ord(key)}).')
80 print(f'That was sequence "{key}" (', end="")
82 print(f" {ord(_)} ", end="")