X-Git-Url: https://wannabe.guru.org/gitweb/?a=blobdiff_plain;f=input_utils.py;h=77094daaa7a70cd83ebf0e2b5ba0adac311d2b01;hb=532df2c5b57c7517dfb3dddd8c1358fbadf8baf3;hp=913146a313608398d902a03eef7fe824399cd6fc;hpb=497fb9e21f45ec08e1486abaee6dfa7b20b8a691;p=python_utils.git diff --git a/input_utils.py b/input_utils.py index 913146a..77094da 100644 --- a/input_utils.py +++ b/input_utils.py @@ -1,12 +1,20 @@ #!/usr/bin/env python3 +# © Copyright 2021-2022, Scott Gasch + """Utilities related to user input.""" -import readchar # type: ignore +import logging import signal import sys from typing import List +import readchar # type: ignore + +import exceptions + +logger = logging.getLogger(__file__) + def single_keystroke_response( valid_responses: List[str], @@ -15,15 +23,15 @@ def single_keystroke_response( default_response: str = None, timeout_seconds: int = None, ) -> str: - class TimeoutError(Exception): - pass + """Get a single keystroke response to a prompt.""" def _handle_timeout(signum, frame) -> None: - raise TimeoutError() + raise exceptions.TimeoutError() def _single_keystroke_response_internal( valid_responses: List[str], timeout_seconds=None ) -> str: + os_special_keystrokes = [3, 26] # ^C, ^Z if timeout_seconds is not None: signal.signal(signal.SIGALRM, _handle_timeout) signal.alarm(timeout_seconds) @@ -31,8 +39,11 @@ def single_keystroke_response( try: while True: response = readchar.readchar() + logger.debug('Keystroke: 0x%x', ord(response)) if response in valid_responses: break + if ord(response) in os_special_keystrokes: + break return response finally: if timeout_seconds is not None: @@ -42,10 +53,11 @@ def single_keystroke_response( print(prompt, end="") sys.stdout.flush() try: - response = _single_keystroke_response_internal( - valid_responses, timeout_seconds - ) - except TimeoutError: + response = _single_keystroke_response_internal(valid_responses, timeout_seconds) + if ord(response) == 3: + raise KeyboardInterrupt('User pressed ^C in input_utils.') + + except exceptions.TimeoutError: if default_response is not None: response = default_response if prompt is not None: @@ -54,12 +66,16 @@ def single_keystroke_response( def yn_response(prompt: str = None, *, timeout_seconds=None) -> str: + """Get a Y/N response to a prompt.""" + return single_keystroke_response( ["y", "n", "Y", "N"], prompt=prompt, timeout_seconds=timeout_seconds ).lower() def keystroke_helper() -> None: + """Misc util to watch keystrokes and report what they were.""" + print("Watching for keystrokes; ^C to quit.") while True: key = readchar.readkey()