# HG changeset patch # User Radek Brich # Date 1300285145 -3600 # Node ID 33ec838dc02149ae5925f0c39ad2022052cbcd06 # Parent 684cdc3525624ba943a3498436b398d17723e794 Fixed escape sequence handling. diff -r 684cdc352562 -r 33ec838dc021 test_input.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test_input.py Wed Mar 16 15:19:05 2011 +0100 @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import locale +locale.setlocale(locale.LC_ALL, '') + +from tuikit import * + + +class MyApplication(Application): + def __init__(self): + Application.__init__(self) + self.top.connect('keypress', self.globalkeypress) + + self.text = '' + textedit = TextEdit(100, 40, self.text) + self.top.add(textedit) + textedit.x = 2 + self.textedit = textedit + + + def globalkeypress(self, keyname, char): + if char == 'q': + self.terminate() + self.text += 'keyname: %s char: %s\n' % (keyname, char) + self.textedit.settext(self.text) + self.textedit.scrolltoend() + + +if __name__ == '__main__': + app = MyApplication() + app.start() + diff -r 684cdc352562 -r 33ec838dc021 tuikit/backend_curses.py --- a/tuikit/backend_curses.py Tue Mar 15 17:27:09 2011 +0100 +++ b/tuikit/backend_curses.py Wed Mar 16 15:19:05 2011 +0100 @@ -255,7 +255,23 @@ ## input ## - def inputqueue_fill(self): + def inputqueue_fill(self, timeout=None): + if timeout is None: + # wait indefinitely + c = self.screen.getch() + self.inputqueue.insert(0, c) + + elif timeout > 0: + # wait + curses.halfdelay(timeout) + c = self.screen.getch() + curses.cbreak() + if c == -1: + return + self.inputqueue.insert(0, c) + + # timeout = 0 -> no wait + self.screen.nodelay(1) while True: @@ -267,51 +283,63 @@ self.screen.nodelay(0) - def inputqueue_next(self): + def inputqueue_top(self, num=0): + return self.inputqueue[-1-num] + + + def inputqueue_get(self): + c = None + try: + c = self.inputqueue.pop() + except IndexError: + pass + return c + + + def inputqueue_get_wait(self): c = None while c is None: try: c = self.inputqueue.pop() except IndexError: curses.napms(25) - self.inputqueue_fill() + self.inputqueue_fill(0) return c + def inputqueue_unget(self, c): + self.inputqueue.append(c) + + def process_input(self, timeout=None): - if len(self.inputqueue) > 0: - c = self.inputqueue_next() - else: - if not timeout is None: - curses.halfdelay(timeout) - c = self.screen.getch() - curses.cbreak() - if c == -1: - return [] - else: - c = self.screen.getch() + # empty queue -> fill + if len(self.inputqueue) == 0: + self.inputqueue_fill(timeout) - if c == curses.KEY_MOUSE: - return self.process_mouse() + res = [] + while len(self.inputqueue): + c = self.inputqueue_get() + + if c == curses.KEY_MOUSE: + res += self.process_mouse() - elif curses.ascii.isctrl(c): - self.inputqueue.append(c) - self.inputqueue_fill() - return self.process_control_chars() + elif curses.ascii.isctrl(c): + self.inputqueue_unget(c) + res += self.process_control_chars() + + elif c >= 192 and c <= 255: + self.inputqueue_unget(c) + res += self.process_utf8_chars() - elif c >= 192 and c <= 255: - self.inputqueue.append(c) - self.inputqueue_fill() - return self.process_utf8_chars() + elif curses.ascii.isprint(c): + res += [('keypress', None, str(chr(c)))] - elif curses.ascii.isprint(c): - return [('keypress', None, str(chr(c)))] + else: + #self.top.keypress(None, unicode(chr(c))) + self.inputqueue_unget(c) + res += self.process_control_chars() - else: - #self.top.keypress(None, unicode(chr(c))) - self.inputqueue.append(c) - self.inputqueue_fill() - return self.process_control_chars() + return res def process_mouse(self): @@ -346,7 +374,7 @@ #FIXME read exact number of chars as defined by utf-8 utf = '' while len(utf) <= 6: - c = self.inputqueue_next() + c = self.inputqueue_get_wait() utf += chr(c) try: uni = str(utf, 'utf-8') @@ -357,25 +385,56 @@ def process_control_chars(self): - keyname = None - for code in self.xterm_codes: - ok = False - if len(self.inputqueue) >= len(code) - 1: - ok = True - for i in range(len(code)-1): - if self.inputqueue[-i-1] != code[i]: - ok = False - break + codes = self.xterm_codes + matchingcodes = [] + match = None + consumed = [] + + # consume next char, filter out matching codes + c = self.inputqueue_get_wait() + consumed.append(c) + + while True: + self.log.debug('c=%s len=%s', c, len(codes)) + for code in codes: + if c == code[len(consumed)-1]: + if len(code) - 1 == len(consumed): + match = code + else: + matchingcodes += [code] + + self.log.debug('matching=%s', len(matchingcodes)) + + # match found, or no matching code found -> stop + if len(matchingcodes) == 0: + break - if ok: - keyname = code[-1] - self.inputqueue = self.inputqueue[:-len(code)+1] + # match found and some sequencies still match -> continue + if len(matchingcodes) > 0: + if len(self.inputqueue) == 0: + self.inputqueue_fill(1) + + c = self.inputqueue_get() + if c: + consumed.append(c) + codes = matchingcodes + matchingcodes = [] + else: + break - if keyname is None: + keyname = None + if match: + # compare match to consumed, return unused chars + l = len(match) - 1 + while len(consumed) > l: + self.inputqueue_unget(consumed[-1]) + del consumed[-1] + keyname = match[-1] + + if match is None: self.log.debug('Unknown control sequence: %s', - ','.join(reversed(['0x%x'%x for x in self.inputqueue]))) - c = self.inputqueue_next() - return [('keypress', 'Unknown%x' % c, None)] + ','.join(['0x%x'%x for x in consumed])) + return [('keypress', 'Unknown', None)] if keyname == 'mouse': return self.process_xterm_mouse() @@ -384,9 +443,9 @@ def process_xterm_mouse(self): - t = self.inputqueue_next() - x = self.inputqueue_next() - 0x21 - y = self.inputqueue_next() - 0x21 + t = self.inputqueue_get_wait() + x = self.inputqueue_get_wait() - 0x21 + y = self.inputqueue_get_wait() - 0x21 ev = MouseEvent(x, y) out = [] diff -r 684cdc352562 -r 33ec838dc021 tuikit/editbox.py --- a/tuikit/editbox.py Tue Mar 15 17:27:09 2011 +0100 +++ b/tuikit/editbox.py Wed Mar 16 15:19:05 2011 +0100 @@ -6,8 +6,6 @@ def __init__(self, width=20, height=20, text=''): Widget.__init__(self, width, height) - self.set_text(text) - self.xofs = 0 self.yofs = 0 @@ -26,6 +24,8 @@ self.newevent('scroll') self.newevent('areasize') + self.set_text(text) + def on_draw(self, screen, x, y): for j in range(self.height): @@ -98,6 +98,7 @@ def set_text(self, text): self.lines = text.split('\n') + self.handle('areasize') def get_text(self): @@ -115,10 +116,10 @@ def set_yofs(self, yofs): + if yofs > len(self.lines) - self.height: + yofs = len(self.lines) - self.height if yofs < 0: yofs = 0 - if yofs > len(self.lines) - self.height: - yofs = len(self.lines) - self.height self.yofs = yofs self.handle('scroll') @@ -183,6 +184,16 @@ self.set_yofs(self.cline) + def move_pagefirst(self): + self.cline = 0 + self.set_yofs(0) + + + def move_pagelast(self): + self.cline = len(self.lines) - 1 + self.set_yofs(self.cline) + + def add_char(self, c): ln = self.lines[self.cline] cpos = self.get_cpos() diff -r 684cdc352562 -r 33ec838dc021 tuikit/scrollbar.py --- a/tuikit/scrollbar.py Tue Mar 15 17:27:09 2011 +0100 +++ b/tuikit/scrollbar.py Wed Mar 16 15:19:05 2011 +0100 @@ -26,7 +26,9 @@ def setpos(self, pos): self.pos = pos - self.thumbpos = int(round(self.pos / self.max * (self.height - 3))) + self.thumbpos = 0 + if self.max and self.pos <= self.max: + self.thumbpos = int(round(self.pos / self.max * (self.height - 3))) def on_draw(self, screen, x, y): diff -r 684cdc352562 -r 33ec838dc021 tuikit/textedit.py --- a/tuikit/textedit.py Tue Mar 15 17:27:09 2011 +0100 +++ b/tuikit/textedit.py Wed Mar 16 15:19:05 2011 +0100 @@ -31,6 +31,10 @@ self.editbox.set_text(text) + def scrolltoend(self): + self.editbox.move_pagelast() + + def on_draw(self, screen, x, y): screen.frame(x, y, self.width, self.height) @@ -40,9 +44,13 @@ def on_editbox_areasize(self): - self.vscroll.max = len(self.editbox.lines) - self.editbox.height + smax = len(self.editbox.lines) - self.editbox.height + if smax < 0: + smax = 0 + self.vscroll.max = smax def on_vscroll_change(self): self.editbox.yofs = self.vscroll.pos self.editbox.redraw() +