From 215c02e369cba4d54f8e7901c51d637834f5b9ce Mon Sep 17 00:00:00 2001 From: Jan Holthuis Date: Mon, 12 Sep 2016 17:51:50 +0200 Subject: [PATCH] linux/reicast-joyconfig: Implement noecho terminal mode for keyboards --- shell/linux/tools/reicast-joyconfig.py | 68 ++++++++++++++++++++------ 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/shell/linux/tools/reicast-joyconfig.py b/shell/linux/tools/reicast-joyconfig.py index 05bfc52ce..42f51ce52 100755 --- a/shell/linux/tools/reicast-joyconfig.py +++ b/shell/linux/tools/reicast-joyconfig.py @@ -7,6 +7,7 @@ import sys import re import os import select +import contextlib if sys.version_info < (3, 0): import ConfigParser as configparser INPUT_FUNC = raw_input @@ -66,6 +67,38 @@ def clear_events(dev): # just in case. pass +@contextlib.contextmanager +def noecho(): + # This function is largely based on unix_getpass(): + # https://github.com/python/cpython/blob/master/Lib/getpass.py#L30 + try: + fd = os.open('/dev/tty', os.O_RDWR | os.O_NOCTTY) + stream = os.fdopen(fd, 'w+', 1) + except EnvironmentError: + try: + fd = sys.stdin.fileno() + stream = sys.stderr + except (AttributeError, ValueError): + fd = None + stream = None + if termios is None or fd is None: + yield + else: + old = termios.tcgetattr(fd) # a copy to save + new = old[:] + new[3] &= ~termios.ECHO # 3 == 'lflags' + tcsetattr_flags = termios.TCSAFLUSH + if hasattr(termios, 'TCSASOFT'): + tcsetattr_flags |= termios.TCSASOFT + + try: + termios.tcsetattr(fd, tcsetattr_flags, new) + yield + finally: + termios.tcsetattr(fd, tcsetattr_flags, old) + if stream is not None: + stream.flush() # issue7208 + def read_button(dev): for event in dev.read_loop(): @@ -145,18 +178,20 @@ def setup_device(dev_id): # Emulator escape button if ask_yes_no("Do you want to map a button to exit the emulator"): - clear_events(dev) - print("Press the that button now...") - event = read_button(dev) + with noecho(): + clear_events(dev) + print("Press the that button now...") + event = read_button(dev) mapping.set("emulator", "btn_escape", event.code) print_mapped_button("emulator escape button", event) # Regular dreamcast buttons for button in DREAMCAST_BUTTONS: if ask_yes_no("Do you want to map the %s button?" % button): - clear_events(dev) - print("Press the %s button now..." % button) - event = read_button(dev) + with noecho(): + clear_events(dev) + print("Press the %s button now..." % button) + event = read_button(dev) mapping.set("dreamcast", "btn_%s" % button.lower(), event.code) print_mapped_button("%s button" % button, event) @@ -164,9 +199,10 @@ def setup_device(dev_id): for i in range(1, 3): if ask_yes_no("Do you want to map DPad %d?" % i): for axis, button1, button2 in DREAMCAST_DPAD: - clear_events(dev) - print("Press the %s button of DPad %d now..." % (button1, i)) - event, axis_inverted = read_axis_or_key(dev, absinfos) + with noecho(): + clear_events(dev) + print("Press the %s button of DPad %d now..." % (button1, i)) + event, axis_inverted = read_axis_or_key(dev, absinfos) if event.type == evdev.ecodes.EV_ABS: axisname = "axis_dpad%d_%s" % (i, axis.lower()) mapping.set("compat", axisname, event.code) @@ -185,9 +221,10 @@ def setup_device(dev_id): # Triggers for trigger in DREAMCAST_TRIGGERS: if ask_yes_no("Do you want to map %s?" % trigger): - clear_events(dev) - print("Press the %s now..." % trigger) - event, axis_inverted = read_axis_or_key(dev, absinfos) + with noecho(): + clear_events(dev) + print("Press the %s now..." % trigger) + event, axis_inverted = read_axis_or_key(dev, absinfos) axis_inverted = not axis_inverted if event.type == evdev.ecodes.EV_ABS: axisname = "axis_%s" % trigger.lower() @@ -201,9 +238,10 @@ def setup_device(dev_id): # Stick if ask_yes_no("Do you want to map the analog stick?"): for axis, axis_dir in DREAMCAST_STICK_AXES: - clear_events(dev) - print("Please move the analog stick as far %s as possible now..." % axis_dir) - event, axis_inverted = read_axis(dev, absinfos) + with noecho(): + clear_events(dev) + print("Please move the analog stick as far %s as possible now..." % axis_dir) + event, axis_inverted = read_axis(dev, absinfos) axisname = "axis_%s" % axis.lower() mapping.set("dreamcast", axisname, event.code) mapping.set("compat", "%s_inverted" % axisname, "yes" if axis_inverted else "no")