+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.stdscr = stdscr
         self.init_loop()
         while True:
-            self.loop()
+            try:
+                self.loop()
+            except AbortOnGetkey:
+                continue
+            self.do_refresh = True
 
     def log(self, msg):
         self._log += [msg]
+        self.do_refresh = True
 
+    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 msg_into_lines_of_width(msg, width):
 
         self.game = Game()
         self.game.tui = self
         self.parser = Parser(self.game)
-        self.do_refresh = True
         self.login_name = None
         self.map_mode = 'terrain + things'
         self.password = 'foo'
         self.offset = YX(0,0)
         self.explorer = YX(0, 0)
         self.input_ = ''
-        self.store_widechar = False
         self.input_prompt = '> '
         self.action_descriptions = {
             'move': 'move',
             self.do_refresh = False
         for msg in self.socket.get_message():
             handle_input(msg)
-        try:
-            key = self.stdscr.getkey()
-            self.do_refresh = True
-        except curses.error:
-            return
-        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
-                return
+        key, keycode = self.get_key_and_keycode()
         self.show_help = False
         self.draw_face = False
         if key == 'KEY_RESIZE':