class ClientEvent(AffectiveEvent, ClientIdMixin):
     'To affect Client identified by ClientIdMixin.'
 
-    @classmethod
-    def make_subtype(cls, method_to_call: str, **kwargs
-                     ) -> type['ClientEvent']:
-        'Return subclass whose .affect calls method_to_call on target, kwargs.'
-        class _AdaptedEvent(ClientEvent):
-            def affect(self, target) -> None:
-                getattr(target, method_to_call)(**kwargs)
-        return _AdaptedEvent
-
 
 class _IrcConnection(BaseIrcConnection):
 
         super().__init__(**kwargs)
 
     def _make_recv_event(self, msg: IrcMessage) -> ClientEvent:
+        # pylint: disable=unexpected-keyword-arg  # confused by client_id=
         return ClientEvent.make_subtype(method_to_call='handle_msg', msg=msg)(
                 client_id=self.client_id)
 
 
 # requirements.txt
 from blessed import Terminal as BlessedTerminal
 # ourselves
-from ircplom.events import (
-        AffectiveEvent, Logger, Loop, PayloadMixin, QueueMixin, QuitEvent)
-# from ircplom.irc_conn import IrcMessage
+from ircplom.events import AffectiveEvent, Logger, Loop, QueueMixin, QuitEvent
 
 _MIN_HEIGHT = 4
 _MIN_WIDTH = 32
     'To affect TUI.'
 
 
-@dataclass
-class _KeyboardEvent(TuiEvent, PayloadMixin):
-    payload: str
-
-    def affect(self, target: 'BaseTui') -> None:
-        if self.payload[0] == _CHAR_RESIZE:
-            target.set_screen()
-            return
-        if self.payload in _KEYBINDINGS:
-            cmd_data = _KEYBINDINGS[self.payload]
-            cmd = target.cmd_name_to_cmd(cmd_data[0])
-            if cmd:
-                cmd(*cmd_data[1:])
-        elif self.payload.startswith(_B64_PREFIX):
-            encoded = self.payload[len(_B64_PREFIX):]
-            to_paste = ''
-            for i, c in enumerate(b64decode(encoded).decode('utf-8')):
-                if i > 512:
-                    break
-                if c.isprintable():
-                    to_paste += c
-                elif c.isspace():
-                    to_paste += ' '
-                else:
-                    to_paste += '#'
-            target.window.prompt.insert(to_paste)
-        elif len(self.payload) == 1:
-            target.window.prompt.insert(self.payload)
-        else:
-            target.log.alert(f'unknown keyboard input: {self.payload}')
-        target.redraw_affected()
-
-
 class BaseTui(QueueMixin):
     'Base for graphical user interface elements.'
 
         self._window_idx = idx
         self.window.draw()
 
+    def handle_keyboard_event(self, typed_in: str) -> None:
+        'Translate keyboard input into appropriate actions.'
+        if typed_in[0] == _CHAR_RESIZE:
+            self.set_screen()
+            return
+        if typed_in in _KEYBINDINGS:
+            cmd_data = _KEYBINDINGS[typed_in]
+            cmd = self.cmd_name_to_cmd(cmd_data[0])
+            if cmd:
+                cmd(*cmd_data[1:])
+        elif typed_in.startswith(_B64_PREFIX):
+            encoded = typed_in[len(_B64_PREFIX):]
+            to_paste = ''
+            for i, c in enumerate(b64decode(encoded).decode('utf-8')):
+                if i > 512:
+                    break
+                if c.isprintable():
+                    to_paste += c
+                elif c.isspace():
+                    to_paste += ' '
+                else:
+                    to_paste += '#'
+            self.window.prompt.insert(to_paste)
+        elif len(typed_in) == 1:
+            self.window.prompt.insert(typed_in)
+        else:
+            self.log.alert(f'unknown keyboard input: {typed_in}')
+        self.redraw_affected()
+
     def cmd__prompt_enter(self) -> None:
         'Get prompt content from .window.prompt.enter, parse to & run command.'
         to_parse = self.window.prompt.enter()
         print(msg, end='')
         self._cursor_yx = _YX(self._cursor_yx.y, end_x)
 
-    def _get_keypresses(self) -> Iterator[Optional[_KeyboardEvent]]:
+    def _get_keypresses(self) -> Iterator[Optional[TuiEvent]]:
         '''Loop through keypresses from terminal, expand blessed's handling.
 
         Explicitly collect KEY_ESCAPE-modified key sequences, and recognize
                             to_yield += c
                 else:
                     to_yield = 'esc:' + ':'.join([str(int(b)) for b in chars])
-            yield _KeyboardEvent(to_yield) if to_yield else None
+            yield (TuiEvent.make_subtype('handle_keyboard_event',
+                                         typed_in=to_yield)() if to_yield
+                   else None)