NewClientEvent)
 
 CMD_SHORTCUTS['disconnect'] = 'window.disconnect'
+CMD_SHORTCUTS['join'] = 'window.join'
 CMD_SHORTCUTS['nick'] = 'window.nick'
 CMD_SHORTCUTS['privmsg'] = 'window.privmsg'
 CMD_SHORTCUTS['reconnect'] = 'window.reconnect'
         'Attempt nickname change.'
         self._send_msg('NICK', (new_nick,))
 
+    def cmd__join(self, channel: str) -> None:
+        'Attempt joining a channel.'
+        self._send_msg('JOIN', (channel,))
+
     def cmd__privmsg(self, target: str, msg: str) -> None:
         'Send chat message msg to target.'
         self._send_msg('PRIVMSG', (target, msg), log_target=target, to_log=msg)
 class _PrivmsgWindow(_ClientWindow):
     prompt: _PrivmsgPromptWidget
 
-    def __init__(self, nickname: str, **kwargs) -> None:
-        self.nickname = nickname
+    def __init__(self, chatname: str, **kwargs) -> None:
+        self.chatname = chatname
         super().__init__(**kwargs)
-        self._title = f'{self.client_id} {self.nickname}'
+        self._title = f'{self.client_id} {self.chatname}'
 
     def cmd__chat(self, msg: str) -> None:
-        'PRIVMSG to target identified by .nickname.'
-        self.cmd__privmsg(target=self.nickname, msg=msg)
+        'PRIVMSG to target identified by .chatname.'
+        self.cmd__privmsg(target=self.chatname, msg=msg)
 
 
 @dataclass
         to_set = win.prompt.prefix_update_keys()
         win.prompt.update_prefix(**{k: getattr(self, k) for k in to_set})
 
-    def _new_win(self, scope: LogScope, nickname: str = '') -> _ClientWindow:
+    def _new_win(self, scope: LogScope, chatname: str = '') -> _ClientWindow:
         kwargs = {'scope': scope, 'log': self.log, 'win_cls': _ClientWindow}
         if scope == LogScope.CHAT:
             kwargs['win_cls'] = _PrivmsgWindow
-            kwargs['nickname'] = nickname
+            kwargs['chatname'] = chatname
         win = self._tui_new_window(**kwargs)
         if isinstance(win, _PrivmsgWindow):
             self._prompt_update(win)
         self.windows += [win]
         return win
 
-    def window(self, scope: LogScope, nickname: str = '') -> _ClientWindow:
+    def window(self, scope: LogScope, chatname: str = '') -> _ClientWindow:
         'Return client window of scope.'
         for win in [w for w in self.windows if w.scope == scope]:
             if scope == LogScope.CHAT:
                 if isinstance(win, _PrivmsgWindow)\
-                        and win.nickname == nickname:
+                        and win.chatname == chatname:
                     return win
                 continue
             return win
-        return self._new_win(scope=scope, nickname=nickname)
+        return self._new_win(scope=scope, chatname=chatname)
 
     def log(self, msg: str, scope: LogScope, **kwargs) -> None:
         'From parsing scope, kwargs, build prefix before sending to logger.'
         else:
             prefix += _LOG_PREFIX_SERVER
         if scope == LogScope.CHAT:
-            nickname = self.nickname if kwargs['out'] else kwargs['nickname']
+            nickname = self.nickname if kwargs['out'] else kwargs['sender']
             prefix += f' [{nickname}]'
         self._tui_log(msg, scope=scope, prefix=prefix, **kwargs)
 
             if target == LogScope.SERVER:
                 return [m.window(LogScope.SERVER), m.window(LogScope.RAW)]
             if target == LogScope.CHAT:
-                return [m.window(LogScope.CHAT, nickname=kwargs['nickname'])]
+                chatname = (kwargs['target'] if kwargs['out']
+                            else kwargs.get('channel', kwargs['sender']))
+                return [m.window(LogScope.CHAT, chatname=chatname)]
             return [m.window(target)]
         return super()._log_target_wins(**kwargs)