EMF_Camp_Badge/upip/ucurses/__init__.py

327 lines
6.2 KiB
Python

import os
import tty, termios
import select
COLOR_BLACK = 0
COLOR_RED = 1
COLOR_GREEN = 2
COLOR_YELLOW = 3
COLOR_BLUE = 4
COLOR_MAGENTA = 5
COLOR_CYAN = 6
COLOR_WHITE = 7
A_NORMAL = 0
A_BOLD = 1
A_UNDERLINE = 2
A_REVERSE = 4
A_STANDOUT = A_REVERSE
ATTRMAP = {
A_NORMAL: b"\x1b[0m",
A_BOLD: b"\x1b[1m", # Some terminal emulators don't render bold by default, then use 4m for underline
A_REVERSE: b"\x1b[7m",
}
# Use http://www.utf8-chartable.de/unicode-utf8-table.pl
# for utf-8 pseudographic reference
# "─"
ACS_HLINE = b"\xe2\x94\x80"
# "│"
ACS_VLINE = b"\xe2\x94\x82"
# "┌"
ACS_ULCORNER = b"\xe2\x94\x8c"
# "┐"
ACS_URCORNER = b"\xe2\x94\x90"
# "└"
ACS_LLCORNER = b"\xe2\x94\x94"
# "┘"
ACS_LRCORNER = b"\xe2\x94\x98"
KEY_F1 = 1031
KEY_RESIZE = 1100
KEY_MOUSE = 1101
KEY_BTAB = 1090
KEY_UP = 1001
KEY_DOWN = 1002
KEY_LEFT = 1003
KEY_RIGHT = 1004
KEY_HOME = 1005
KEY_END = 1006
KEY_PGUP = 1007
KEY_PGDN = 1008
KEY_QUIT = 1009
KEY_ENTER = 1010
KEY_BACKSPACE = 1011
KEY_DELETE = 1012
KEY_ESC = 0x1b
KEY_DC = KEY_DELETE
KEY_PPAGE = KEY_PGUP
KEY_NPAGE = KEY_PGDN
KEYMAP = {
b"\x1b[A": KEY_UP,
b"\x1b[B": KEY_DOWN,
b"\x1b[D": KEY_LEFT,
b"\x1b[C": KEY_RIGHT,
b"\x1bOH": KEY_HOME,
b"\x1bOF": KEY_END,
b"\x1b[1~": KEY_HOME,
b"\x1b[4~": KEY_END,
b"\x1b[5~": KEY_PGUP,
b"\x1b[6~": KEY_PGDN,
b"\x03": KEY_QUIT,
b"\r": KEY_ENTER,
b"\x7f": KEY_BACKSPACE,
b"\x1b[3~": KEY_DELETE,
b"\x1bOA": KEY_UP,
b"\x1bOB": KEY_DOWN,
b"\x1bOD": KEY_LEFT,
b"\x1bOC": KEY_RIGHT,
b"\x1bOP": KEY_F1,
b"\x1b": KEY_ESC,
b"\x1b[Z": KEY_BTAB,
}
ALL_MOUSE_EVENTS = 0xff
def _wr(s):
# TODO: When Python is 3.5, update this to use only bytes
if isinstance(s, str):
s = bytes(s, "utf-8")
os.write(1, s)
def _move(row, col):
# TODO: When Python is 3.5, update this to use bytes
_wr("\x1b[%d;%dH" % (row + 1, col + 1))
# Clear specified number of positions
def _clear_num_pos(num):
if num > 0:
_wr("\x1b[%dX" % num)
def _draw_box(left, top, width, height):
bottom = top + height - 1
_move(top, left)
_wr(ACS_ULCORNER)
hor = ACS_HLINE * (width - 2)
_wr(hor)
_wr(ACS_URCORNER)
_move(bottom, left)
_wr(ACS_LLCORNER)
_wr(hor)
_wr(ACS_LRCORNER)
top += 1
while top < bottom:
_move(top, left)
_wr(ACS_VLINE)
_move(top, left + width - 1)
_wr(ACS_VLINE)
top += 1
class error(Exception):
pass
class Window:
def __init__(self, lines, cols, y, x):
self.lines = lines
self.cols = cols
self.y = y
self.x = x
self.bkgattr = A_NORMAL
self.keybuf = None
self.keyi = 0
self.keydelay = -1
def _goto(self, row, col):
_move(self.y + row, self.x + col)
def move(self, y, x):
# Maybe need to cache coords?
self._goto(y, x)
def getmaxyx(self):
return (self.lines, self.cols)
def addstr(self, y, x, str, attr=A_NORMAL):
self._goto(y, x)
# TODO: Should be "ORed"
if attr == A_NORMAL:
attr = self.bkgattr
if attr != A_NORMAL:
_wr(ATTRMAP[attr])
_wr(str)
_wr(ATTRMAP[A_NORMAL])
else:
_wr(str)
def addnstr(self, y, x, str, n, attr=A_NORMAL):
self.addstr(y, x, str[:n], attr)
def addch(self, y, x, ch, attr=A_NORMAL):
if isinstance(ch, int):
ch = chr(ch)
self.addstr(y, x, ch, attr)
def attron(self, attr):
pass
def attroff(self, attr):
pass
def attrset(self, attr):
pass
def bkgdset(self, ch, attr=A_NORMAL):
self.bkgattr = attr
def erase(self):
for i in range(self.lines):
self._goto(i, 0)
_clear_num_pos(self.cols)
def border(self):
_draw_box(self.x, self.y, self.cols, self.lines)
def hline(self, y, x, ch, n):
self.move(y, x)
_wr(ch * n)
def vline(self, y, x, ch, n):
for i in range(n):
self.move(y + i, x)
_wr(ch)
def refresh(self):
pass
def redrawwin(self):
pass
def keypad(self, yes):
pass
def timeout(self, delay):
self.keydelay = delay
def nodelay(self, yes):
if yes:
self.keydelay = 0
else:
self.keydelay = -1
def getch(self):
if self.keybuf and self.keyi < len(self.keybuf):
c = self.keybuf[self.keyi]
self.keyi += 1
return c
if self.keydelay >= 0:
USE_EPOLL = 1
if USE_EPOLL:
poll = select.epoll()
poll.register(0, select.EPOLLIN)
res = poll.poll(self.keydelay / 1000)
poll.unregister(0)
poll.close()
else:
res = select.select([0], [], [], self.keydelay / 1000)[0]
if not res:
return -1
key = os.read(0, 32)
if key[0] != 0x1b:
self.keybuf = key
self.keyi = 1
key = key[0]
else:
if key in KEYMAP:
key = KEYMAP[key]
else:
assert False, repr(key)
return key
SCREEN = Window(24, 80, 0, 0)
org_termios = None
def wrapper(func):
global org_termios
org_termios = termios.tcgetattr(0)
res = func()
endwin()
return res
def initscr():
global org_termios
org_termios = termios.tcgetattr(0)
return SCREEN
def doupdate():
pass
def endwin():
global org_termios
_wr(b"\r")
termios.tcsetattr(0, termios.TCSANOW, org_termios)
def raw():
tty.setraw(0)
def cbreak():
#TODO
pass
def nocbreak():
#TODO
pass
def echo():
#TODO
pass
def noecho():
#TODO
pass
def meta(yes):
#TODO
pass
def mousemask(mask):
# Mouse reporting - X10 compatbility mode
_wr(b"\x1b[?9h")
def has_colors():
return False
def can_change_color():
return False
def curs_set(visibility):
if visibility > 0:
_wr(b"\x1b[?25h")
else:
_wr(b"\x1b[?25l")
def beep():
_wr(b"\x07")
def newwin(lines, cols, y=0, x=0):
#print("newwin(%d, %d, %d, %d)" % (lines, cols, y, x))
cols = cols or SCREEN.cols
lines = lines or SCREEN.lines
return Window(lines, cols, y, x)