def __init__(self, stream): from win32console import ( GetStdHandle, STD_OUTPUT_HANDLE, FOREGROUND_RED, FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_INTENSITY, ) red, green, blue, bold = ( FOREGROUND_RED, FOREGROUND_GREEN, FOREGROUND_BLUE, FOREGROUND_INTENSITY, ) self.stream = stream self.screenBuffer = GetStdHandle(STD_OUTPUT_HANDLE) self._colors = { "normal": red | green | blue, "red": red | bold, "green": green | bold, "blue": blue | bold, "yellow": red | green | bold, "magenta": red | blue | bold, "cyan": green | blue | bold, "white": red | green | blue | bold, }
class WindowsKeyPoller: def __init__(self): self.read_handle = GetStdHandle(STD_INPUT_HANDLE) self.read_handle.SetConsoleMode(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT) self.cur_event_length = 0 self.cur_keys_length = 0 self.captured_chars = [] def cleanup(self): pass def poll(self): if self.captured_chars: return self.captured_chars.pop(0) events_peek = self.read_handle.PeekConsoleInput(10000) if not events_peek: return None if not len(events_peek) == self.cur_event_length: for cur_event in events_peek[self.cur_event_length:]: if cur_event.EventType == KEY_EVENT: if ord(cur_event.Char) and cur_event.KeyDown: cur_char = str(cur_event.Char) self.captured_chars.append(cur_char) self.cur_event_length = len(events_peek) if self.captured_chars: return self.captured_chars.pop(0) else: return None
class KeyPoller(): def __init__(self): self.readHandle = GetStdHandle(STD_INPUT_HANDLE) self.readHandle.SetConsoleMode(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT) self.curEventLength = 0 self.curKeysLength = 0 self.capturedChars = [] def poll(self): if not len(self.capturedChars) == 0: return self.capturedChars.pop(0) eventsPeek = self.readHandle.PeekConsoleInput(10000) if len(eventsPeek) == 0: return None if not len(eventsPeek) == self.curEventLength: for curEvent in eventsPeek[self.curEventLength:]: if curEvent.EventType == KEY_EVENT: if ord(curEvent.Char) == 0 or not curEvent.KeyDown: pass else: curChar = str(curEvent.Char) self.capturedChars.append(curChar) self.curEventLength = len(eventsPeek) if not len(self.capturedChars) == 0: return self.capturedChars.pop(0) else: return None
def __enter__(self): self.readHandle = GetStdHandle(STD_INPUT_HANDLE) self.readHandle.SetConsoleMode(ENABLE_PROCESSED_INPUT) self.input_lenth = len(self.readHandle.PeekConsoleInput(10000)) return self
def __init__(self): self.read_handle = GetStdHandle(STD_INPUT_HANDLE) self.read_handle.SetConsoleMode(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT) self.cur_event_length = 0 self.cur_keys_length = 0 self.captured_chars = []
class KeyPoller(): def __init__(self): #https://stackoverflow.com/questions/13207678/whats-the-simplest-way-of-detecting-keyboard-input-in-python-from-the-terminal self.readHandle = GetStdHandle(STD_INPUT_HANDLE) self.readHandle.SetConsoleMode(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT) self.curEventLength = 0 self.curKeysLength = 0 self.capturedChars = [] def poll(self): if not len(self.capturedChars) == 0: return self.capturedChars.pop(0) eventsPeek = self.readHandle.PeekConsoleInput(10000) if len(eventsPeek) == 0: return None if not len(eventsPeek) == self.curEventLength: for curEvent in eventsPeek[self.curEventLength:]: if curEvent.EventType == KEY_EVENT: if ord(curEvent.Char) == 0 or not curEvent.KeyDown: pass else: curChar = str(curEvent.Char) self.capturedChars.append(curChar) self.curEventLength = len(eventsPeek) if not len(self.capturedChars) == 0: return self.capturedChars.pop(0) else: return None
class KeyboardHook(): """Keyboard Hook Class""" def __enter__(self): self.readHandle = GetStdHandle(STD_INPUT_HANDLE) self.readHandle.SetConsoleMode(ENABLE_PROCESSED_INPUT) self.input_lenth = len(self.readHandle.PeekConsoleInput(10000)) return self def __exit__(self, type, value, traceback): pass def reset(self): self.input_lenth = len(self.readHandle.PeekConsoleInput(10000)) return True def key_pressed(self): """poll method to check for keyboard input""" events_peek = self.readHandle.PeekConsoleInput(10000) #Events come in pairs of KEY_DOWN, KEY_UP so wait for at least 2 events if len(events_peek) >= (self.input_lenth + 2): self.input_lenth = len(events_peek) return True return False
class _Win32Colorizer: """ See _AnsiColorizer docstring. """ def __init__(self, stream): from win32console import ( # type: ignore[import] FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_INTENSITY, FOREGROUND_RED, STD_OUTPUT_HANDLE, GetStdHandle, ) red, green, blue, bold = ( FOREGROUND_RED, FOREGROUND_GREEN, FOREGROUND_BLUE, FOREGROUND_INTENSITY, ) self.stream = stream self.screenBuffer = GetStdHandle(STD_OUTPUT_HANDLE) self._colors = { "normal": red | green | blue, "red": red | bold, "green": green | bold, "blue": blue | bold, "yellow": red | green | bold, "magenta": red | blue | bold, "cyan": green | blue | bold, "white": red | green | blue | bold, } @classmethod def supported(cls, stream=sys.stdout): try: import win32console screenBuffer = win32console.GetStdHandle(win32console.STD_OUTPUT_HANDLE) except ImportError: return False import pywintypes # type: ignore[import] try: screenBuffer.SetConsoleTextAttribute( win32console.FOREGROUND_RED | win32console.FOREGROUND_GREEN | win32console.FOREGROUND_BLUE ) except pywintypes.error: return False else: return True def write(self, text, color): color = self._colors[color] self.screenBuffer.SetConsoleTextAttribute(color) self.stream.write(text) self.screenBuffer.SetConsoleTextAttribute(self._colors["normal"])
def __enter__(self): self.readHandle = GetStdHandle(STD_INPUT_HANDLE) self.readHandle.SetConsoleMode(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT) self.capturedChars = [] return self
def __init__(self): self.readHandle = GetStdHandle(STD_INPUT_HANDLE) self.readHandle.SetConsoleMode(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT) self.curEventLength = 0 self.curKeysLength = 0 self.capturedChars = []
def __init__(self): self.stopLock = threading.Lock() self.stopped = True self.capturedChars = "" self.readHandle = GetStdHandle(STD_INPUT_HANDLE) self.readHandle.SetConsoleMode(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT)
class KeyPoller(): def __enter__(self): global isWindows if isWindows: self.readHandle = GetStdHandle(STD_INPUT_HANDLE) self.readHandle.SetConsoleMode(ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT) self.curEventLength = 0 self.curKeysLength = 0 self.capturedChars = [] else: # Save the terminal settings self.fd = sys.stdin.fileno() self.new_term = termios.tcgetattr(self.fd) self.old_term = termios.tcgetattr(self.fd) # New terminal setting unbuffered self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO) termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term) return self def __exit__(self, type, value, traceback): if isWindows: pass else: termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term) def poll(self): if isWindows: if not len(self.capturedChars) == 0: return self.capturedChars.pop(0) eventsPeek = self.readHandle.PeekConsoleInput(10000) if len(eventsPeek) == 0: return None if not len(eventsPeek) == self.curEventLength: for curEvent in eventsPeek[self.curEventLength:]: if curEvent.EventType == KEY_EVENT: if ord(curEvent.Char) == 0 or not curEvent.KeyDown: pass else: curChar = str(curEvent.Char) self.capturedChars.append(curChar) self.curEventLength = len(eventsPeek) if not len(self.capturedChars) == 0: return self.capturedChars.pop(0) else: return None else: dr,dw,de = select.select([sys.stdin], [], [], 0) if not dr == []: return sys.stdin.read(1) return None
def __init__(self): #https://stackoverflow.com/questions/13207678/whats-the-simplest-way-of-detecting-keyboard-input-in-python-from-the-terminal self.readHandle = GetStdHandle(STD_INPUT_HANDLE) self.readHandle.SetConsoleMode(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT) self.curEventLength = 0 self.curKeysLength = 0 self.capturedChars = []
def __init__(self): if sys.stdin.isatty(): self.read_handle = GetStdHandle(STD_INPUT_HANDLE) self.read_handle.SetConsoleMode(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT) self.cur_event_length = 0 self.cur_keys_length = 0 self.captured_chars = [] else: raise InitError("Terminal was not a tty. Keyboard input disabled")
class _Win32Colorizer(object): """ See _AnsiColorizer docstring. """ def __init__(self, stream): from win32console import FOREGROUND_BLUE from win32console import FOREGROUND_GREEN from win32console import FOREGROUND_INTENSITY from win32console import FOREGROUND_RED from win32console import GetStdHandle from win32console import STD_OUT_HANDLE red, green, blue, bold = (FOREGROUND_RED, FOREGROUND_GREEN, FOREGROUND_BLUE, FOREGROUND_INTENSITY) self.stream = stream self.screenBuffer = GetStdHandle(STD_OUT_HANDLE) self._colors = { 'normal': red | green | blue, 'red': red | bold, 'green': green | bold, 'blue': blue | bold, 'yellow': red | green | bold, 'magenta': red | blue | bold, 'cyan': green | blue | bold, 'white': red | green | blue | bold } def supported(cls, stream=sys.stdout): try: import win32console screenBuffer = win32console.GetStdHandle( win32console.STD_OUT_HANDLE) except ImportError: return False import pywintypes try: screenBuffer.SetConsoleTextAttribute( win32console.FOREGROUND_RED | win32console.FOREGROUND_GREEN | win32console.FOREGROUND_BLUE) except pywintypes.error: return False else: return True supported = classmethod(supported) def write(self, text, color): color = self._colors[color] self.screenBuffer.SetConsoleTextAttribute(color) self.stream.write(text) self.screenBuffer.SetConsoleTextAttribute(self._colors['normal'])
def __init__(self, stream): from win32console import GetStdHandle, STD_OUT_HANDLE from win32console import FOREGROUND_RED, FOREGROUND_BLUE from win32console import FOREGROUND_GREEN, FOREGROUND_INTENSITY red, green, blue, bold = (FOREGROUND_RED, FOREGROUND_GREEN, FOREGROUND_BLUE, FOREGROUND_INTENSITY) self.stream = stream self.screenBuffer = GetStdHandle(STD_OUT_HANDLE) self._colors = { 'normal': red | green | blue, 'red': red | bold, 'green': green | bold, 'blue': blue | bold, 'yellow': red | green | bold, 'magenta': red | blue | bold, 'cyan': green | blue | bold, 'white': red | green | blue | bold}
def prompt(prompt, default=''): if on_windows(): keys = [] for c in str(default): eve = PyINPUT_RECORDType(KEY_EVENT) eve.Char = c eve.RepeatCount = 1 eve.KeyDown = True keys.append(eve) std_input = GetStdHandle(STD_INPUT_HANDLE) std_input.WriteConsoleInput(keys) elif on_linux(): set_startup_hook(lambda : insert_text(default)) try: return input(prompt) finally: set_startup_hook() return input(prompt)
def prepare_virtual_console() -> None: """ On Windows, ensure that Console Virtual Terminal Sequences are enabled. """ if POSIX_MODE: return # https://docs.microsoft.com/en-us/windows/console/setconsolemode ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 # stdout/stderr will be the same console screen buffer, but this could return None or raise try: h = GetStdHandle(STD_OUTPUT_HANDLE) if h: h.SetConsoleMode(h.GetConsoleMode() | ENABLE_VIRTUAL_TERMINAL_PROCESSING) except pywinerror: logger.debug("Failed to set console mode", exc_info=True)
def __enter__(self): global isWindows if isWindows: self.readHandle = GetStdHandle(STD_INPUT_HANDLE) self.readHandle.SetConsoleMode(ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT|ENABLE_PROCESSED_INPUT) self.curEventLength = 0 self.curKeysLength = 0 self.capturedChars = [] else: # Save the terminal settings self.fd = sys.stdin.fileno() self.new_term = termios.tcgetattr(self.fd) self.old_term = termios.tcgetattr(self.fd) # New terminal setting unbuffered self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO) termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term) return self
class KeyListener: def __enter__(self): self.readHandle = GetStdHandle(STD_INPUT_HANDLE) self.readHandle.SetConsoleMode(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT) self.capturedChars = [] return self def __exit__(self, type, value, traceback): pass def poll(self): if self.capturedChars: return self.capturedChars.pop(0) eventsPeek = self.readHandle.PeekConsoleInput(10000) if len(eventsPeek) == 0: return None eventsPeek = self.readHandle.ReadConsoleInput(10000) for curEvent in eventsPeek: if curEvent.EventType == KEY_EVENT: if not curEvent.KeyDown: pass else: char, control = None, None if curEvent.VirtualKeyCode in controlKeyValues: control = ControlKeys(curEvent.VirtualKeyCode) else: char = curEvent.Char self.capturedChars.append((char, control)) if self.capturedChars: return self.capturedChars.pop(0) else: return None
return record.VirtualKeyCode in [16, 17, 18] # Initialization FOREGROUND_BLUE = 0x01 FOREGROUND_GREEN = 0x02 FOREGROUND_RED = 0x04 FOREGROUND_WHITE = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED FOREGROUND_BRIGHT = 0x08 BACKGROUND_BLUE = 0x10 BACKGROUND_GREEN = 0x20 BACKGROUND_RED = 0x40 BACKGROUND_BRIGHT = 0x80 BACKGROUND_WHITE = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED stdin_handle = GetStdHandle(STD_INPUT_HANDLE) stdout_handle = ctypes.windll.kernel32.GetStdHandle(-11) class ColorOutputStream: """ We install a custom sys.stdout that handles: * our color sequences * string encoding Note that this requires sys.stdout be only imported _after_ console; not doing so will bring the original stdout in the current scope! """ encoding = sys.__stdout__.encoding def write(self, str):
""" return record.VirtualKeyCode in [16, 17, 18] # Initialization FOREGROUND_BLUE = 0x01 FOREGROUND_GREEN = 0x02 FOREGROUND_RED = 0x04 FOREGROUND_WHITE = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED FOREGROUND_BRIGHT = 0x08 BACKGROUND_BLUE = 0x10 BACKGROUND_GREEN = 0x20 BACKGROUND_RED = 0x40 BACKGROUND_BRIGHT = 0x80 BACKGROUND_WHITE = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED stdin_handle = GetStdHandle(STD_INPUT_HANDLE) stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE) class ColorOutputStream: """ We install a custom sys.stdout that handles: * our color sequences * string encoding Note that this requires sys.stdout be only imported _after_ console; not doing so will bring the original stdout in the current scope! Additional Note: mode, name, softspace, writelines, and flush are not used anywhere in PyCmd's source code, but since they're expected on the stdout handle, it wouldn't be unexpected for them to be referenced in external user code or a debugger. (so I implemented them)
class KeyAsyncReader(): def __init__(self): self.stopLock = threading.Lock() self.stopped = True self.capturedChars = "" self.readHandle = GetStdHandle(STD_INPUT_HANDLE) self.readHandle.SetConsoleMode(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT) def startReading(self, readCallback): self.stopLock.acquire() try: if not self.stopped: raise Exception("Capture is already going") self.stopped = False self.readCallback = readCallback backgroundCaptureThread = threading.Thread( target=self.backgroundThreadReading) backgroundCaptureThread.daemon = True backgroundCaptureThread.start() except: self.stopLock.release() raise self.stopLock.release() def backgroundThreadReading(self): curEventLength = 0 curKeysLength = 0 while True: eventsPeek = self.readHandle.PeekConsoleInput(10000) self.stopLock.acquire() if self.stopped: self.stopLock.release() return self.stopLock.release() if len(eventsPeek) == 0: continue if not len(eventsPeek) == curEventLength: if self.getCharsFromEvents(eventsPeek[curEventLength:]): self.stopLock.acquire() self.stopped = True self.stopLock.release() break curEventLength = len(eventsPeek) time.sleep(1) def getCharsFromEvents(self, eventsPeek): callbackReturnedTrue = False for curEvent in eventsPeek: if curEvent.EventType == KEY_EVENT: if ord(curEvent.Char) == 0 or not curEvent.KeyDown: pass else: curChar = str(curEvent.Char) if self.readCallback(curChar) == True: callbackReturnedTrue = True return callbackReturnedTrue def stopReading(self): self.stopLock.acquire() self.stopped = True
def __enter__(self): global isWindows if isWindows: self.readHandle = GetStdHandle(STD_INPUT_HANDLE)