+class AbortOnGetkey(Exception):
+ pass
+
+
+
class TUI:
def __init__(self):
self._log = []
+ self.do_refresh = True
+ self.store_widechar = False
curses.wrapper(self.run_loop)
def addstr(self, y, x, line, attr=0):
self.size = self.size - YX(self.size.y % 4, 0)
self.size = self.size - YX(0, self.size.x % 4)
+ def log(self, msg):
+ self._log += [msg]
+ self.do_refresh = True
+
def init_loop(self):
curses.curs_set(0) # hide cursor
self.stdscr.timeout(10)
self.reset_size()
+ def get_key_and_keycode(self):
+ try:
+ key = self.stdscr.getkey()
+ except curses.error:
+ raise AbortOnGetkey
+ keycode = None
+ if len(key) == 1:
+ keycode = ord(key)
+ # workaround for <https://stackoverflow.com/a/56390915>
+ if self.store_widechar:
+ self.store_widechar = False
+ key = bytes([195, keycode]).decode()
+ if keycode == 195:
+ self.store_widechar = True
+ raise AbortOnGetkey
+ return key, keycode
+
def run_loop(self, stdscr):
self.stdscr = stdscr
self.init_loop()
while True:
- self.loop()
-
- def log(self, msg):
- self._log += [msg]
+ self.on_each_loop_start()
+ for msg in self.socket.get_message():
+ self.handle_server_message(msg)
+ if self.do_refresh:
+ self.stdscr.clear()
+ self.draw_screen()
+ self.do_refresh = False
+ try:
+ key, keycode = self.get_key_and_keycode()
+ except AbortOnGetkey:
+ continue
+ self.on_key(key, keycode)
+ self.do_refresh = True