import contextlib import sys import termios ESC = "\x1b" MOUSE = ESC + "[M" UP_KEY = ESC + "[A" DOWN_KEY = ESC + "[B" RIGHT_KEY = ESC + "[C" LEFT_KEY = ESC + "[D" PAGE_UP_KEY = ESC + "[5~" PAGE_DOWN_KEY = ESC + "[6~" HOME_KEY = ESC + "[H" END_KEY = ESC + "[F" def move(x, y): return ESC + f"[{y + 1:d};{x + 1:d}H" @contextlib.contextmanager def terminal_title(title): sys.stdout.write(ESC + "7") # save sys.stdout.write(f"\033]0;{title}\007") # set title try: yield finally: sys.stdout.write(ESC + "8") # restore @contextlib.contextmanager def mouse_tracking(): sys.stdout.write(ESC + "[?1000h" + ESC + "[?1002h") # tracking on try: yield finally: sys.stdout.write(ESC + "[?1002l" + ESC + "[?1000l") # tracking off @contextlib.contextmanager def alternate_buffer(): sys.stdout.write(ESC + "[?1049h") # switch to alternate buffer try: yield finally: sys.stdout.write(ESC + "[?1049l") # restore normal buffer @contextlib.contextmanager def interactive(): old_termios_settings = termios.tcgetattr(sys.stdin) new_settings = termios.tcgetattr(sys.stdin) new_settings[3] = new_settings[3] & ~termios.ECHO & ~termios.ICANON new_settings[6][termios.VMIN] = 0 termios.tcsetattr(sys.stdin, termios.TCSADRAIN, new_settings) sys.stdout.write(ESC + "[?1l") # Ensure normal cursor key codes try: yield finally: termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_termios_settings) RELEASE_MOUSE = 0 DRAG_MOUSE = 1 CLICK_MOUSE = 2 PRESS_MOUSE = 3 WHEEL_UP_MOUSE = 4 WHEEL_DOWN_MOUSE = 5 def decode_mouse_input(term_code): keys = [ord(byte) for byte in term_code] b = keys[0] - 32 x, y = (keys[1] - 33) % 256, (keys[2] - 33) % 256 button = ((b & 64) / 64 * 3) + (b & 3) + 1 if b & 3 == 3: action = RELEASE_MOUSE button = 0 elif b & 2048: action = RELEASE_MOUSE elif b & 32: action = DRAG_MOUSE elif b & 1536: action = CLICK_MOUSE else: action = PRESS_MOUSE return (action, button, x, y)