# HG changeset patch # User Radek Brich # Date 1358898623 -3600 # Node ID 5f0697950f1505a3375dff51724d4486f46ff1cd # Parent 03f591f5fe5cd1642eb8e7453ce2dc1aa1c23599 DriverCurses: Add support for key modifiers. diff -r 03f591f5fe5c -r 5f0697950f15 tests/curses_keycodes.py --- a/tests/curses_keycodes.py Sun Jan 20 00:49:19 2013 +0100 +++ b/tests/curses_keycodes.py Wed Jan 23 00:50:23 2013 +0100 @@ -14,14 +14,19 @@ curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION) while True: c = screen.getch() + s = '' screen.nodelay(1) while c != -1: + try: + s += chr(c) + except ValueError: + s += '?' screen.addstr('0x%02x,' % c) c = screen.getch() screen.nodelay(0) - screen.addstr('\n') + screen.addstr(' %r\n' % s) screen.refresh() diff -r 03f591f5fe5c -r 5f0697950f15 tuikit/driver_curses.py --- a/tuikit/driver_curses.py Sun Jan 20 00:49:19 2013 +0100 +++ b/tuikit/driver_curses.py Wed Jan 23 00:50:23 2013 +0100 @@ -9,41 +9,47 @@ class DriverCurses(Driver): - xterm_codes = ( + key_codes = ( (0x09, 'tab' ), (0x0a, 'enter' ), (0x7f, 'backspace' ), (0x1b, 'escape' ), - (0x1b,0x4f,0x50, 'f1' ), - (0x1b,0x4f,0x51, 'f2' ), - (0x1b,0x4f,0x52, 'f3' ), - (0x1b,0x4f,0x53, 'f4' ), - (0x1b,0x5b,0x31,0x35,0x7e, 'f5' ), - (0x1b,0x5b,0x31,0x37,0x7e, 'f6' ), - (0x1b,0x5b,0x31,0x38,0x7e, 'f7' ), - (0x1b,0x5b,0x31,0x39,0x7e, 'f8' ), - (0x1b,0x5b,0x31,0x7e, 'home' ), # linux - (0x1b,0x5b,0x32,0x30,0x7e, 'f9' ), - (0x1b,0x5b,0x32,0x31,0x7e, 'f10' ), - (0x1b,0x5b,0x32,0x33,0x7e, 'f11' ), - (0x1b,0x5b,0x32,0x34,0x7e, 'f12' ), - (0x1b,0x5b,0x32,0x7e, 'insert' ), - (0x1b,0x5b,0x33,0x7e, 'delete' ), - (0x1b,0x5b,0x34,0x7e, 'end' ), # linux - (0x1b,0x5b,0x35,0x7e, 'pageup' ), - (0x1b,0x5b,0x36,0x7e, 'pagedown' ), - (0x1b,0x5b,0x41, 'up' ), - (0x1b,0x5b,0x42, 'down' ), - (0x1b,0x5b,0x43, 'right' ), - (0x1b,0x5b,0x44, 'left' ), - (0x1b,0x5b,0x46, 'end' ), - (0x1b,0x5b,0x48, 'home' ), - (0x1b,0x5b,0x4d, 'mouse' ), - (0x1b,0x5b,0x5b,0x41, 'f1' ), # linux - (0x1b,0x5b,0x5b,0x42, 'f2' ), # linux - (0x1b,0x5b,0x5b,0x43, 'f3' ), # linux - (0x1b,0x5b,0x5b,0x44, 'f4' ), # linux - (0x1b,0x5b,0x5b,0x45, 'f5' ), # linux + (0x1b,0x4f,0x50, 'f1' ), # xterm + (0x1b,0x4f,0x51, 'f2' ), # xterm + (0x1b,0x4f,0x52, 'f3' ), # xterm + (0x1b,0x4f,0x53, 'f4' ), # xterm + (0x1b,0x5b, 'CSI' ), # see csi_codes + ) + + # http://en.wikipedia.org/wiki/ANSI_escape_code + csi_codes = ( + # code param key name + (0x7e, 1, 'home' ), # linux + (0x7e, 2, 'insert' ), + (0x7e, 3, 'delete' ), + (0x7e, 4, 'end' ), # linux + (0x7e, 5, 'pageup' ), + (0x7e, 6, 'pagedown' ), + (0x7e, 15, 'f5' ), + (0x7e, 17, 'f6' ), + (0x7e, 18, 'f7' ), + (0x7e, 19, 'f8' ), + (0x7e, 20, 'f9' ), + (0x7e, 21, 'f10' ), + (0x7e, 23, 'f11' ), + (0x7e, 24, 'f12' ), + (0x41, 1, 'up' ), + (0x42, 1, 'down' ), + (0x43, 1, 'right' ), + (0x44, 1, 'left' ), + (0x46, 1, 'end' ), # xterm + (0x48, 1, 'home' ), # xterm + (0x4d, None, 'mouse' ), + (0x5b,0x41, 1, 'f1' ), # linux + (0x5b,0x42, 1, 'f2' ), # linux + (0x5b,0x43, 1, 'f3' ), # linux + (0x5b,0x44, 1, 'f4' ), # linux + (0x5b,0x45, 1, 'f5' ), # linux ) color_map = { @@ -280,7 +286,6 @@ res += [('keypress', None, str(chr(c)))] else: - #self.top.keypress(None, unicode(chr(c))) self.inputqueue_unget(c) res += self.process_control_chars() @@ -328,7 +333,7 @@ def process_control_chars(self): - codes = self.xterm_codes + codes = self.key_codes matchingcodes = [] match = None consumed = [] @@ -379,8 +384,8 @@ ','.join(['0x%x'%x for x in consumed])) return [('keypress', 'Unknown', None)] - if keyname == 'mouse': - return self.process_xterm_mouse() + if keyname == 'CSI': + return self.process_control_sequence() return [('keypress', keyname, None)] @@ -413,6 +418,81 @@ return out + def process_control_sequence(self): + codes = self.csi_codes + debug_seq = [0x1b, 0x5b] + c = self.inputqueue_get_wait() + debug_seq.append(c) + + # numeric parameters? + params = [] + if chr(c).isdigit(): + params.append(chr(c)) + while True: + c = self.inputqueue_get_wait() + debug_seq.append(c) + if chr(c).isdigit(): + params[-1] += chr(c) + elif chr(c) == ';': + params.append('') + else: + break + params = [int(x) for x in params] + if len(params) == 0: + params = [1] + + # filter codes using + while True: + matching_codes = [] + for code in codes: + if len(code) > 2 and code[0] == c: + matching_codes.append(code[1:]) + codes = matching_codes + + if len(codes) == 0: + # no match -> unknown code + seq = ','.join(['0x%x' % x for x in debug_seq]) + self.log.debug('Unknown control sequence: %s', seq) + return [('keypress', 'Unknown:' + seq, None)] + elif len(codes) == 1: + # one match -> we got the winner + break + elif len(codes[0]) == 2: + # more than one matching, but no more chars to check + # will be sorted out using parameters + break + else: + # more than one matching -> continue loop + c = self.inputqueue_get_wait() + debug_seq.append(c) + + # filter codes using first parameter + matching_codes = [] + for code in codes: + if params[0] == code[0] or params[0] is None: + matching_codes.append(code) + + if len(matching_codes) == 0: + # no match -> unknown code + seq = ','.join(['0x%x' % x for x in debug_seq]) + self.log.debug('Unknown control sequence: %s', seq) + return [('keypress', 'Unknown:' + seq, None)] + + if len(matching_codes) > 1: + raise Exception('Internal error: invalid csi_codes, more than one matching') + + keyname = matching_codes[0][1] + + if keyname == 'mouse': + return self.process_xterm_mouse() + + # modifiers + mod = 0 + if len(params) > 1: + mod = params[1] - 1 + + return [('keypress', keyname, None, mod)] + driverclass = DriverCurses diff -r 03f591f5fe5c -r 5f0697950f15 tuikit/events.py --- a/tuikit/events.py Sun Jan 20 00:49:19 2013 +0100 +++ b/tuikit/events.py Wed Jan 23 00:50:23 2013 +0100 @@ -48,13 +48,20 @@ class KeyboardEvent(Event): - def __init__(self, keyname, char): + + MOD_SHIFT = 1<<0 + MOD_ALT = 1<<1 + MOD_CTRL = 1<<2 + MOD_META = 1<<3 + + def __init__(self, keyname, char, mod=0): Event.__init__(self) self.keyname = keyname self.char = char + self.mod = mod def __repr__(self): - return 'KeyboardEvent(keyname={0.keyname},char={0.char})'.format(self) + return 'KeyboardEvent(keyname={0.keyname},char={0.char},mod={0.mod})'.format(self) class MouseEvent(Event): @@ -66,7 +73,7 @@ self.wy = y self.px = 0 # parent coordinates self.py = 0 - #: Mouse button: left=1, middle=2, right=3, wheelup=4 wheeldown=5 + #: Mouse button: left=1, middle=2, right=3, wheelup=4, wheeldown=5 self.button = button def make_child_event(self, container, child): diff -r 03f591f5fe5c -r 5f0697950f15 tuikit/layout.py --- a/tuikit/layout.py Sun Jan 20 00:49:19 2013 +0100 +++ b/tuikit/layout.py Wed Jan 23 00:50:23 2013 +0100 @@ -227,7 +227,7 @@ self._grid = [] rown = 0 coln = 0 - for child in self._getchildren(): + for child in self._get_children(): if coln == 0: row = [] for _i in range(self.numcols):