📄 curses_display.py
字号:
of keys pressed. If raw_keys is True this function will return a ( keys pressed, raw keycodes ) tuple instead. Examples of keys returned ------------------------- ASCII printable characters: " ", "a", "0", "A", "-", "/" ASCII control characters: "tab", "enter" Escape sequences: "up", "page up", "home", "insert", "f1" Key combinations: "shift f1", "meta a", "ctrl b" Window events: "window resize" When a narrow encoding is not enabled "Extended ASCII" characters: "\\xa1", "\\xb2", "\\xfe" When a wide encoding is enabled Double-byte characters: "\\xa1\\xea", "\\xb2\\xd4" When utf8 encoding is enabled Unicode characters: u"\\u00a5", u'\\u253c" Examples of mouse events returned --------------------------------- Mouse button press: ('mouse press', 1, 15, 13), ('meta mouse press', 2, 17, 23) Mouse button release: ('mouse release', 0, 18, 13), ('ctrl mouse release', 0, 17, 23) """ assert self._started keys, raw = self._get_input( self.max_tenths ) # Avoid pegging CPU at 100% when slowly resizing, and work # around a bug with some braindead curses implementations that # return "no key" between "window resize" commands if keys==['window resize'] and self.prev_input_resize: while True: keys, raw2 = self._get_input(self.resize_tenths) raw += raw2 if not keys: keys, raw2 = self._get_input( self.resize_tenths) raw += raw2 if keys!=['window resize']: break if keys[-1:]!=['window resize']: keys.append('window resize') if keys==['window resize']: self.prev_input_resize = 2 elif self.prev_input_resize == 2 and not keys: self.prev_input_resize = 1 else: self.prev_input_resize = 0 if raw_keys: return keys, raw return keys def _get_input(self, wait_tenths): # this works around a strange curses bug with window resizing # not being reported correctly with repeated calls to this # function without a doupdate call in between curses.doupdate() key = self._getch(wait_tenths) resize = False raw = [] keys = [] while key >= 0: raw.append(key) if key==KEY_RESIZE: resize = True elif key==KEY_MOUSE: keys += self._encode_mouse_event() else: keys.append(key) key = self._getch_nodelay() processed = [] try: while keys: run, keys = escape.process_keyqueue(keys, True) processed += run except escape.MoreInputRequired: key = self._getch(self.complete_tenths) while key >= 0: raw.append(key) if key==KEY_RESIZE: resize = True elif key==KEY_MOUSE: keys += self._encode_mouse_event() else: keys.append(key) key = self._getch_nodelay() while keys: run, keys = escape.process_keyqueue(keys, False) processed += run if resize: processed.append('window resize') return processed, raw def _encode_mouse_event(self): # convert to escape sequence last = next = self.last_bstate (id,x,y,z,bstate) = curses.getmouse() mod = 0 if bstate & curses.BUTTON_SHIFT: mod |= 4 if bstate & curses.BUTTON_ALT: mod |= 8 if bstate & curses.BUTTON_CTRL: mod |= 16 l = [] def append_button( b ): b |= mod l.extend([ 27, ord('['), ord('M'), b+32, x+33, y+33 ]) if bstate & curses.BUTTON1_PRESSED and last & 1 == 0: append_button( 0 ) next |= 1 if bstate & curses.BUTTON2_PRESSED and last & 2 == 0: append_button( 1 ) next |= 2 if bstate & curses.BUTTON3_PRESSED and last & 4 == 0: append_button( 2 ) next |= 4 if bstate & curses.BUTTON4_PRESSED and last & 8 == 0: append_button( 64 ) next |= 8 if bstate & curses.BUTTON1_RELEASED and last & 1: append_button( 0 + escape.MOUSE_RELEASE_FLAG ) next &= ~ 1 if bstate & curses.BUTTON2_RELEASED and last & 2: append_button( 1 + escape.MOUSE_RELEASE_FLAG ) next &= ~ 2 if bstate & curses.BUTTON3_RELEASED and last & 4: append_button( 2 + escape.MOUSE_RELEASE_FLAG ) next &= ~ 4 if bstate & curses.BUTTON4_RELEASED and last & 8: append_button( 64 + escape.MOUSE_RELEASE_FLAG ) next &= ~ 8 self.last_bstate = next return l def _dbg_instr(self): # messy input string (intended for debugging) curses.echo() self.s.nodelay(0) curses.halfdelay(100) str = self.s.getstr() curses.noecho() return str def _dbg_out(self,str): # messy output function (intended for debugging) self.s.clrtoeol() self.s.addstr(str) self.s.refresh() self._curs_set(1) def _dbg_query(self,question): # messy query (intended for debugging) self._dbg_out(question) return self._dbg_instr() def _dbg_refresh(self): self.s.refresh() def get_cols_rows(self): """Return the terminal dimensions (num columns, num rows).""" rows,cols = self.s.getmaxyx() return cols,rows def _setattr(self, a): if a is None: self.s.attrset( 0 ) return if not self.attrconv.has_key(a): raise Exception, "Attribute %s not registered!"%`a` self.s.attrset( self.attrconv[a] ) def draw_screen(self, (cols, rows), r ): """Paint screen with rendered canvas.""" assert self._started assert r.rows() == rows, "canvas size and passed size don't match" y = -1 for row in r.content(): y += 1 try: self.s.move( y, 0 ) except _curses.error: # terminal shrunk? # move failed so stop rendering. return first = True lasta = None nr = 0 for a, cs, seg in row: seg = seg.translate( _trans_table ) if first or lasta != a: self._setattr(a) lasta = a try: if cs == "0": for i in range(len(seg)): self.s.addch( 0x400000 + ord(seg[i]) ) else: assert cs is None self.s.addstr( seg ) except _curses.error: # it's ok to get out of the # screen on the lower right if (y == rows-1 and nr == len(row)-1): pass else: # perhaps screen size changed # quietly abort. return nr += 1 if r.cursor is not None: x,y = r.cursor self._curs_set(1) try: self.s.move(y,x) except _curses.error: pass else: self._curs_set(0) self.s.move(0,0) self.s.refresh() self.keep_cache_alive_link = r def clear(self): """ Force the screen to be completely repainted on the next call to draw_screen(). """ self.s.clear()class _test: def __init__(self): self.ui = Screen() self.l = _curses_colours.keys() self.l.sort() for c in self.l: self.ui.register_palette( [ (c+" on black", c, 'black', 'underline'), (c+" on dark blue",c, 'dark blue', 'bold'), (c+" on light gray",c,'light gray', 'standout'), ]) self.ui.run_wrapper(self.run) def run(self): class FakeRender: pass r = FakeRender() text = [" has_color = "+`self.ui.has_color`,""] attr = [[],[]] r.coords = {} r.cursor = None for c in self.l: t = "" a = [] for p in c+" on black",c+" on dark blue",c+" on light gray": a.append((p,27)) t=t+ (p+27*" ")[:27] text.append( t ) attr.append( a ) text += ["","return values from get_input(): (q exits)", ""] attr += [[],[],[]] cols,rows = self.ui.get_cols_rows() keys = None while keys!=['q']: r.text=([t.ljust(cols) for t in text]+[""]*rows)[:rows] r.attr=(attr+[[]]*rows) [:rows] self.ui.draw_screen((cols,rows),r) keys, raw = self.ui.get_input( raw_keys = True ) if 'window resize' in keys: cols, rows = self.ui.get_cols_rows() if not keys: continue t = "" a = [] for k in keys: if type(k) == type(u""): k = k.encode("utf-8") t += "'"+k + "' " a += [(None,1), ('yellow on dark blue',len(k)), (None,2)] text.append(t + ": "+ `raw`) attr.append(a) text = text[-rows:] attr = attr[-rows:] if '__main__'==__name__: _test()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -