From 1e90590b0d2953f693459c2d4ed80613041c9d7e Mon Sep 17 00:00:00 2001 From: brliron Date: Tue, 28 Aug 2018 19:35:46 +0200 Subject: [PATCH 1/3] Add better input unicode support, and pass input to blocking mode. --- Discline.py | 2 ++ input/input_handler.py | 31 ++++++++------------- input/messageEdit.py | 19 +++++++------ ui/ui.py | 61 +++++++++++++++++------------------------- 4 files changed, 48 insertions(+), 65 deletions(-) diff --git a/Discline.py b/Discline.py index 36f4dcd..c39d62e 100755 --- a/Discline.py +++ b/Discline.py @@ -32,6 +32,8 @@ # Set terminal X11 window title print('\33]0;Discline\a', end='', flush=True) +# Set the timeout for the ESC key to 25ms +os.environ.setdefault('ESCDELAY', '25') gc.initClient() diff --git a/input/input_handler.py b/input/input_handler.py index b81fa12..0622496 100644 --- a/input/input_handler.py +++ b/input/input_handler.py @@ -20,21 +20,18 @@ def key_input(): editWin = gc.ui.editWin call = (ui.draw_edit_win, True) gc.ui_thread.funcs.append(call) - while call in gc.ui_thread.funcs or \ - call[0].__name__ in gc.ui_thread.locks: - time.sleep(0.01) while not gc.doExit: prompt = gc.client.prompt - ch = editWin.getch() - if ch == -1 or not gc.ui.displayPanel.hidden(): + ch = editWin.get_wch() + if not gc.ui.displayPanel.hidden(): time.sleep(0.01) continue - if chr(ch) != '\n' and len(gc.ui.messageEdit.inputBuffer) > 0 and \ - gc.ui.messageEdit.inputBuffer[0] != ord('/'): + if ch != '\n' and len(gc.ui.messageEdit.inputBuffer) > 0 and \ + gc.ui.messageEdit.inputBuffer[0] != '/': gc.typingBeingHandled = True # prevents crashes when enter is hit and input buf is empty - if chr(ch) == '\n' and not gc.ui.messageEdit.inputBuffer: + if ch == '\n' and not gc.ui.messageEdit.inputBuffer: continue if ch == curses.KEY_PPAGE: gc.ui.channel_log_offset -= settings["scroll_lines"] @@ -49,15 +46,10 @@ def key_input(): ui.draw_screen() continue # if ESC is pressed, clear messageEdit buffer - elif ch == 27: - ch = editWin.getch() - if ch in (0x7f, ord('\b'), curses.KEY_BACKSPACE): - gc.ui.messageEdit.reset() - call = (ui.draw_edit_win, True) - gc.ui_thread.funcs.append(call) - while call in gc.ui_thread.funcs or \ - call[0].__name__ in gc.ui_thread.locks: - time.sleep(0.01) + elif ch == chr(27): + gc.ui.messageEdit.reset() + call = (ui.draw_edit_win, True) + gc.ui_thread.funcs.append(call) continue ret = gc.ui.messageEdit.addKey(ch) if ret is not None: @@ -65,9 +57,6 @@ def key_input(): gc.ui.messageEdit.reset() call = (ui.draw_edit_win, True) gc.ui_thread.funcs.append(call) - while not gc.doExit and (call in gc.ui_thread.funcs or \ - call[0].__name__ in gc.ui_thread.locks): - time.sleep(0.01) log("key_input finished") gc.tasksExited += 1 @@ -152,6 +141,8 @@ def parseCommand(command, arg=None): elif command in ("quit", "exit"): try: gc.exit_thread.start() except SystemExit: pass + while not gc.doExit: + time.sleep(0.01) elif command in ("help", 'h'): ui.draw_help() elif command in ("guilds", "glds", "servers", "servs"): ui.draw_guildlist() elif command in ("channels", "chans"): ui.draw_channellist() diff --git a/input/messageEdit.py b/input/messageEdit.py index a2ec729..387adb6 100644 --- a/input/messageEdit.py +++ b/input/messageEdit.py @@ -1,16 +1,17 @@ import curses +from utils.log import log class MessageEdit: def __init__(self, termWidth): self.curPos = 0 self.startPos = 0 # relative to len(inputBuffer) self.termWidth = self.width = termWidth - self.inputBuffer = [] + self.inputBuffer = "" def reset(self): self.curPos = 0 self.startPos = 0 - del(self.inputBuffer[:]) + self.inputBuffer = "" def resize(self): pass @@ -19,7 +20,7 @@ def setPrompt(self, prompt): self.width = self.termWidth - (len(prompt) + 5) - 1 def getCurrentData(self): - return (bytearray(self.inputBuffer).decode("utf-8"), self.curPos, self.startPos) + return (self.inputBuffer, self.curPos, self.startPos) def addKey(self, ch): # check if character is function character @@ -44,17 +45,19 @@ def addKey(self, ch): # TODO: Implement edit last message on KEY_UP elif ch == curses.KEY_UP or ch == curses.KEY_DOWN: pass - elif ch in (0x7f, ord('\b'), curses.KEY_BACKSPACE): + elif ch in (chr(0x7f), '\b', curses.KEY_BACKSPACE): if self.curPos > 0: - self.inputBuffer.pop(self.curPos-1) + self.inputBuffer = self.inputBuffer[:self.curPos - 1] + self.inputBuffer[self.curPos:] self.curPos -= 1 if self.startPos > 0 and self.curPos == self.startPos: self.startPos -= 1 - elif ch == ord('\n'): - return bytearray(self.inputBuffer).decode("utf-8") + elif ch == '\n': + return self.inputBuffer + elif not isinstance(ch, str): + log("Unknown key " + str(ch)) # Normal text else: - self.inputBuffer.insert(self.curPos, ch) + self.inputBuffer = self.inputBuffer[:self.curPos] + ch + self.inputBuffer[self.curPos:] self.curPos += 1 if self.curPos-self.startPos > self.width: self.startPos += 1 diff --git a/ui/ui.py b/ui/ui.py index c1cdeb8..220682d 100755 --- a/ui/ui.py +++ b/ui/ui.py @@ -161,7 +161,6 @@ def makeBottomWin(self, resize=False): return content = curses.newwin(1,self.max_x, self.max_y-1,0) content.keypad(True) - content.nodelay(True) self.editWin = content self.contentWins.append(content) @@ -356,10 +355,9 @@ def set_display(string, attrs=0): display.addstr("(press q to quit this dialog)") display.refresh() while True: - ch = display.getch() - if ch == ord('q'): + ch = display.get_wch() + if ch == 'q': break - time.sleep(0.1) display.clear() gc.ui.toggleDisplay() draw_screen() @@ -504,10 +502,9 @@ def draw_guildlist(): if len(gc.client.guilds) == 0: display.addstr("Error: You are not in any guilds.", gc.ui.colors["red"]) while True: - ch = display.getch() - if ch == ord('q'): + ch = display.get_wch() + if ch == 'q': break - time.sleep(0.1) display.clear() gc.ui.toggleDisplay() return @@ -554,8 +551,8 @@ def draw_guildlist(): color = serv[1] display.addstr(2+serv_id,0, serv[0], color) display.addstr(2+serv_id+2,0, "(press q to quit this dialog)", gc.ui.colors["green"]) - ch = display.getch() - if ch == ord('q'): + ch = display.get_wch() + if ch == 'q': break if len(buf) > (gc.ui.max_y-5): if ch == curses.KEY_UP: @@ -566,7 +563,6 @@ def draw_guildlist(): line_offset = 0 elif len(buf) > (gc.ui.max_y-5) and line_offset > (len(buf)-(gc.ui.max_y-5)): line_offset = len(buf)-(gc.ui.max_y-5) - time.sleep(0.01) gc.ui.toggleDisplay() gc.ui.refreshAll() draw_screen() @@ -578,10 +574,9 @@ def draw_channellist(): if len(gc.client.guilds) == 0: display.addstr("Error: You are not in any guilds.", gc.ui.colors["red"]) while True: - ch = display.getch() - if ch == ord('q'): + ch = display.get_wch() + if ch == 'q': break - time.sleep(0.1) display.clear() gc.ui.toggleDisplay() return @@ -589,10 +584,9 @@ def draw_channellist(): if len(gc.client.current_guild.channels) == 0: display.addstr("Error: Does this guild not have any channels?", gc.ui.colors["red"]) while True: - ch = display.getch() - if ch == ord('q'): + ch = display.get_wch() + if ch == 'q': break - time.sleep(0.1) display.clear() gc.ui.toggleDisplay() return @@ -616,8 +610,8 @@ def draw_channellist(): color = chan[1] display.addstr(2+chan_id,0, chan[0], color) display.addstr(2+chan_id+2,0, "(press q to quit this dialog)", gc.ui.colors["green"]) - ch = display.getch() - if ch == ord('q'): + ch = display.get_wch() + if ch == 'q': break if len(buf) > (gc.ui.max_y-5): if ch == curses.KEY_UP: @@ -628,7 +622,6 @@ def draw_channellist(): line_offset = 0 elif len(buf) > (gc.ui.max_y-5) and line_offset > (len(buf)-(gc.ui.max_y-5)): line_offset = len(buf)-(gc.ui.max_y-5) - time.sleep(0.01) gc.ui.toggleDisplay() gc.ui.refreshAll() draw_screen() @@ -640,10 +633,9 @@ def draw_emojilist(): if len(gc.client.guilds) == 0: display.addstr("Error: You are not in any guilds.", gc.ui.colors["red"]) while True: - ch = display.getch() - if ch == ord('q'): + ch = display.get_wch() + if ch == 'q': break - time.sleep(0.1) display.clear() gc.ui.toggleDisplay() draw_screen() @@ -671,8 +663,8 @@ def draw_emojilist(): color = emoji[1] display.addstr(2+emoji_id,0, emoji[0], color) display.addstr(2+emoji_id+2,0, "(press q to quit this dialog)", gc.ui.colors["green"]) - ch = display.getch() - if ch == ord('q'): + ch = display.get_wch() + if ch == 'q': break if len(emojis) > (gc.ui.max_y-5): if ch == curses.KEY_UP: @@ -683,7 +675,6 @@ def draw_emojilist(): line_offset = 0 elif len(emojis) > (gc.ui.max_y-5) and line_offset > (len(emojis)-(gc.ui.max_y-5)): line_offset = len(emojis)-(gc.ui.max_y-5) - time.sleep(0.01) gc.ui.toggleDisplay() gc.ui.refreshAll() draw_screen() @@ -694,10 +685,9 @@ def draw_userlist(): if len(gc.client.guilds) == 0: display.addstr("Error: You are not in any guilds.", gc.ui.colors["red"]) while True: - ch = display.getch() - if ch == ord('q'): + ch = display.get_wch() + if ch == 'q': break - time.sleep(0.1) display.clear() gc.ui.toggleDisplay() draw_screen() @@ -706,10 +696,9 @@ def draw_userlist(): if len(gc.client.current_guild.channels) == 0: display.addstr("Error: Does this guild not have any channels?", gc.ui.colors["red"]) while True: - ch = display.getch() - if ch == ord('q'): + ch = display.get_wch() + if ch == 'q': break - time.sleep(0.1) display.clear() gc.ui.toggleDisplay() draw_screen() @@ -765,8 +754,8 @@ def draw_userlist(): color = user[1] display.addstr(2+user_id,0, user[0], color) display.addstr(2+user_id+2,0, "(press q to quit this dialog)", gc.ui.colors["green"]) - ch = display.getch() - if ch == ord('q'): + ch = display.get_wch() + if ch == 'q': break if len(buf) > (gc.ui.max_y-5): if ch == curses.KEY_UP: @@ -777,7 +766,6 @@ def draw_userlist(): line_offset = 0 elif len(buf) > (gc.ui.max_y-5) and line_offset > (len(buf)-(gc.ui.max_y-5)): line_offset = len(buf)-(gc.ui.max_y-5) - time.sleep(0.01) gc.ui.toggleDisplay() gc.ui.refreshAll() draw_screen() @@ -851,8 +839,8 @@ def draw_help(terminateAfter=False): display.addstr('-'*45, segment[1]) continue display.addstr(segment[0] + ' ', segment[1]) - ch = display.getch() - if ch == ord('q'): + ch = display.get_wch() + if ch == 'q': break if len(buf) > (gc.ui.max_y-5): if ch == curses.KEY_UP: @@ -867,7 +855,6 @@ def draw_help(terminateAfter=False): line_offset = 0 elif len(buf) > (gc.ui.max_y-5) and line_offset > (len(buf)-(gc.ui.max_y-5)): line_offset = len(buf)-(gc.ui.max_y-5) - time.sleep(0.01) if terminateAfter: raise SystemExit gc.ui.toggleDisplay() From 01d7d7bfbd2e0ff924418ab37935a56c565e550e Mon Sep 17 00:00:00 2001 From: brliron Date: Wed, 29 Aug 2018 11:01:11 +0200 Subject: [PATCH 2/3] Fix end key --- input/messageEdit.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/input/messageEdit.py b/input/messageEdit.py index 387adb6..b4f7c9c 100644 --- a/input/messageEdit.py +++ b/input/messageEdit.py @@ -32,6 +32,8 @@ def addKey(self, ch): # if inputBuffer fits into line self.curPos = len(self.inputBuffer) self.startPos = self.curPos - self.width + if self.startPos < 0: + self.startPos = 0 elif ch == curses.KEY_LEFT: # curPos is greater than 0 if self.curPos > 0: From bf118e399bca57fdd0d05d27fb0e5574981c282b Mon Sep 17 00:00:00 2001 From: brliron Date: Wed, 29 Aug 2018 11:14:43 +0200 Subject: [PATCH 3/3] Add support for del key --- input/messageEdit.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/input/messageEdit.py b/input/messageEdit.py index b4f7c9c..9fa8dc4 100644 --- a/input/messageEdit.py +++ b/input/messageEdit.py @@ -53,6 +53,9 @@ def addKey(self, ch): self.curPos -= 1 if self.startPos > 0 and self.curPos == self.startPos: self.startPos -= 1 + elif ch == curses.KEY_DC: + if self.curPos < len(self.inputBuffer): + self.inputBuffer = self.inputBuffer[:self.curPos] + self.inputBuffer[self.curPos + 1:] elif ch == '\n': return self.inputBuffer elif not isinstance(ch, str):