tuikit/driver_curses.py
changeset 65 5f0697950f15
parent 57 911927edbdde
child 66 824a9837bbb3
equal deleted inserted replaced
64:03f591f5fe5c 65:5f0697950f15
     7 
     7 
     8 from tuikit.driver import Driver
     8 from tuikit.driver import Driver
     9 
     9 
    10 
    10 
    11 class DriverCurses(Driver):
    11 class DriverCurses(Driver):
    12     xterm_codes = (
    12     key_codes = (
    13         (0x09,                      'tab'           ),
    13         (0x09,                      'tab'           ),
    14         (0x0a,                      'enter'         ),
    14         (0x0a,                      'enter'         ),
    15         (0x7f,                      'backspace'     ),
    15         (0x7f,                      'backspace'     ),
    16         (0x1b,                      'escape'        ),
    16         (0x1b,                      'escape'        ),
    17         (0x1b,0x4f,0x50,            'f1'            ),
    17         (0x1b,0x4f,0x50,            'f1'            ),  # xterm
    18         (0x1b,0x4f,0x51,            'f2'            ),
    18         (0x1b,0x4f,0x51,            'f2'            ),  # xterm
    19         (0x1b,0x4f,0x52,            'f3'            ),
    19         (0x1b,0x4f,0x52,            'f3'            ),  # xterm
    20         (0x1b,0x4f,0x53,            'f4'            ),
    20         (0x1b,0x4f,0x53,            'f4'            ),  # xterm
    21         (0x1b,0x5b,0x31,0x35,0x7e,  'f5'            ),
    21         (0x1b,0x5b,                 'CSI'           ),  # see csi_codes
    22         (0x1b,0x5b,0x31,0x37,0x7e,  'f6'            ),
    22     )
    23         (0x1b,0x5b,0x31,0x38,0x7e,  'f7'            ),
    23 
    24         (0x1b,0x5b,0x31,0x39,0x7e,  'f8'            ),
    24     # http://en.wikipedia.org/wiki/ANSI_escape_code
    25         (0x1b,0x5b,0x31,0x7e,       'home'          ),  # linux
    25     csi_codes = (
    26         (0x1b,0x5b,0x32,0x30,0x7e,  'f9'            ),
    26         # code            param     key name
    27         (0x1b,0x5b,0x32,0x31,0x7e,  'f10'           ),
    27         (0x7e,              1,      'home'          ),  # linux
    28         (0x1b,0x5b,0x32,0x33,0x7e,  'f11'           ),
    28         (0x7e,              2,      'insert'        ),
    29         (0x1b,0x5b,0x32,0x34,0x7e,  'f12'           ),
    29         (0x7e,              3,      'delete'        ),
    30         (0x1b,0x5b,0x32,0x7e,       'insert'        ),
    30         (0x7e,              4,      'end'           ),  # linux
    31         (0x1b,0x5b,0x33,0x7e,       'delete'        ),
    31         (0x7e,              5,      'pageup'        ),
    32         (0x1b,0x5b,0x34,0x7e,       'end'           ),  # linux
    32         (0x7e,              6,      'pagedown'      ),
    33         (0x1b,0x5b,0x35,0x7e,       'pageup'        ),
    33         (0x7e,              15,     'f5'            ),
    34         (0x1b,0x5b,0x36,0x7e,       'pagedown'      ),
    34         (0x7e,              17,     'f6'            ),
    35         (0x1b,0x5b,0x41,            'up'            ),
    35         (0x7e,              18,     'f7'            ),
    36         (0x1b,0x5b,0x42,            'down'          ),
    36         (0x7e,              19,     'f8'            ),
    37         (0x1b,0x5b,0x43,            'right'         ),
    37         (0x7e,              20,     'f9'            ),
    38         (0x1b,0x5b,0x44,            'left'          ),
    38         (0x7e,              21,     'f10'           ),
    39         (0x1b,0x5b,0x46,            'end'           ),
    39         (0x7e,              23,     'f11'           ),
    40         (0x1b,0x5b,0x48,            'home'          ),
    40         (0x7e,              24,     'f12'           ),
    41         (0x1b,0x5b,0x4d,            'mouse'         ),
    41         (0x41,              1,      'up'            ),
    42         (0x1b,0x5b,0x5b,0x41,       'f1'            ),  # linux
    42         (0x42,              1,      'down'          ),
    43         (0x1b,0x5b,0x5b,0x42,       'f2'            ),  # linux
    43         (0x43,              1,      'right'         ),
    44         (0x1b,0x5b,0x5b,0x43,       'f3'            ),  # linux
    44         (0x44,              1,      'left'          ),
    45         (0x1b,0x5b,0x5b,0x44,       'f4'            ),  # linux
    45         (0x46,              1,      'end'           ),  # xterm
    46         (0x1b,0x5b,0x5b,0x45,       'f5'            ),  # linux
    46         (0x48,              1,      'home'          ),  # xterm
       
    47         (0x4d,              None,   'mouse'         ),
       
    48         (0x5b,0x41,         1,      'f1'            ),  # linux
       
    49         (0x5b,0x42,         1,      'f2'            ),  # linux
       
    50         (0x5b,0x43,         1,      'f3'            ),  # linux
       
    51         (0x5b,0x44,         1,      'f4'            ),  # linux
       
    52         (0x5b,0x45,         1,      'f5'            ),  # linux
    47     )
    53     )
    48 
    54 
    49     color_map = {
    55     color_map = {
    50         'black'   : curses.COLOR_BLACK,
    56         'black'   : curses.COLOR_BLACK,
    51         'blue'    : curses.COLOR_BLUE,
    57         'blue'    : curses.COLOR_BLUE,
   278 
   284 
   279             elif curses.ascii.isprint(c):
   285             elif curses.ascii.isprint(c):
   280                 res += [('keypress', None, str(chr(c)))]
   286                 res += [('keypress', None, str(chr(c)))]
   281 
   287 
   282             else:
   288             else:
   283                 #self.top.keypress(None, unicode(chr(c)))
       
   284                 self.inputqueue_unget(c)
   289                 self.inputqueue_unget(c)
   285                 res += self.process_control_chars()
   290                 res += self.process_control_chars()
   286 
   291 
   287         return res
   292         return res
   288 
   293 
   326                 continue
   331                 continue
   327         raise Exception('Invalid UTF-8 sequence: %r' % utf)
   332         raise Exception('Invalid UTF-8 sequence: %r' % utf)
   328 
   333 
   329 
   334 
   330     def process_control_chars(self):
   335     def process_control_chars(self):
   331         codes = self.xterm_codes
   336         codes = self.key_codes
   332         matchingcodes = []
   337         matchingcodes = []
   333         match = None
   338         match = None
   334         consumed = []
   339         consumed = []
   335 
   340 
   336         # consume next char, filter out matching codes
   341         # consume next char, filter out matching codes
   377         if match is None:
   382         if match is None:
   378             self.log.debug('Unknown control sequence: %s',
   383             self.log.debug('Unknown control sequence: %s',
   379                 ','.join(['0x%x'%x for x in consumed]))
   384                 ','.join(['0x%x'%x for x in consumed]))
   380             return [('keypress', 'Unknown', None)]
   385             return [('keypress', 'Unknown', None)]
   381 
   386 
   382         if keyname == 'mouse':
   387         if keyname == 'CSI':
   383             return self.process_xterm_mouse()
   388             return self.process_control_sequence()
   384 
   389 
   385         return [('keypress', keyname, None)]
   390         return [('keypress', keyname, None)]
   386 
   391 
   387 
   392 
   388     def process_xterm_mouse(self):
   393     def process_xterm_mouse(self):
   411         else:
   416         else:
   412             raise Exception('Unknown mouse event: %x' % t)
   417             raise Exception('Unknown mouse event: %x' % t)
   413 
   418 
   414         return out
   419         return out
   415 
   420 
       
   421     def process_control_sequence(self):
       
   422         codes = self.csi_codes
       
   423         debug_seq = [0x1b, 0x5b]
       
   424         c = self.inputqueue_get_wait()
       
   425         debug_seq.append(c)
       
   426 
       
   427         # numeric parameters?
       
   428         params = []
       
   429         if chr(c).isdigit():
       
   430             params.append(chr(c))
       
   431             while True:
       
   432                 c = self.inputqueue_get_wait()
       
   433                 debug_seq.append(c)
       
   434                 if chr(c).isdigit():
       
   435                     params[-1] += chr(c)
       
   436                 elif chr(c) == ';':
       
   437                     params.append('')
       
   438                 else:
       
   439                     break
       
   440         params = [int(x) for x in params]
       
   441         if len(params) == 0:
       
   442             params = [1]
       
   443 
       
   444         # filter codes using
       
   445         while True:
       
   446             matching_codes = []
       
   447             for code in codes:
       
   448                 if len(code) > 2 and code[0] == c:
       
   449                     matching_codes.append(code[1:])
       
   450             codes = matching_codes
       
   451 
       
   452             if len(codes) == 0:
       
   453                 # no match -> unknown code
       
   454                 seq = ','.join(['0x%x' % x for x in debug_seq])
       
   455                 self.log.debug('Unknown control sequence: %s', seq)
       
   456                 return [('keypress', 'Unknown:' + seq, None)]
       
   457             elif len(codes) == 1:
       
   458                 # one match -> we got the winner
       
   459                 break
       
   460             elif len(codes[0]) == 2:
       
   461                 # more than one matching, but no more chars to check
       
   462                 # will be sorted out using parameters
       
   463                 break
       
   464             else:
       
   465                 # more than one matching -> continue loop
       
   466                 c = self.inputqueue_get_wait()
       
   467                 debug_seq.append(c)
       
   468 
       
   469         # filter codes using first parameter
       
   470         matching_codes = []
       
   471         for code in codes:
       
   472             if params[0] == code[0] or params[0] is None:
       
   473                 matching_codes.append(code)
       
   474 
       
   475         if len(matching_codes) == 0:
       
   476             # no match -> unknown code
       
   477             seq = ','.join(['0x%x' % x for x in debug_seq])
       
   478             self.log.debug('Unknown control sequence: %s', seq)
       
   479             return [('keypress', 'Unknown:' + seq, None)]
       
   480 
       
   481         if len(matching_codes) > 1:
       
   482             raise Exception('Internal error: invalid csi_codes, more than one matching')
       
   483 
       
   484         keyname = matching_codes[0][1]
       
   485 
       
   486         if keyname == 'mouse':
       
   487             return self.process_xterm_mouse()
       
   488 
       
   489         # modifiers
       
   490         mod = 0
       
   491         if len(params) > 1:
       
   492             mod = params[1] - 1
       
   493 
       
   494         return [('keypress', keyname, None, mod)]
       
   495 
   416 
   496 
   417 driverclass = DriverCurses
   497 driverclass = DriverCurses
   418 
   498