summaryrefslogtreecommitdiff
path: root/input_utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'input_utils.py')
-rw-r--r--input_utils.py74
1 files changed, 74 insertions, 0 deletions
diff --git a/input_utils.py b/input_utils.py
new file mode 100644
index 0000000..913146a
--- /dev/null
+++ b/input_utils.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+
+"""Utilities related to user input."""
+
+import readchar # type: ignore
+import signal
+import sys
+from typing import List
+
+
+def single_keystroke_response(
+ valid_responses: List[str],
+ *,
+ prompt: str = None,
+ default_response: str = None,
+ timeout_seconds: int = None,
+) -> str:
+ class TimeoutError(Exception):
+ pass
+
+ def _handle_timeout(signum, frame) -> None:
+ raise TimeoutError()
+
+ def _single_keystroke_response_internal(
+ valid_responses: List[str], timeout_seconds=None
+ ) -> str:
+ if timeout_seconds is not None:
+ signal.signal(signal.SIGALRM, _handle_timeout)
+ signal.alarm(timeout_seconds)
+
+ try:
+ while True:
+ response = readchar.readchar()
+ if response in valid_responses:
+ break
+ return response
+ finally:
+ if timeout_seconds is not None:
+ signal.alarm(0)
+
+ if prompt is not None:
+ print(prompt, end="")
+ sys.stdout.flush()
+ try:
+ response = _single_keystroke_response_internal(
+ valid_responses, timeout_seconds
+ )
+ except TimeoutError:
+ if default_response is not None:
+ response = default_response
+ if prompt is not None:
+ print(response)
+ return response
+
+
+def yn_response(prompt: str = None, *, timeout_seconds=None) -> str:
+ return single_keystroke_response(
+ ["y", "n", "Y", "N"], prompt=prompt, timeout_seconds=timeout_seconds
+ ).lower()
+
+
+def keystroke_helper() -> None:
+ print("Watching for keystrokes; ^C to quit.")
+ while True:
+ key = readchar.readkey()
+ if len(key) == 1:
+ print(f'That was "{key}" ({ord(key)}).')
+ if ord(key) == 3:
+ return
+ else:
+ print(f'That was sequence "{key}" (', end="")
+ for _ in key:
+ print(f" {ord(_)} ", end="")
+ print(")")