first save
This commit is contained in:
176
.venv/lib/python3.12/site-packages/mpremote/console.py
Normal file
176
.venv/lib/python3.12/site-packages/mpremote/console.py
Normal file
@@ -0,0 +1,176 @@
|
||||
import sys, time
|
||||
|
||||
try:
|
||||
import select, termios
|
||||
except ImportError:
|
||||
termios = None
|
||||
select = None
|
||||
import msvcrt, signal
|
||||
|
||||
|
||||
class ConsolePosix:
|
||||
def __init__(self):
|
||||
self.infd = sys.stdin.fileno()
|
||||
self.infile = sys.stdin.buffer
|
||||
self.outfile = sys.stdout.buffer
|
||||
if hasattr(self.infile, "raw"):
|
||||
self.infile = self.infile.raw
|
||||
if hasattr(self.outfile, "raw"):
|
||||
self.outfile = self.outfile.raw
|
||||
|
||||
self.orig_attr = termios.tcgetattr(self.infd)
|
||||
|
||||
def enter(self):
|
||||
# attr is: [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]
|
||||
attr = termios.tcgetattr(self.infd)
|
||||
attr[0] &= ~(
|
||||
termios.BRKINT | termios.ICRNL | termios.INPCK | termios.ISTRIP | termios.IXON
|
||||
)
|
||||
attr[1] = 0
|
||||
attr[2] = attr[2] & ~(termios.CSIZE | termios.PARENB) | termios.CS8
|
||||
attr[3] = 0
|
||||
attr[6][termios.VMIN] = 1
|
||||
attr[6][termios.VTIME] = 0
|
||||
termios.tcsetattr(self.infd, termios.TCSANOW, attr)
|
||||
|
||||
def exit(self):
|
||||
termios.tcsetattr(self.infd, termios.TCSANOW, self.orig_attr)
|
||||
|
||||
def waitchar(self, pyb_serial):
|
||||
# TODO pyb_serial might not have fd
|
||||
select.select([self.infd, pyb_serial.fd], [], [])
|
||||
|
||||
def readchar(self):
|
||||
res = select.select([self.infd], [], [], 0)
|
||||
if res[0]:
|
||||
return self.infile.read(1)
|
||||
else:
|
||||
return None
|
||||
|
||||
def write(self, buf):
|
||||
self.outfile.write(buf)
|
||||
|
||||
|
||||
class ConsoleWindows:
|
||||
KEY_MAP = {
|
||||
b"H": b"A", # UP
|
||||
b"P": b"B", # DOWN
|
||||
b"M": b"C", # RIGHT
|
||||
b"K": b"D", # LEFT
|
||||
b"G": b"H", # POS1
|
||||
b"O": b"F", # END
|
||||
b"Q": b"6~", # PGDN
|
||||
b"I": b"5~", # PGUP
|
||||
b"s": b"1;5D", # CTRL-LEFT,
|
||||
b"t": b"1;5C", # CTRL-RIGHT,
|
||||
b"\x8d": b"1;5A", # CTRL-UP,
|
||||
b"\x91": b"1;5B", # CTRL-DOWN,
|
||||
b"w": b"1;5H", # CTRL-POS1
|
||||
b"u": b"1;5F", # CTRL-END
|
||||
b"\x98": b"1;3A", # ALT-UP,
|
||||
b"\xa0": b"1;3B", # ALT-DOWN,
|
||||
b"\x9d": b"1;3C", # ALT-RIGHT,
|
||||
b"\x9b": b"1;3D", # ALT-LEFT,
|
||||
b"\x97": b"1;3H", # ALT-POS1,
|
||||
b"\x9f": b"1;3F", # ALT-END,
|
||||
b"S": b"3~", # DEL,
|
||||
b"\x93": b"3;5~", # CTRL-DEL
|
||||
b"R": b"2~", # INS
|
||||
b"\x92": b"2;5~", # CTRL-INS
|
||||
b"\x94": b"Z", # Ctrl-Tab = BACKTAB,
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.ctrl_c = 0
|
||||
|
||||
def _sigint_handler(self, signo, frame):
|
||||
self.ctrl_c += 1
|
||||
|
||||
def enter(self):
|
||||
signal.signal(signal.SIGINT, self._sigint_handler)
|
||||
|
||||
def exit(self):
|
||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
||||
|
||||
def inWaiting(self):
|
||||
return 1 if self.ctrl_c or msvcrt.kbhit() else 0
|
||||
|
||||
def waitchar(self, pyb_serial):
|
||||
while not (self.inWaiting() or pyb_serial.inWaiting()):
|
||||
time.sleep(0.01)
|
||||
|
||||
def readchar(self):
|
||||
if self.ctrl_c:
|
||||
self.ctrl_c -= 1
|
||||
return b"\x03"
|
||||
if msvcrt.kbhit():
|
||||
ch = msvcrt.getch()
|
||||
while ch in b"\x00\xe0": # arrow or function key prefix?
|
||||
if not msvcrt.kbhit():
|
||||
return None
|
||||
ch = msvcrt.getch() # second call returns the actual key code
|
||||
try:
|
||||
ch = b"\x1b[" + self.KEY_MAP[ch]
|
||||
except KeyError:
|
||||
return None
|
||||
return ch
|
||||
|
||||
def write(self, buf):
|
||||
buf = buf.decode() if isinstance(buf, bytes) else buf
|
||||
sys.stdout.write(buf)
|
||||
sys.stdout.flush()
|
||||
# for b in buf:
|
||||
# if isinstance(b, bytes):
|
||||
# msvcrt.putch(b)
|
||||
# else:
|
||||
# msvcrt.putwch(b)
|
||||
|
||||
|
||||
if termios:
|
||||
Console = ConsolePosix
|
||||
VT_ENABLED = True
|
||||
else:
|
||||
Console = ConsoleWindows
|
||||
|
||||
# Windows VT mode ( >= win10 only)
|
||||
# https://bugs.python.org/msg291732
|
||||
import ctypes, os
|
||||
from ctypes import wintypes
|
||||
|
||||
kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
|
||||
|
||||
ERROR_INVALID_PARAMETER = 0x0057
|
||||
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
|
||||
|
||||
def _check_bool(result, func, args):
|
||||
if not result:
|
||||
raise ctypes.WinError(ctypes.get_last_error())
|
||||
return args
|
||||
|
||||
LPDWORD = ctypes.POINTER(wintypes.DWORD)
|
||||
kernel32.GetConsoleMode.errcheck = _check_bool
|
||||
kernel32.GetConsoleMode.argtypes = (wintypes.HANDLE, LPDWORD)
|
||||
kernel32.SetConsoleMode.errcheck = _check_bool
|
||||
kernel32.SetConsoleMode.argtypes = (wintypes.HANDLE, wintypes.DWORD)
|
||||
|
||||
def set_conout_mode(new_mode, mask=0xFFFFFFFF):
|
||||
# don't assume StandardOutput is a console.
|
||||
# open CONOUT$ instead
|
||||
fdout = os.open("CONOUT$", os.O_RDWR)
|
||||
try:
|
||||
hout = msvcrt.get_osfhandle(fdout)
|
||||
old_mode = wintypes.DWORD()
|
||||
kernel32.GetConsoleMode(hout, ctypes.byref(old_mode))
|
||||
mode = (new_mode & mask) | (old_mode.value & ~mask)
|
||||
kernel32.SetConsoleMode(hout, mode)
|
||||
return old_mode.value
|
||||
finally:
|
||||
os.close(fdout)
|
||||
|
||||
# def enable_vt_mode():
|
||||
mode = mask = ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
try:
|
||||
set_conout_mode(mode, mask)
|
||||
VT_ENABLED = True
|
||||
except WindowsError:
|
||||
VT_ENABLED = False
|
||||
Reference in New Issue
Block a user