import sys,os import curses import logging def draw_menu(stdscr): k = 0 kw = "" kk = "" height, width = stdscr.getmaxyx() min_x_keystr = width - 1 min_x_wkeystr = width - 1 min_x_kkeystr = width - 1 cursor_x = 0 cursor_y = 0 if len(sys.argv) > 1: myarg = sys.argv[1].upper() else: myarg = "CWK" # Clear and refresh the screen for a blank canvas stdscr.clear() stdscr.refresh() stdscr.timeout(-1) # Set blocking read # Start colors in curses curses.start_color() curses.init_pair(1, curses.COLOR_CYAN, curses.COLOR_BLACK) curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK) curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_WHITE) # Loop where k is the last character pressed while (k != ord("q")): logging.debug("Loop top:k={},kw={},kk={}".format(k, kw, kk)) # Initialization if k == curses.KEY_RESIZE: stdscr.clear() stdscr.refresh() height, width = stdscr.getmaxyx() if k == curses.KEY_DOWN: cursor_y = cursor_y + 1 elif k == curses.KEY_UP: cursor_y = cursor_y - 1 elif k == curses.KEY_RIGHT: cursor_x = cursor_x + 1 elif k == curses.KEY_LEFT: cursor_x = cursor_x - 1 cursor_x = max(0, cursor_x) cursor_x = min(width-1, cursor_x) cursor_y = max(0, cursor_y) cursor_y = min(height-1, cursor_y) # Declaration of strings title = "Curses example"[:width-1] subtitle = "Written by Clay McLeod"[:width-1] try: ver_m, ver_n, ver_p = curses.ncurses_version except: ver_m, ver_n, ver_p = curses.version cversion = "Curses Version {}.{}.{}".format(ver_m, ver_n, ver_p) statusbarstr = "Press 'q' to exit | STATUS BAR | Pos: {}, {}".format(cursor_x, cursor_y) if "C" in myarg: if k <= 0: logging.debug("k <= 0") keystr = "No key press detected..."[:width-1] else: if k < 256: logging.debug("k < 256") keystr = "Last key pressed: {} = 0x{:02x}".format(k, k)[:width-1] else: logging.debug("k >= 256") keystr = "Last key pressed: {} = 0x{:04x}".format(k, k)[:width-1] else: logging.debug("Not doing getch()") keystr = "No key press detected..."[:width-1] if "W" in myarg: if isinstance(kw, str) and len(kw) < 1: logging.debug("kw == str('')") wkeystr = "No wide key press detected..."[:width-1] else: if isinstance(kw, str): logging.debug("kw == str({}),type({}),len=({})".format(kw, type(kw), len(kw))) if len(kw) == 1 and ord(kw) < 32: logging.debug("ord(kw) < 32") kw = curses.unctrl(kw).decode("utf-8", "backslashreplace") #xkw = [":".join("{}".format(hex(ord(c)) for c in kw))] xkw = "0x" for _c in kw: xkw += str(hex(ord(_c)))[2:] # int(_c.encode("utf-8", "backslashreplace"))) logging.debug("xkw == {}".format(xkw)) wkeystr = "Last wide key pressed: {} = {}".format( kw, xkw)[:width-1] else: logging.debug("kw != str({}),type({})".format(kw, type(kw))) wkeystr = "Last wide key pressed: {} = 0x{:04x}".format( kw, kw)[:width-1] else: logging.debug("Not doing get_wch()") wkeystr = "No wide key press detected..."[:width-1] if "K" in myarg: if isinstance(kk, str) and len(kk) < 1: logging.debug("kk == str('')") kkeystr = "No 'key' press detected..."[:width-1] else: if isinstance(kk, str): logging.debug("kk == str({}),type({}),len=({})".format(kk, type(kk), len(kk))) if len(kk) == 1 and ord(kk) < 32: logging.debug("ord(kk) < 32") kk = curses.unctrl(kk).decode("utf-8", "backslashreplace") #xkk = [":".join("{}".format(hex(ord(c)) for c in kk))] xkk = "0x" for _c in kk: xkk += str(hex(ord(_c)))[2:] # int(_c.encode("utf-8", "backslashreplace"))) logging.debug("xkk == {}".format(xkk)) kkeystr = "Last 'key' pressed: {} = {}".format( kk, xkk)[:width-1] else: logging.debug("kk != str({}),type({})".format(kk, type(kk))) kkeystr = "Last 'key' pressed: {} type({})".format( kk, type(kk))[:width-1] else: logging.debug("Not doing getkey()") kkeystr = "No 'key' press detected..."[:width-1] # Centering calculations start_x_title = int((width // 2) - (len(title) // 2) - len(title) % 2) start_x_subtitle = int((width // 2) - (len(subtitle) // 2) - len(subtitle) % 2) start_x_cversion = int((width // 2) - (len(cversion) // 2) - len(cversion) % 2) start_x_keystr = int((width // 2) - (len(keystr) // 2) - len(keystr) % 2) start_x_wkeystr = int((width // 2) - (len(wkeystr) // 2) - len(wkeystr) % 2) start_x_kkeystr = int((width // 2) - (len(kkeystr) // 2) - len(kkeystr) % 2) start_y = int((height // 2) - 2) min_x_keystr = min(min_x_keystr, start_x_keystr) min_x_wkeystr = min(min_x_wkeystr, start_x_wkeystr) min_x_kkeystr = min(min_x_kkeystr, start_x_kkeystr) # Rendering some text whstr = "Width: {}, Height: {}".format(width, height) stdscr.addstr(0, 0, whstr, curses.color_pair(1)) # Render status bar stdscr.attron(curses.color_pair(3)) stdscr.addstr(height-1, 0, statusbarstr) stdscr.addstr(height-1, len(statusbarstr), " " * (width - len(statusbarstr) - 1)) stdscr.attroff(curses.color_pair(3)) # Turning on attributes for title stdscr.attron(curses.color_pair(2)) stdscr.attron(curses.A_BOLD) # Rendering title stdscr.addstr(start_y, start_x_title, title) # Turning off attributes for title stdscr.attroff(curses.color_pair(2)) stdscr.attroff(curses.A_BOLD) # Print rest of text stdscr.addstr(start_y - 3, start_x_cversion, cversion) stdscr.addstr(start_y + 1, start_x_subtitle, subtitle) stdscr.addstr(start_y + 3, (width // 2) - 2, '-' * 4) stdscr.addstr(start_y + 5, start_x_keystr, keystr) stdscr.addstr(start_y + 7, start_x_wkeystr, wkeystr) stdscr.addstr(start_y + 9, start_x_kkeystr, kkeystr) stdscr.move(cursor_y, cursor_x) # Refresh the screen stdscr.refresh() # Reset key values and flush input k = kw = kk = -1 curses.flushinp() # Wait for next input if "C" in myarg: k = stdscr.getch() # Prepare to get wide-char version if k != -1: curses.ungetch(k) else: k = -1 # Get wide char version if "W" in myarg: try: kw = stdscr.get_wch() except: kw = "" # Prepare to get key version if kw != -1 and kw != "": curses.unget_wch(kw) if not "C" in myarg: if isinstance(kw, str): if len(kw) > 0: k = ord(kw[0]) else: k = -1 else: k = -1 else: pass else: kw = "" # Get key version if "K" in myarg: try: kk = stdscr.getkey() except: kk = "" if not "C" in myarg: if isinstance(kk, str): if len(kk) > 0: k = ord(kk[0]) else: k = -1 else: k = -1 else: pass else: kk = "" # Clear the keystroke text stdscr.move(start_y + 5, min_x_keystr) stdscr.clrtoeol() stdscr.move(start_y + 7, min_x_wkeystr) stdscr.clrtoeol() stdscr.move(start_y + 9, min_x_kkeystr) stdscr.clrtoeol() stdscr.refresh() def main(): curses.wrapper(draw_menu) if __name__ == "__main__": try: os.remove("pycurses4.log") except: pass logging.basicConfig(filename="pycurses4.log", level=logging.DEBUG) main()