When running mpremote in the vscode terminal on OSX the sys.stdout.buffer does not have the raw attribute. It works fine without it.
177 lines
5.2 KiB
Python
177 lines
5.2 KiB
Python
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 as e:
|
|
VT_ENABLED = False
|