| """Reimplementation of the standard extension module '_curses' using cffi.""" | |
| import sys | |
| from functools import wraps | |
| from _curses_cffi import ffi, lib | |
| def _copy_to_globals(name): | |
| globals()[name] = getattr(lib, name) | |
| def _setup(): | |
| for name in ['ERR', 'OK', 'KEY_MIN', 'KEY_MAX', | |
| 'A_ATTRIBUTES', 'A_NORMAL', 'A_STANDOUT', 'A_UNDERLINE', | |
| 'A_REVERSE', 'A_BLINK', 'A_DIM', 'A_BOLD', 'A_ALTCHARSET', | |
| 'A_PROTECT', 'A_CHARTEXT', 'A_COLOR', | |
| 'COLOR_BLACK', 'COLOR_RED', 'COLOR_GREEN', 'COLOR_YELLOW', | |
| 'COLOR_BLUE', 'COLOR_MAGENTA', 'COLOR_CYAN', 'COLOR_WHITE', | |
| ]: | |
| _copy_to_globals(name) | |
| if not lib._m_NetBSD: | |
| _copy_to_globals('A_INVIS') | |
| for name in ['A_HORIZONTAL', 'A_LEFT', 'A_LOW', 'A_RIGHT', 'A_TOP', | |
| 'A_VERTICAL', | |
| ]: | |
| if hasattr(lib, name): | |
| _copy_to_globals(name) | |
| if lib._m_NCURSES_MOUSE_VERSION: | |
| for name in ["BUTTON1_PRESSED", "BUTTON1_RELEASED", "BUTTON1_CLICKED", | |
| "BUTTON1_DOUBLE_CLICKED", "BUTTON1_TRIPLE_CLICKED", | |
| "BUTTON2_PRESSED", "BUTTON2_RELEASED", "BUTTON2_CLICKED", | |
| "BUTTON2_DOUBLE_CLICKED", "BUTTON2_TRIPLE_CLICKED", | |
| "BUTTON3_PRESSED", "BUTTON3_RELEASED", "BUTTON3_CLICKED", | |
| "BUTTON3_DOUBLE_CLICKED", "BUTTON3_TRIPLE_CLICKED", | |
| "BUTTON4_PRESSED", "BUTTON4_RELEASED", "BUTTON4_CLICKED", | |
| "BUTTON4_DOUBLE_CLICKED", "BUTTON4_TRIPLE_CLICKED", | |
| "BUTTON_SHIFT", "BUTTON_CTRL", "BUTTON_ALT", | |
| "ALL_MOUSE_EVENTS", "REPORT_MOUSE_POSITION", | |
| ]: | |
| _copy_to_globals(name) | |
| if not lib._m_NetBSD: | |
| for key in range(lib.KEY_MIN, lib.KEY_MAX): | |
| key_n = lib.keyname(key) | |
| if key_n == ffi.NULL: | |
| continue | |
| key_n = ffi.string(key_n) | |
| if key_n == b"UNKNOWN KEY": | |
| continue | |
| if not isinstance(key_n, str): # python 3 | |
| key_n = key_n.decode() | |
| key_n = key_n.replace('(', '').replace(')', '') | |
| globals()[key_n] = key | |
| _setup() | |
| # Do we want this? | |
| # version = "2.2" | |
| # __version__ = "2.2" | |
| # ____________________________________________________________ | |
| _initialised_setupterm = False | |
| _initialised = False | |
| _initialised_color = False | |
| def _ensure_initialised_setupterm(): | |
| if not _initialised_setupterm: | |
| raise error("must call (at least) setupterm() first") | |
| def _ensure_initialised(): | |
| if not _initialised: | |
| raise error("must call initscr() first") | |
| def _ensure_initialised_color(): | |
| if not _initialised and _initialised_color: | |
| raise error("must call start_color() first") | |
| def _check_ERR(code, fname): | |
| if code != lib.ERR: | |
| return None | |
| elif fname is None: | |
| raise error("curses function returned ERR") | |
| else: | |
| raise error("%s() returned ERR" % (fname,)) | |
| def _check_NULL(rval): | |
| if rval == ffi.NULL: | |
| raise error("curses function returned NULL") | |
| return rval | |
| def _call_lib(method_name, *args): | |
| return getattr(lib, method_name)(*args) | |
| def _call_lib_check_ERR(method_name, *args): | |
| return _check_ERR(_call_lib(method_name, *args), method_name) | |
| def _mk_no_return(method_name): | |
| def _execute(): | |
| _ensure_initialised() | |
| return _call_lib_check_ERR(method_name) | |
| _execute.__name__ = method_name | |
| return _execute | |
| def _mk_flag_func(method_name): | |
| # This is in the CPython implementation, but not documented anywhere. | |
| # We have to support it, though, even if it make me sad. | |
| def _execute(flag=True): | |
| _ensure_initialised() | |
| if flag: | |
| return _call_lib_check_ERR(method_name) | |
| else: | |
| return _call_lib_check_ERR('no' + method_name) | |
| _execute.__name__ = method_name | |
| return _execute | |
| def _mk_return_val(method_name): | |
| def _execute(): | |
| return _call_lib(method_name) | |
| _execute.__name__ = method_name | |
| return _execute | |
| def _mk_w_getyx(method_name): | |
| def _execute(self): | |
| y = _call_lib(method_name + 'y', self._win) | |
| x = _call_lib(method_name + 'x', self._win) | |
| return (y, x) | |
| _execute.__name__ = method_name | |
| return _execute | |
| def _mk_w_no_return(method_name): | |
| def _execute(self, *args): | |
| return _call_lib_check_ERR(method_name, self._win, *args) | |
| _execute.__name__ = method_name | |
| return _execute | |
| def _mk_w_return_val(method_name): | |
| def _execute(self, *args): | |
| return _call_lib(method_name, self._win, *args) | |
| _execute.__name__ = method_name | |
| return _execute | |
| def _chtype(ch): | |
| return int(ffi.cast("chtype", ch)) | |
| def _texttype(text): | |
| if isinstance(text, str): | |
| return text | |
| elif isinstance(text, unicode): | |
| return str(text) # default encoding | |
| else: | |
| raise TypeError("str or unicode expected, got a '%s' object" | |
| % (type(text).__name__,)) | |
| def _extract_yx(args): | |
| if len(args) >= 2: | |
| return (args[0], args[1], args[2:]) | |
| return (None, None, args) | |
| def _process_args(funcname, args, count, optcount, frontopt=0): | |
| outargs = [] | |
| if frontopt: | |
| if len(args) > count + optcount: | |
| # We have the front optional args here. | |
| outargs.extend(args[:frontopt]) | |
| args = args[frontopt:] | |
| else: | |
| # No front optional args, so make them None. | |
| outargs.extend([None] * frontopt) | |
| if (len(args) < count) or (len(args) > count + optcount): | |
| raise error("%s requires %s to %s arguments" % ( | |
| funcname, count, count + optcount + frontopt)) | |
| outargs.extend(args) | |
| return outargs | |
| def _argspec(count, optcount=0, frontopt=0): | |
| def _argspec_deco(func): | |
| @wraps(func) | |
| def _wrapped(self, *args): | |
| outargs = _process_args( | |
| func.__name__, args, count, optcount, frontopt) | |
| return func(self, *outargs) | |
| return _wrapped | |
| return _argspec_deco | |
| # ____________________________________________________________ | |
| class error(Exception): | |
| pass | |
| class Window(object): | |
| def __init__(self, window): | |
| self._win = window | |
| def __del__(self): | |
| if self._win != lib.stdscr: | |
| lib.delwin(self._win) | |
| untouchwin = _mk_w_no_return("untouchwin") | |
| touchwin = _mk_w_no_return("touchwin") | |
| redrawwin = _mk_w_no_return("redrawwin") | |
| insertln = _mk_w_no_return("winsertln") | |
| erase = _mk_w_no_return("werase") | |
| deleteln = _mk_w_no_return("wdeleteln") | |
| is_wintouched = _mk_w_return_val("is_wintouched") | |
| syncdown = _mk_w_return_val("wsyncdown") | |
| syncup = _mk_w_return_val("wsyncup") | |
| standend = _mk_w_return_val("wstandend") | |
| standout = _mk_w_return_val("wstandout") | |
| cursyncup = _mk_w_return_val("wcursyncup") | |
| clrtoeol = _mk_w_return_val("wclrtoeol") | |
| clrtobot = _mk_w_return_val("wclrtobot") | |
| clear = _mk_w_return_val("wclear") | |
| idcok = _mk_w_no_return("idcok") | |
| immedok = _mk_w_no_return("immedok") | |
| timeout = _mk_w_no_return("wtimeout") | |
| getyx = _mk_w_getyx("getcur") | |
| getbegyx = _mk_w_getyx("getbeg") | |
| getmaxyx = _mk_w_getyx("getmax") | |
| getparyx = _mk_w_getyx("getpar") | |
| clearok = _mk_w_no_return("clearok") | |
| idlok = _mk_w_no_return("idlok") | |
| leaveok = _mk_w_no_return("leaveok") | |
| notimeout = _mk_w_no_return("notimeout") | |
| scrollok = _mk_w_no_return("scrollok") | |
| insdelln = _mk_w_no_return("winsdelln") | |
| syncok = _mk_w_no_return("syncok") | |
| mvwin = _mk_w_no_return("mvwin") | |
| mvderwin = _mk_w_no_return("mvderwin") | |
| move = _mk_w_no_return("wmove") | |
| if not lib._m_STRICT_SYSV_CURSES: | |
| resize = _mk_w_no_return("wresize") | |
| if lib._m_NetBSD: | |
| keypad = _mk_w_return_val("keypad") | |
| nodelay = _mk_w_return_val("nodelay") | |
| else: | |
| keypad = _mk_w_no_return("keypad") | |
| nodelay = _mk_w_no_return("nodelay") | |
| @_argspec(1, 1, 2) | |
| def addch(self, y, x, ch, attr=None): | |
| if attr is None: | |
| attr = lib.A_NORMAL | |
| ch = _chtype(ch) | |
| if y is not None: | |
| code = lib.mvwaddch(self._win, y, x, ch | attr) | |
| else: | |
| code = lib.waddch(self._win, ch | attr) | |
| return _check_ERR(code, "addch") | |
| @_argspec(1, 1, 2) | |
| def addstr(self, y, x, text, attr=None): | |
| text = _texttype(text) | |
| if attr is not None: | |
| attr_old = lib.getattrs(self._win) | |
| lib.wattrset(self._win, attr) | |
| if y is not None: | |
| code = lib.mvwaddstr(self._win, y, x, text) | |
| else: | |
| code = lib.waddstr(self._win, text) | |
| if attr is not None: | |
| lib.wattrset(self._win, attr_old) | |
| return _check_ERR(code, "addstr") | |
| @_argspec(2, 1, 2) | |
| def addnstr(self, y, x, text, n, attr=None): | |
| text = _texttype(text) | |
| if attr is not None: | |
| attr_old = lib.getattrs(self._win) | |
| lib.wattrset(self._win, attr) | |
| if y is not None: | |
| code = lib.mvwaddnstr(self._win, y, x, text, n) | |
| else: | |
| code = lib.waddnstr(self._win, text, n) | |
| if attr is not None: | |
| lib.wattrset(self._win, attr_old) | |
| return _check_ERR(code, "addnstr") | |
| def bkgd(self, ch, attr=None): | |
| if attr is None: | |
| attr = lib.A_NORMAL | |
| return _check_ERR(lib.wbkgd(self._win, _chtype(ch) | attr), "bkgd") | |
| attroff = _mk_w_no_return("wattroff") | |
| attron = _mk_w_no_return("wattron") | |
| attrset = _mk_w_no_return("wattrset") | |
| def bkgdset(self, ch, attr=None): | |
| if attr is None: | |
| attr = lib.A_NORMAL | |
| lib.wbkgdset(self._win, _chtype(ch) | attr) | |
| return None | |
| def border(self, ls=0, rs=0, ts=0, bs=0, tl=0, tr=0, bl=0, br=0): | |
| lib.wborder(self._win, | |
| _chtype(ls), _chtype(rs), _chtype(ts), _chtype(bs), | |
| _chtype(tl), _chtype(tr), _chtype(bl), _chtype(br)) | |
| return None | |
| def box(self, vertint=0, horint=0): | |
| lib.box(self._win, vertint, horint) | |
| return None | |
| @_argspec(1, 1, 2) | |
| def chgat(self, y, x, num, attr=None): | |
| # These optional args are in a weird order. | |
| if attr is None: | |
| attr = num | |
| num = -1 | |
| color = ((attr >> 8) & 0xff) | |
| attr = attr - (color << 8) | |
| if y is not None: | |
| code = lib.mvwchgat(self._win, y, x, num, attr, color, ffi.NULL) | |
| lib.touchline(self._win, y, 1) | |
| else: | |
| yy, _ = self.getyx() | |
| code = lib.wchgat(self._win, num, attr, color, ffi.NULL) | |
| lib.touchline(self._win, yy, 1) | |
| return _check_ERR(code, "chgat") | |
| def delch(self, *args): | |
| if len(args) == 0: | |
| code = lib.wdelch(self._win) | |
| elif len(args) == 2: | |
| code = lib.mvwdelch(self._win, *args) | |
| else: | |
| raise error("delch requires 0 or 2 arguments") | |
| return _check_ERR(code, "[mv]wdelch") | |
| def derwin(self, *args): | |
| nlines = 0 | |
| ncols = 0 | |
| if len(args) == 2: | |
| begin_y, begin_x = args | |
| elif len(args) == 4: | |
| nlines, ncols, begin_y, begin_x = args | |
| else: | |
| raise error("derwin requires 2 or 4 arguments") | |
| win = lib.derwin(self._win, nlines, ncols, begin_y, begin_x) | |
| return Window(_check_NULL(win)) | |
| def echochar(self, ch, attr=None): | |
| if attr is None: | |
| attr = lib.A_NORMAL | |
| ch = _chtype(ch) | |
| if lib._m_ispad(self._win): | |
| code = lib.pechochar(self._win, ch | attr) | |
| else: | |
| code = lib.wechochar(self._win, ch | attr) | |
| return _check_ERR(code, "echochar") | |
| if lib._m_NCURSES_MOUSE_VERSION: | |
| enclose = _mk_w_return_val("wenclose") | |
| getbkgd = _mk_w_return_val("getbkgd") | |
| def getch(self, *args): | |
| if len(args) == 0: | |
| val = lib.wgetch(self._win) | |
| elif len(args) == 2: | |
| val = lib.mvwgetch(self._win, *args) | |
| else: | |
| raise error("getch requires 0 or 2 arguments") | |
| return val | |
| def getkey(self, *args): | |
| if len(args) == 0: | |
| val = lib.wgetch(self._win) | |
| elif len(args) == 2: | |
| val = lib.mvwgetch(self._win, *args) | |
| else: | |
| raise error("getkey requires 0 or 2 arguments") | |
| if val == lib.ERR: | |
| raise error("no input") | |
| elif val <= 255: | |
| return chr(val) | |
| else: | |
| # XXX: The following line is different if `__NetBSD__` is defined. | |
| val = lib.keyname(val) | |
| if val == ffi.NULL: | |
| return "" | |
| return ffi.string(val) | |
| @_argspec(0, 1, 2) | |
| def getstr(self, y, x, n=1023): | |
| n = min(n, 1023) | |
| buf = ffi.new("char[1024]") # /* This should be big enough.. I hope */ | |
| if y is None: | |
| val = lib.wgetnstr(self._win, buf, n) | |
| else: | |
| val = lib.mvwgetnstr(self._win, y, x, buf, n) | |
| if val == lib.ERR: | |
| return "" | |
| return ffi.string(buf) | |
| @_argspec(2, 1, 2) | |
| def hline(self, y, x, ch, n, attr=None): | |
| ch = _chtype(ch) | |
| if attr is None: | |
| attr = lib.A_NORMAL | |
| if y is not None: | |
| _check_ERR(lib.wmove(self._win, y, x), "wmove") | |
| return _check_ERR(lib.whline(self._win, ch | attr, n), "hline") | |
| @_argspec(1, 1, 2) | |
| def insch(self, y, x, ch, attr=None): | |
| ch = _chtype(ch) | |
| if attr is None: | |
| attr = lib.A_NORMAL | |
| if y is not None: | |
| code = lib.mvwinsch(self._win, y, x, ch | attr) | |
| else: | |
| code = lib.winsch(self._win, ch | attr) | |
| return _check_ERR(code, "insch") | |
| def inch(self, *args): | |
| if len(args) == 0: | |
| return lib.winch(self._win) | |
| elif len(args) == 2: | |
| return lib.mvwinch(self._win, *args) | |
| else: | |
| raise error("inch requires 0 or 2 arguments") | |
| @_argspec(0, 1, 2) | |
| def instr(self, y, x, n=1023): | |
| n = min(n, 1023) | |
| buf = ffi.new("char[1024]") # /* This should be big enough.. I hope */ | |
| if y is None: | |
| code = lib.winnstr(self._win, buf, n) | |
| else: | |
| code = lib.mvwinnstr(self._win, y, x, buf, n) | |
| if code == lib.ERR: | |
| return "" | |
| return ffi.string(buf) | |
| @_argspec(1, 1, 2) | |
| def insstr(self, y, x, text, attr=None): | |
| text = _texttype(text) | |
| if attr is not None: | |
| attr_old = lib.getattrs(self._win) | |
| lib.wattrset(self._win, attr) | |
| if y is not None: | |
| code = lib.mvwinsstr(self._win, y, x, text) | |
| else: | |
| code = lib.winsstr(self._win, text) | |
| if attr is not None: | |
| lib.wattrset(self._win, attr_old) | |
| return _check_ERR(code, "insstr") | |
| @_argspec(2, 1, 2) | |
| def insnstr(self, y, x, text, n, attr=None): | |
| text = _texttype(text) | |
| if attr is not None: | |
| attr_old = lib.getattrs(self._win) | |
| lib.wattrset(self._win, attr) | |
| if y is not None: | |
| code = lib.mvwinsnstr(self._win, y, x, text, n) | |
| else: | |
| code = lib.winsnstr(self._win, text, n) | |
| if attr is not None: | |
| lib.wattrset(self._win, attr_old) | |
| return _check_ERR(code, "insnstr") | |
| def is_linetouched(self, line): | |
| code = lib.is_linetouched(self._win, line) | |
| if code == lib.ERR: | |
| raise error("is_linetouched: line number outside of boundaries") | |
| if code == lib.FALSE: | |
| return False | |
| return True | |
| def noutrefresh(self, *args): | |
| if lib._m_ispad(self._win): | |
| if len(args) != 6: | |
| raise error( | |
| "noutrefresh() called for a pad requires 6 arguments") | |
| return _check_ERR(lib.pnoutrefresh(self._win, *args), | |
| "pnoutrefresh") | |
| else: | |
| # XXX: Better args check here? We need zero args. | |
| return _check_ERR(lib.wnoutrefresh(self._win, *args), | |
| "wnoutrefresh") | |
| nooutrefresh = noutrefresh # "to be removed in 2.3", but in 2.7, 3.x. | |
| def _copywin(self, dstwin, overlay, | |
| sminr, sminc, dminr, dminc, dmaxr, dmaxc): | |
| return _check_ERR(lib.copywin(self._win, dstwin._win, | |
| sminr, sminc, dminr, dminc, dmaxr, dmaxc, | |
| overlay), "copywin") | |
| def overlay(self, dstwin, *args): | |
| if len(args) == 6: | |
| return self._copywin(dstwin, True, *args) | |
| elif len(args) == 0: | |
| return _check_ERR(lib.overlay(self._win, dstwin._win), "overlay") | |
| else: | |
| raise error("overlay requires one or seven arguments") | |
| def overwrite(self, dstwin, *args): | |
| if len(args) == 6: | |
| return self._copywin(dstwin, False, *args) | |
| elif len(args) == 0: | |
| return _check_ERR(lib.overwrite(self._win, dstwin._win), | |
| "overwrite") | |
| else: | |
| raise error("overwrite requires one or seven arguments") | |
| def putwin(self, filep): | |
| # filestar = ffi.new("FILE *", filep) | |
| return _check_ERR(lib.putwin(self._win, filep), "putwin") | |
| def redrawln(self, beg, num): | |
| return _check_ERR(lib.wredrawln(self._win, beg, num), "redrawln") | |
| def refresh(self, *args): | |
| if lib._m_ispad(self._win): | |
| if len(args) != 6: | |
| raise error( | |
| "noutrefresh() called for a pad requires 6 arguments") | |
| return _check_ERR(lib.prefresh(self._win, *args), "prefresh") | |
| else: | |
| # XXX: Better args check here? We need zero args. | |
| return _check_ERR(lib.wrefresh(self._win, *args), "wrefresh") | |
| def setscrreg(self, y, x): | |
| return _check_ERR(lib.wsetscrreg(self._win, y, x), "wsetscrreg") | |
| def subwin(self, *args): | |
| nlines = 0 | |
| ncols = 0 | |
| if len(args) == 2: | |
| begin_y, begin_x = args | |
| elif len(args) == 4: | |
| nlines, ncols, begin_y, begin_x = args | |
| else: | |
| raise error("subwin requires 2 or 4 arguments") | |
| if lib._m_ispad(self._win): | |
| win = lib.subpad(self._win, nlines, ncols, begin_y, begin_x) | |
| else: | |
| win = lib.subwin(self._win, nlines, ncols, begin_y, begin_x) | |
| return Window(_check_NULL(win)) | |
| def scroll(self, nlines=None): | |
| if nlines is None: | |
| return _check_ERR(lib.scroll(self._win), "scroll") | |
| else: | |
| return _check_ERR(lib.wscrl(self._win, nlines), "scroll") | |
| def touchline(self, st, cnt, val=None): | |
| if val is None: | |
| return _check_ERR(lib.touchline(self._win, st, cnt), "touchline") | |
| else: | |
| return _check_ERR(lib.wtouchln(self._win, st, cnt, val), | |
| "touchline") | |
| @_argspec(2, 1, 2) | |
| def vline(self, y, x, ch, n, attr=None): | |
| ch = _chtype(ch) | |
| if attr is None: | |
| attr = lib.A_NORMAL | |
| if y is not None: | |
| _check_ERR(lib.wmove(self._win, y, x), "wmove") | |
| return _check_ERR(lib.wvline(self._win, ch | attr, n), "vline") | |
| beep = _mk_no_return("beep") | |
| def_prog_mode = _mk_no_return("def_prog_mode") | |
| def_shell_mode = _mk_no_return("def_shell_mode") | |
| doupdate = _mk_no_return("doupdate") | |
| endwin = _mk_no_return("endwin") | |
| flash = _mk_no_return("flash") | |
| nocbreak = _mk_no_return("nocbreak") | |
| noecho = _mk_no_return("noecho") | |
| nonl = _mk_no_return("nonl") | |
| noraw = _mk_no_return("noraw") | |
| reset_prog_mode = _mk_no_return("reset_prog_mode") | |
| reset_shell_mode = _mk_no_return("reset_shell_mode") | |
| resetty = _mk_no_return("resetty") | |
| savetty = _mk_no_return("savetty") | |
| cbreak = _mk_flag_func("cbreak") | |
| echo = _mk_flag_func("echo") | |
| nl = _mk_flag_func("nl") | |
| raw = _mk_flag_func("raw") | |
| baudrate = _mk_return_val("baudrate") | |
| termattrs = _mk_return_val("termattrs") | |
| termname = _mk_return_val("termname") | |
| longname = _mk_return_val("longname") | |
| can_change_color = _mk_return_val("can_change_color") | |
| has_colors = _mk_return_val("has_colors") | |
| has_ic = _mk_return_val("has_ic") | |
| has_il = _mk_return_val("has_il") | |
| isendwin = _mk_return_val("isendwin") | |
| flushinp = _mk_return_val("flushinp") | |
| noqiflush = _mk_return_val("noqiflush") | |
| def filter(): | |
| lib.filter() | |
| return None | |
| def color_content(color): | |
| _ensure_initialised_color() | |
| r, g, b = ffi.new("short *"), ffi.new("short *"), ffi.new("short *") | |
| if lib.color_content(color, r, g, b) == lib.ERR: | |
| raise error("Argument 1 was out of range. Check value of COLORS.") | |
| return (r[0], g[0], b[0]) | |
| def color_pair(n): | |
| _ensure_initialised_color() | |
| return (n << 8) | |
| def curs_set(vis): | |
| _ensure_initialised() | |
| val = lib.curs_set(vis) | |
| _check_ERR(val, "curs_set") | |
| return val | |
| def delay_output(ms): | |
| _ensure_initialised() | |
| return _check_ERR(lib.delay_output(ms), "delay_output") | |
| def erasechar(): | |
| _ensure_initialised() | |
| return lib.erasechar() | |
| def getsyx(): | |
| _ensure_initialised() | |
| yx = ffi.new("int[2]") | |
| lib._m_getsyx(yx) | |
| return (yx[0], yx[1]) | |
| if lib._m_NCURSES_MOUSE_VERSION: | |
| def getmouse(): | |
| _ensure_initialised() | |
| mevent = ffi.new("MEVENT *") | |
| _check_ERR(lib.getmouse(mevent), "getmouse") | |
| return (mevent.id, mevent.x, mevent.y, mevent.z, mevent.bstate) | |
| def ungetmouse(id, x, y, z, bstate): | |
| _ensure_initialised() | |
| mevent = ffi.new("MEVENT *") | |
| mevent.id, mevent.x, mevent.y, mevent.z, mevent.bstate = ( | |
| id, x, y, z, bstate) | |
| return _check_ERR(lib.ungetmouse(mevent), "ungetmouse") | |
| def getwin(filep): | |
| return Window(_check_NULL(lib.getwin(filep))) | |
| def halfdelay(tenths): | |
| _ensure_initialised() | |
| return _check_ERR(lib.halfdelay(tenths), "halfdelay") | |
| if not lib._m_STRICT_SYSV_CURSES: | |
| def has_key(ch): | |
| _ensure_initialised() | |
| return lib.has_key(ch) | |
| def init_color(color, r, g, b): | |
| _ensure_initialised_color() | |
| return _check_ERR(lib.init_color(color, r, g, b), "init_color") | |
| def init_pair(pair, f, b): | |
| _ensure_initialised_color() | |
| return _check_ERR(lib.init_pair(pair, f, b), "init_pair") | |
| def _mk_acs(name, ichar): | |
| if len(ichar) == 1: | |
| globals()[name] = lib.acs_map[ord(ichar)] | |
| else: | |
| globals()[name] = globals()[ichar] | |
| def _map_acs(): | |
| _mk_acs("ACS_ULCORNER", 'l') | |
| _mk_acs("ACS_LLCORNER", 'm') | |
| _mk_acs("ACS_URCORNER", 'k') | |
| _mk_acs("ACS_LRCORNER", 'j') | |
| _mk_acs("ACS_LTEE", 't') | |
| _mk_acs("ACS_RTEE", 'u') | |
| _mk_acs("ACS_BTEE", 'v') | |
| _mk_acs("ACS_TTEE", 'w') | |
| _mk_acs("ACS_HLINE", 'q') | |
| _mk_acs("ACS_VLINE", 'x') | |
| _mk_acs("ACS_PLUS", 'n') | |
| _mk_acs("ACS_S1", 'o') | |
| _mk_acs("ACS_S9", 's') | |
| _mk_acs("ACS_DIAMOND", '`') | |
| _mk_acs("ACS_CKBOARD", 'a') | |
| _mk_acs("ACS_DEGREE", 'f') | |
| _mk_acs("ACS_PLMINUS", 'g') | |
| _mk_acs("ACS_BULLET", '~') | |
| _mk_acs("ACS_LARROW", ',') | |
| _mk_acs("ACS_RARROW", '+') | |
| _mk_acs("ACS_DARROW", '.') | |
| _mk_acs("ACS_UARROW", '-') | |
| _mk_acs("ACS_BOARD", 'h') | |
| _mk_acs("ACS_LANTERN", 'i') | |
| _mk_acs("ACS_BLOCK", '0') | |
| _mk_acs("ACS_S3", 'p') | |
| _mk_acs("ACS_S7", 'r') | |
| _mk_acs("ACS_LEQUAL", 'y') | |
| _mk_acs("ACS_GEQUAL", 'z') | |
| _mk_acs("ACS_PI", '{') | |
| _mk_acs("ACS_NEQUAL", '|') | |
| _mk_acs("ACS_STERLING", '}') | |
| _mk_acs("ACS_BSSB", "ACS_ULCORNER") | |
| _mk_acs("ACS_SSBB", "ACS_LLCORNER") | |
| _mk_acs("ACS_BBSS", "ACS_URCORNER") | |
| _mk_acs("ACS_SBBS", "ACS_LRCORNER") | |
| _mk_acs("ACS_SBSS", "ACS_RTEE") | |
| _mk_acs("ACS_SSSB", "ACS_LTEE") | |
| _mk_acs("ACS_SSBS", "ACS_BTEE") | |
| _mk_acs("ACS_BSSS", "ACS_TTEE") | |
| _mk_acs("ACS_BSBS", "ACS_HLINE") | |
| _mk_acs("ACS_SBSB", "ACS_VLINE") | |
| _mk_acs("ACS_SSSS", "ACS_PLUS") | |
| def initscr(): | |
| if _initialised: | |
| lib.wrefresh(lib.stdscr) | |
| return Window(lib.stdscr) | |
| win = _check_NULL(lib.initscr()) | |
| globals()['_initialised_setupterm'] = True | |
| globals()['_initialised'] = True | |
| _map_acs() | |
| globals()["LINES"] = lib.LINES | |
| globals()["COLS"] = lib.COLS | |
| return Window(win) | |
| def setupterm(term=None, fd=-1): | |
| if fd == -1: | |
| # XXX: Check for missing stdout here? | |
| fd = sys.stdout.fileno() | |
| if _initialised_setupterm: | |
| return None | |
| if term is None: | |
| term = ffi.NULL | |
| err = ffi.new("int *") | |
| if lib.setupterm(term, fd, err) == lib.ERR: | |
| err = err[0] | |
| if err == 0: | |
| raise error("setupterm: could not find terminal") | |
| elif err == -1: | |
| raise error("setupterm: could not find terminfo database") | |
| else: | |
| raise error("setupterm: unknown error") | |
| globals()["_initialised_setupterm"] = True | |
| return None | |
| def intrflush(ch): | |
| _ensure_initialised() | |
| return _check_ERR(lib.intrflush(ffi.NULL, ch), "intrflush") | |
| # XXX: #ifdef HAVE_CURSES_IS_TERM_RESIZED | |
| def is_term_resized(lines, columns): | |
| _ensure_initialised() | |
| return lib.is_term_resized(lines, columns) | |
| if not lib._m_NetBSD: | |
| def keyname(ch): | |
| _ensure_initialised() | |
| if ch < 0: | |
| raise error("invalid key number") | |
| knp = lib.keyname(ch) | |
| if knp == ffi.NULL: | |
| return "" | |
| return ffi.string(knp) | |
| def killchar(): | |
| return lib.killchar() | |
| def meta(ch): | |
| return _check_ERR(lib.meta(lib.stdscr, ch), "meta") | |
| if lib._m_NCURSES_MOUSE_VERSION: | |
| def mouseinterval(interval): | |
| _ensure_initialised() | |
| return _check_ERR(lib.mouseinterval(interval), "mouseinterval") | |
| def mousemask(newmask): | |
| _ensure_initialised() | |
| oldmask = ffi.new("mmask_t *") | |
| availmask = lib.mousemask(newmask, oldmask) | |
| return (availmask, oldmask) | |
| def napms(ms): | |
| _ensure_initialised() | |
| return lib.napms(ms) | |
| def newpad(nlines, ncols): | |
| _ensure_initialised() | |
| return Window(_check_NULL(lib.newpad(nlines, ncols))) | |
| def newwin(nlines, ncols, begin_y=None, begin_x=None): | |
| _ensure_initialised() | |
| if begin_x is None: | |
| if begin_y is not None: | |
| raise error("newwin requires 2 or 4 arguments") | |
| begin_y = begin_x = 0 | |
| return Window(_check_NULL(lib.newwin(nlines, ncols, begin_y, begin_x))) | |
| def pair_content(pair): | |
| _ensure_initialised_color() | |
| f = ffi.new("short *") | |
| b = ffi.new("short *") | |
| if lib.pair_content(pair, f, b) == lib.ERR: | |
| raise error("Argument 1 was out of range. (1..COLOR_PAIRS-1)") | |
| return (f, b) | |
| def pair_number(pairvalue): | |
| _ensure_initialised_color() | |
| return (pairvalue & lib.A_COLOR) >> 8 | |
| def putp(text): | |
| text = _texttype(text) | |
| return _check_ERR(lib.putp(text), "putp") | |
| def qiflush(flag=True): | |
| _ensure_initialised() | |
| if flag: | |
| lib.qiflush() | |
| else: | |
| lib.noqiflush() | |
| return None | |
| # XXX: Do something about the following? | |
| # /* Internal helper used for updating curses.LINES, curses.COLS, _curses.LINES | |
| # * and _curses.COLS */ | |
| # #if defined(HAVE_CURSES_RESIZETERM) || defined(HAVE_CURSES_RESIZE_TERM) | |
| # static int | |
| # update_lines_cols(void) | |
| # { | |
| # PyObject *o; | |
| # PyObject *m = PyImport_ImportModuleNoBlock("curses"); | |
| # if (!m) | |
| # return 0; | |
| # o = PyInt_FromLong(LINES); | |
| # if (!o) { | |
| # Py_DECREF(m); | |
| # return 0; | |
| # } | |
| # if (PyObject_SetAttrString(m, "LINES", o)) { | |
| # Py_DECREF(m); | |
| # Py_DECREF(o); | |
| # return 0; | |
| # } | |
| # if (PyDict_SetItemString(ModDict, "LINES", o)) { | |
| # Py_DECREF(m); | |
| # Py_DECREF(o); | |
| # return 0; | |
| # } | |
| # Py_DECREF(o); | |
| # o = PyInt_FromLong(COLS); | |
| # if (!o) { | |
| # Py_DECREF(m); | |
| # return 0; | |
| # } | |
| # if (PyObject_SetAttrString(m, "COLS", o)) { | |
| # Py_DECREF(m); | |
| # Py_DECREF(o); | |
| # return 0; | |
| # } | |
| # if (PyDict_SetItemString(ModDict, "COLS", o)) { | |
| # Py_DECREF(m); | |
| # Py_DECREF(o); | |
| # return 0; | |
| # } | |
| # Py_DECREF(o); | |
| # Py_DECREF(m); | |
| # return 1; | |
| # } | |
| # #endif | |
| # #ifdef HAVE_CURSES_RESIZETERM | |
| # static PyObject * | |
| # PyCurses_ResizeTerm(PyObject *self, PyObject *args) | |
| # { | |
| # int lines; | |
| # int columns; | |
| # PyObject *result; | |
| # PyCursesInitialised; | |
| # if (!PyArg_ParseTuple(args,"ii:resizeterm", &lines, &columns)) | |
| # return NULL; | |
| # result = PyCursesCheckERR(resizeterm(lines, columns), "resizeterm"); | |
| # if (!result) | |
| # return NULL; | |
| # if (!update_lines_cols()) | |
| # return NULL; | |
| # return result; | |
| # } | |
| # #endif | |
| # #ifdef HAVE_CURSES_RESIZE_TERM | |
| # static PyObject * | |
| # PyCurses_Resize_Term(PyObject *self, PyObject *args) | |
| # { | |
| # int lines; | |
| # int columns; | |
| # PyObject *result; | |
| # PyCursesInitialised; | |
| # if (!PyArg_ParseTuple(args,"ii:resize_term", &lines, &columns)) | |
| # return NULL; | |
| # result = PyCursesCheckERR(resize_term(lines, columns), "resize_term"); | |
| # if (!result) | |
| # return NULL; | |
| # if (!update_lines_cols()) | |
| # return NULL; | |
| # return result; | |
| # } | |
| # #endif /* HAVE_CURSES_RESIZE_TERM */ | |
| def setsyx(y, x): | |
| _ensure_initialised() | |
| lib.setsyx(y, x) | |
| return None | |
| def start_color(): | |
| _check_ERR(lib.start_color(), "start_color") | |
| globals()["COLORS"] = lib.COLORS | |
| globals()["COLOR_PAIRS"] = lib.COLOR_PAIRS | |
| globals()["_initialised_color"] = True | |
| return None | |
| def tigetflag(capname): | |
| _ensure_initialised_setupterm() | |
| return lib.tigetflag(capname) | |
| def tigetnum(capname): | |
| _ensure_initialised_setupterm() | |
| return lib.tigetnum(capname) | |
| def tigetstr(capname): | |
| _ensure_initialised_setupterm() | |
| val = lib.tigetstr(capname) | |
| if int(ffi.cast("intptr_t", val)) in (0, -1): | |
| return None | |
| return ffi.string(val) | |
| def tparm(fmt, i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0, i8=0, i9=0): | |
| args = [ffi.cast("int", i) for i in (i1, i2, i3, i4, i5, i6, i7, i8, i9)] | |
| result = lib.tparm(fmt, *args) | |
| if result == ffi.NULL: | |
| raise error("tparm() returned NULL") | |
| return ffi.string(result) | |
| def typeahead(fd): | |
| _ensure_initialised() | |
| return _check_ERR(lib.typeahead(fd), "typeahead") | |
| def unctrl(ch): | |
| _ensure_initialised() | |
| return lib.unctrl(_chtype(ch)) | |
| def ungetch(ch): | |
| _ensure_initialised() | |
| return _check_ERR(lib.ungetch(_chtype(ch)), "ungetch") | |
| def use_env(flag): | |
| lib.use_env(flag) | |
| return None | |
| if not lib._m_STRICT_SYSV_CURSES: | |
| def use_default_colors(): | |
| _ensure_initialised_color() | |
| return _check_ERR(lib.use_default_colors(), "use_default_colors") |