summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzsquareplusc <cliechti@gmx.net>2020-09-14 05:39:36 +0200
committerGitHub <noreply@github.com>2020-09-14 05:39:36 +0200
commit1a9f0c9d319e3c038873d926277c09eb43f39bd3 (patch)
tree8bf5a80a034613e193f0853ef6d09ae8061c6cad
parente43a771f42eeffbedd303c9f5abb6b97cdd24d83 (diff)
parent035053d61d3fc54a71914fd77da22e75b2779c26 (diff)
downloadpyserial-git-1a9f0c9d319e3c038873d926277c09eb43f39bd3.tar.gz
Merge pull request #351 from cefn/master
win32: Working CMD.exe terminal using Windows 10 ANSI support
-rw-r--r--serial/tools/miniterm.py56
1 files changed, 54 insertions, 2 deletions
diff --git a/serial/tools/miniterm.py b/serial/tools/miniterm.py
index 3b8d5d2..2ec155e 100644
--- a/serial/tools/miniterm.py
+++ b/serial/tools/miniterm.py
@@ -88,6 +88,7 @@ class ConsoleBase(object):
if os.name == 'nt': # noqa
import msvcrt
import ctypes
+ import platform
class Out(object):
"""file-like wrapper that uses os.write"""
@@ -102,12 +103,52 @@ if os.name == 'nt': # noqa
os.write(self.fd, s)
class Console(ConsoleBase):
+ fncodes = {
+ ';': '\1bOP', # F1
+ '<': '\1bOQ', # F2
+ '=': '\1bOR', # F3
+ '>': '\1bOS', # F4
+ '?': '\1b[15~', # F5
+ '@': '\1b[17~', # F6
+ 'A': '\1b[18~', # F7
+ 'B': '\1b[19~', # F8
+ 'C': '\1b[20~', # F9
+ 'D': '\1b[21~', # F10
+ }
+ navcodes = {
+ 'H': '\x1b[A', # UP
+ 'P': '\x1b[B', # DOWN
+ 'K': '\x1b[D', # LEFT
+ 'M': '\x1b[C', # RIGHT
+ 'G': '\x1b[H', # HOME
+ 'O': '\x1b[F', # END
+ 'R': '\x1b[2~', # INSERT
+ 'S': '\x1b[3~', # DELETE
+ 'I': '\x1b[5~', # PGUP
+ 'Q': '\x1b[6~', # PGDN
+ }
+
def __init__(self):
super(Console, self).__init__()
self._saved_ocp = ctypes.windll.kernel32.GetConsoleOutputCP()
self._saved_icp = ctypes.windll.kernel32.GetConsoleCP()
ctypes.windll.kernel32.SetConsoleOutputCP(65001)
ctypes.windll.kernel32.SetConsoleCP(65001)
+ # ANSI handling available through SetConsoleMode since Windows 10 v1511
+ # https://en.wikipedia.org/wiki/ANSI_escape_code#cite_note-win10th2-1
+ if platform.release() == '10' and int(platform.version().split('.')[2]) > 10586:
+ ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
+ import ctypes.wintypes as wintypes
+ if not hasattr(wintypes, 'LPDWORD'): # PY2
+ wintypes.LPDWORD = ctypes.POINTER(wintypes.DWORD)
+ SetConsoleMode = ctypes.windll.kernel32.SetConsoleMode
+ GetConsoleMode = ctypes.windll.kernel32.GetConsoleMode
+ GetStdHandle = ctypes.windll.kernel32.GetStdHandle
+ mode = wintypes.DWORD()
+ GetConsoleMode(GetStdHandle(-11), ctypes.byref(mode))
+ if (mode.value & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0:
+ SetConsoleMode(GetStdHandle(-11), mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+ self._saved_cm = mode
self.output = codecs.getwriter('UTF-8')(Out(sys.stdout.fileno()), 'replace')
# the change of the code page is not propagated to Python, manually fix it
sys.stderr = codecs.getwriter('UTF-8')(Out(sys.stderr.fileno()), 'replace')
@@ -117,14 +158,25 @@ if os.name == 'nt': # noqa
def __del__(self):
ctypes.windll.kernel32.SetConsoleOutputCP(self._saved_ocp)
ctypes.windll.kernel32.SetConsoleCP(self._saved_icp)
+ try:
+ ctypes.windll.kernel32.SetConsoleMode(ctypes.windll.kernel32.GetStdHandle(-11), self._saved_cm)
+ except AttributeError: # in case no _saved_cm
+ pass
def getkey(self):
while True:
z = msvcrt.getwch()
if z == unichr(13):
return unichr(10)
- elif z in (unichr(0), unichr(0x0e)): # functions keys, ignore
- msvcrt.getwch()
+ elif z is unichr(0) or z is unichr(0xe0):
+ try:
+ code = msvcrt.getwch()
+ if z is unichr(0):
+ return self.fncodes[code]
+ else:
+ return self.navcodes[code]
+ except KeyError:
+ pass
else:
return z