1"""Reimplementation of the standard extension module '_curses' using cffi.""" 2 3import sys 4from functools import wraps 5 6from _curses_cffi import ffi, lib 7 8 9def _copy_to_globals(name): 10 globals()[name] = getattr(lib, name) 11 12 13def _setup(): 14 for name in ['ERR', 'OK', 'KEY_MIN', 'KEY_MAX', 15 'A_ATTRIBUTES', 'A_NORMAL', 'A_STANDOUT', 'A_UNDERLINE', 16 'A_REVERSE', 'A_BLINK', 'A_DIM', 'A_BOLD', 'A_ALTCHARSET', 17 'A_PROTECT', 'A_CHARTEXT', 'A_COLOR', 18 'COLOR_BLACK', 'COLOR_RED', 'COLOR_GREEN', 'COLOR_YELLOW', 19 'COLOR_BLUE', 'COLOR_MAGENTA', 'COLOR_CYAN', 'COLOR_WHITE', 20 ]: 21 _copy_to_globals(name) 22 23 if not lib._m_NetBSD: 24 _copy_to_globals('A_INVIS') 25 26 for name in ['A_HORIZONTAL', 'A_LEFT', 'A_LOW', 'A_RIGHT', 'A_TOP', 27 'A_VERTICAL', 28 ]: 29 if hasattr(lib, name): 30 _copy_to_globals(name) 31 32 if lib._m_NCURSES_MOUSE_VERSION: 33 for name in ["BUTTON1_PRESSED", "BUTTON1_RELEASED", "BUTTON1_CLICKED", 34 "BUTTON1_DOUBLE_CLICKED", "BUTTON1_TRIPLE_CLICKED", 35 "BUTTON2_PRESSED", "BUTTON2_RELEASED", "BUTTON2_CLICKED", 36 "BUTTON2_DOUBLE_CLICKED", "BUTTON2_TRIPLE_CLICKED", 37 "BUTTON3_PRESSED", "BUTTON3_RELEASED", "BUTTON3_CLICKED", 38 "BUTTON3_DOUBLE_CLICKED", "BUTTON3_TRIPLE_CLICKED", 39 "BUTTON4_PRESSED", "BUTTON4_RELEASED", "BUTTON4_CLICKED", 40 "BUTTON4_DOUBLE_CLICKED", "BUTTON4_TRIPLE_CLICKED", 41 "BUTTON_SHIFT", "BUTTON_CTRL", "BUTTON_ALT", 42 "ALL_MOUSE_EVENTS", "REPORT_MOUSE_POSITION", 43 ]: 44 _copy_to_globals(name) 45 46 if not lib._m_NetBSD: 47 for key in range(lib.KEY_MIN, lib.KEY_MAX): 48 key_n = lib.keyname(key) 49 if key_n == ffi.NULL: 50 continue 51 key_n = ffi.string(key_n) 52 if key_n == b"UNKNOWN KEY": 53 continue 54 if not isinstance(key_n, str): # python 3 55 key_n = key_n.decode() 56 key_n = key_n.replace('(', '').replace(')', '') 57 globals()[key_n] = key 58 59_setup() 60 61# Do we want this? 62# version = "2.2" 63# __version__ = "2.2" 64 65 66# ____________________________________________________________ 67 68 69_initialised_setupterm = False 70_initialised = False 71_initialised_color = False 72 73 74def _ensure_initialised_setupterm(): 75 if not _initialised_setupterm: 76 raise error("must call (at least) setupterm() first") 77 78 79def _ensure_initialised(): 80 if not _initialised: 81 raise error("must call initscr() first") 82 83 84def _ensure_initialised_color(): 85 if not _initialised and _initialised_color: 86 raise error("must call start_color() first") 87 88 89def _check_ERR(code, fname): 90 if code != lib.ERR: 91 return None 92 elif fname is None: 93 raise error("curses function returned ERR") 94 else: 95 raise error("%s() returned ERR" % (fname,)) 96 97 98def _check_NULL(rval): 99 if rval == ffi.NULL: 100 raise error("curses function returned NULL") 101 return rval 102 103 104def _call_lib(method_name, *args): 105 return getattr(lib, method_name)(*args) 106 107 108def _call_lib_check_ERR(method_name, *args): 109 return _check_ERR(_call_lib(method_name, *args), method_name) 110 111 112def _mk_no_return(method_name): 113 def _execute(): 114 _ensure_initialised() 115 return _call_lib_check_ERR(method_name) 116 _execute.__name__ = method_name 117 return _execute 118 119 120def _mk_flag_func(method_name): 121 # This is in the CPython implementation, but not documented anywhere. 122 # We have to support it, though, even if it make me sad. 123 def _execute(flag=True): 124 _ensure_initialised() 125 if flag: 126 return _call_lib_check_ERR(method_name) 127 else: 128 return _call_lib_check_ERR('no' + method_name) 129 _execute.__name__ = method_name 130 return _execute 131 132 133def _mk_return_val(method_name): 134 def _execute(): 135 return _call_lib(method_name) 136 _execute.__name__ = method_name 137 return _execute 138 139 140def _mk_w_getyx(method_name): 141 def _execute(self): 142 y = _call_lib(method_name + 'y', self._win) 143 x = _call_lib(method_name + 'x', self._win) 144 return (y, x) 145 _execute.__name__ = method_name 146 return _execute 147 148 149def _mk_w_no_return(method_name): 150 def _execute(self, *args): 151 return _call_lib_check_ERR(method_name, self._win, *args) 152 _execute.__name__ = method_name 153 return _execute 154 155 156def _mk_w_return_val(method_name): 157 def _execute(self, *args): 158 return _call_lib(method_name, self._win, *args) 159 _execute.__name__ = method_name 160 return _execute 161 162 163def _chtype(ch): 164 return int(ffi.cast("chtype", ch)) 165 166def _texttype(text): 167 if isinstance(text, str): 168 return text 169 elif isinstance(text, unicode): 170 return str(text) # default encoding 171 else: 172 raise TypeError("str or unicode expected, got a '%s' object" 173 % (type(text).__name__,)) 174 175 176def _extract_yx(args): 177 if len(args) >= 2: 178 return (args[0], args[1], args[2:]) 179 return (None, None, args) 180 181 182def _process_args(funcname, args, count, optcount, frontopt=0): 183 outargs = [] 184 if frontopt: 185 if len(args) > count + optcount: 186 # We have the front optional args here. 187 outargs.extend(args[:frontopt]) 188 args = args[frontopt:] 189 else: 190 # No front optional args, so make them None. 191 outargs.extend([None] * frontopt) 192 if (len(args) < count) or (len(args) > count + optcount): 193 raise error("%s requires %s to %s arguments" % ( 194 funcname, count, count + optcount + frontopt)) 195 outargs.extend(args) 196 return outargs 197 198 199def _argspec(count, optcount=0, frontopt=0): 200 def _argspec_deco(func): 201 @wraps(func) 202 def _wrapped(self, *args): 203 outargs = _process_args( 204 func.__name__, args, count, optcount, frontopt) 205 return func(self, *outargs) 206 return _wrapped 207 return _argspec_deco 208 209 210# ____________________________________________________________ 211 212 213class error(Exception): 214 pass 215 216 217class Window(object): 218 def __init__(self, window): 219 self._win = window 220 221 def __del__(self): 222 if self._win != lib.stdscr: 223 lib.delwin(self._win) 224 225 untouchwin = _mk_w_no_return("untouchwin") 226 touchwin = _mk_w_no_return("touchwin") 227 redrawwin = _mk_w_no_return("redrawwin") 228 insertln = _mk_w_no_return("winsertln") 229 erase = _mk_w_no_return("werase") 230 deleteln = _mk_w_no_return("wdeleteln") 231 232 is_wintouched = _mk_w_return_val("is_wintouched") 233 234 syncdown = _mk_w_return_val("wsyncdown") 235 syncup = _mk_w_return_val("wsyncup") 236 standend = _mk_w_return_val("wstandend") 237 standout = _mk_w_return_val("wstandout") 238 cursyncup = _mk_w_return_val("wcursyncup") 239 clrtoeol = _mk_w_return_val("wclrtoeol") 240 clrtobot = _mk_w_return_val("wclrtobot") 241 clear = _mk_w_return_val("wclear") 242 243 idcok = _mk_w_no_return("idcok") 244 immedok = _mk_w_no_return("immedok") 245 timeout = _mk_w_no_return("wtimeout") 246 247 getyx = _mk_w_getyx("getcur") 248 getbegyx = _mk_w_getyx("getbeg") 249 getmaxyx = _mk_w_getyx("getmax") 250 getparyx = _mk_w_getyx("getpar") 251 252 clearok = _mk_w_no_return("clearok") 253 idlok = _mk_w_no_return("idlok") 254 leaveok = _mk_w_no_return("leaveok") 255 notimeout = _mk_w_no_return("notimeout") 256 scrollok = _mk_w_no_return("scrollok") 257 insdelln = _mk_w_no_return("winsdelln") 258 syncok = _mk_w_no_return("syncok") 259 260 mvwin = _mk_w_no_return("mvwin") 261 mvderwin = _mk_w_no_return("mvderwin") 262 move = _mk_w_no_return("wmove") 263 264 if not lib._m_STRICT_SYSV_CURSES: 265 resize = _mk_w_no_return("wresize") 266 267 if lib._m_NetBSD: 268 keypad = _mk_w_return_val("keypad") 269 nodelay = _mk_w_return_val("nodelay") 270 else: 271 keypad = _mk_w_no_return("keypad") 272 nodelay = _mk_w_no_return("nodelay") 273 274 @_argspec(1, 1, 2) 275 def addch(self, y, x, ch, attr=None): 276 if attr is None: 277 attr = lib.A_NORMAL 278 ch = _chtype(ch) 279 280 if y is not None: 281 code = lib.mvwaddch(self._win, y, x, ch | attr) 282 else: 283 code = lib.waddch(self._win, ch | attr) 284 return _check_ERR(code, "addch") 285 286 @_argspec(1, 1, 2) 287 def addstr(self, y, x, text, attr=None): 288 text = _texttype(text) 289 if attr is not None: 290 attr_old = lib.getattrs(self._win) 291 lib.wattrset(self._win, attr) 292 if y is not None: 293 code = lib.mvwaddstr(self._win, y, x, text) 294 else: 295 code = lib.waddstr(self._win, text) 296 if attr is not None: 297 lib.wattrset(self._win, attr_old) 298 return _check_ERR(code, "addstr") 299 300 @_argspec(2, 1, 2) 301 def addnstr(self, y, x, text, n, attr=None): 302 text = _texttype(text) 303 if attr is not None: 304 attr_old = lib.getattrs(self._win) 305 lib.wattrset(self._win, attr) 306 if y is not None: 307 code = lib.mvwaddnstr(self._win, y, x, text, n) 308 else: 309 code = lib.waddnstr(self._win, text, n) 310 if attr is not None: 311 lib.wattrset(self._win, attr_old) 312 return _check_ERR(code, "addnstr") 313 314 def bkgd(self, ch, attr=None): 315 if attr is None: 316 attr = lib.A_NORMAL 317 return _check_ERR(lib.wbkgd(self._win, _chtype(ch) | attr), "bkgd") 318 319 attroff = _mk_w_no_return("wattroff") 320 attron = _mk_w_no_return("wattron") 321 attrset = _mk_w_no_return("wattrset") 322 323 def bkgdset(self, ch, attr=None): 324 if attr is None: 325 attr = lib.A_NORMAL 326 lib.wbkgdset(self._win, _chtype(ch) | attr) 327 return None 328 329 def border(self, ls=0, rs=0, ts=0, bs=0, tl=0, tr=0, bl=0, br=0): 330 lib.wborder(self._win, 331 _chtype(ls), _chtype(rs), _chtype(ts), _chtype(bs), 332 _chtype(tl), _chtype(tr), _chtype(bl), _chtype(br)) 333 return None 334 335 def box(self, vertint=0, horint=0): 336 lib.box(self._win, vertint, horint) 337 return None 338 339 @_argspec(1, 1, 2) 340 def chgat(self, y, x, num, attr=None): 341 # These optional args are in a weird order. 342 if attr is None: 343 attr = num 344 num = -1 345 346 color = ((attr >> 8) & 0xff) 347 attr = attr - (color << 8) 348 349 if y is not None: 350 code = lib.mvwchgat(self._win, y, x, num, attr, color, ffi.NULL) 351 lib.touchline(self._win, y, 1) 352 else: 353 yy, _ = self.getyx() 354 code = lib.wchgat(self._win, num, attr, color, ffi.NULL) 355 lib.touchline(self._win, yy, 1) 356 return _check_ERR(code, "chgat") 357 358 def delch(self, *args): 359 if len(args) == 0: 360 code = lib.wdelch(self._win) 361 elif len(args) == 2: 362 code = lib.mvwdelch(self._win, *args) 363 else: 364 raise error("delch requires 0 or 2 arguments") 365 return _check_ERR(code, "[mv]wdelch") 366 367 def derwin(self, *args): 368 nlines = 0 369 ncols = 0 370 if len(args) == 2: 371 begin_y, begin_x = args 372 elif len(args) == 4: 373 nlines, ncols, begin_y, begin_x = args 374 else: 375 raise error("derwin requires 2 or 4 arguments") 376 377 win = lib.derwin(self._win, nlines, ncols, begin_y, begin_x) 378 return Window(_check_NULL(win)) 379 380 def echochar(self, ch, attr=None): 381 if attr is None: 382 attr = lib.A_NORMAL 383 ch = _chtype(ch) 384 385 if lib._m_ispad(self._win): 386 code = lib.pechochar(self._win, ch | attr) 387 else: 388 code = lib.wechochar(self._win, ch | attr) 389 return _check_ERR(code, "echochar") 390 391 if lib._m_NCURSES_MOUSE_VERSION: 392 enclose = _mk_w_return_val("wenclose") 393 394 getbkgd = _mk_w_return_val("getbkgd") 395 396 def getch(self, *args): 397 if len(args) == 0: 398 val = lib.wgetch(self._win) 399 elif len(args) == 2: 400 val = lib.mvwgetch(self._win, *args) 401 else: 402 raise error("getch requires 0 or 2 arguments") 403 return val 404 405 def getkey(self, *args): 406 if len(args) == 0: 407 val = lib.wgetch(self._win) 408 elif len(args) == 2: 409 val = lib.mvwgetch(self._win, *args) 410 else: 411 raise error("getkey requires 0 or 2 arguments") 412 413 if val == lib.ERR: 414 raise error("no input") 415 elif val <= 255: 416 return chr(val) 417 else: 418 # XXX: The following line is different if `__NetBSD__` is defined. 419 val = lib.keyname(val) 420 if val == ffi.NULL: 421 return "" 422 return ffi.string(val) 423 424 @_argspec(0, 1, 2) 425 def getstr(self, y, x, n=1023): 426 n = min(n, 1023) 427 buf = ffi.new("char[1024]") # /* This should be big enough.. I hope */ 428 429 if y is None: 430 val = lib.wgetnstr(self._win, buf, n) 431 else: 432 val = lib.mvwgetnstr(self._win, y, x, buf, n) 433 434 if val == lib.ERR: 435 return "" 436 return ffi.string(buf) 437 438 @_argspec(2, 1, 2) 439 def hline(self, y, x, ch, n, attr=None): 440 ch = _chtype(ch) 441 if attr is None: 442 attr = lib.A_NORMAL 443 if y is not None: 444 _check_ERR(lib.wmove(self._win, y, x), "wmove") 445 return _check_ERR(lib.whline(self._win, ch | attr, n), "hline") 446 447 @_argspec(1, 1, 2) 448 def insch(self, y, x, ch, attr=None): 449 ch = _chtype(ch) 450 if attr is None: 451 attr = lib.A_NORMAL 452 if y is not None: 453 code = lib.mvwinsch(self._win, y, x, ch | attr) 454 else: 455 code = lib.winsch(self._win, ch | attr) 456 return _check_ERR(code, "insch") 457 458 def inch(self, *args): 459 if len(args) == 0: 460 return lib.winch(self._win) 461 elif len(args) == 2: 462 return lib.mvwinch(self._win, *args) 463 else: 464 raise error("inch requires 0 or 2 arguments") 465 466 @_argspec(0, 1, 2) 467 def instr(self, y, x, n=1023): 468 n = min(n, 1023) 469 buf = ffi.new("char[1024]") # /* This should be big enough.. I hope */ 470 if y is None: 471 code = lib.winnstr(self._win, buf, n) 472 else: 473 code = lib.mvwinnstr(self._win, y, x, buf, n) 474 475 if code == lib.ERR: 476 return "" 477 return ffi.string(buf) 478 479 @_argspec(1, 1, 2) 480 def insstr(self, y, x, text, attr=None): 481 text = _texttype(text) 482 if attr is not None: 483 attr_old = lib.getattrs(self._win) 484 lib.wattrset(self._win, attr) 485 if y is not None: 486 code = lib.mvwinsstr(self._win, y, x, text) 487 else: 488 code = lib.winsstr(self._win, text) 489 if attr is not None: 490 lib.wattrset(self._win, attr_old) 491 return _check_ERR(code, "insstr") 492 493 @_argspec(2, 1, 2) 494 def insnstr(self, y, x, text, n, attr=None): 495 text = _texttype(text) 496 if attr is not None: 497 attr_old = lib.getattrs(self._win) 498 lib.wattrset(self._win, attr) 499 if y is not None: 500 code = lib.mvwinsnstr(self._win, y, x, text, n) 501 else: 502 code = lib.winsnstr(self._win, text, n) 503 if attr is not None: 504 lib.wattrset(self._win, attr_old) 505 return _check_ERR(code, "insnstr") 506 507 def is_linetouched(self, line): 508 code = lib.is_linetouched(self._win, line) 509 if code == lib.ERR: 510 raise error("is_linetouched: line number outside of boundaries") 511 if code == lib.FALSE: 512 return False 513 return True 514 515 def noutrefresh(self, *args): 516 if lib._m_ispad(self._win): 517 if len(args) != 6: 518 raise error( 519 "noutrefresh() called for a pad requires 6 arguments") 520 return _check_ERR(lib.pnoutrefresh(self._win, *args), 521 "pnoutrefresh") 522 else: 523 # XXX: Better args check here? We need zero args. 524 return _check_ERR(lib.wnoutrefresh(self._win, *args), 525 "wnoutrefresh") 526 527 nooutrefresh = noutrefresh # "to be removed in 2.3", but in 2.7, 3.x. 528 529 def _copywin(self, dstwin, overlay, 530 sminr, sminc, dminr, dminc, dmaxr, dmaxc): 531 return _check_ERR(lib.copywin(self._win, dstwin._win, 532 sminr, sminc, dminr, dminc, dmaxr, dmaxc, 533 overlay), "copywin") 534 535 def overlay(self, dstwin, *args): 536 if len(args) == 6: 537 return self._copywin(dstwin, True, *args) 538 elif len(args) == 0: 539 return _check_ERR(lib.overlay(self._win, dstwin._win), "overlay") 540 else: 541 raise error("overlay requires one or seven arguments") 542 543 def overwrite(self, dstwin, *args): 544 if len(args) == 6: 545 return self._copywin(dstwin, False, *args) 546 elif len(args) == 0: 547 return _check_ERR(lib.overwrite(self._win, dstwin._win), 548 "overwrite") 549 else: 550 raise error("overwrite requires one or seven arguments") 551 552 def putwin(self, filep): 553 # filestar = ffi.new("FILE *", filep) 554 return _check_ERR(lib.putwin(self._win, filep), "putwin") 555 556 def redrawln(self, beg, num): 557 return _check_ERR(lib.wredrawln(self._win, beg, num), "redrawln") 558 559 def refresh(self, *args): 560 if lib._m_ispad(self._win): 561 if len(args) != 6: 562 raise error( 563 "noutrefresh() called for a pad requires 6 arguments") 564 return _check_ERR(lib.prefresh(self._win, *args), "prefresh") 565 else: 566 # XXX: Better args check here? We need zero args. 567 return _check_ERR(lib.wrefresh(self._win, *args), "wrefresh") 568 569 def setscrreg(self, y, x): 570 return _check_ERR(lib.wsetscrreg(self._win, y, x), "wsetscrreg") 571 572 def subwin(self, *args): 573 nlines = 0 574 ncols = 0 575 if len(args) == 2: 576 begin_y, begin_x = args 577 elif len(args) == 4: 578 nlines, ncols, begin_y, begin_x = args 579 else: 580 raise error("subwin requires 2 or 4 arguments") 581 582 if lib._m_ispad(self._win): 583 win = lib.subpad(self._win, nlines, ncols, begin_y, begin_x) 584 else: 585 win = lib.subwin(self._win, nlines, ncols, begin_y, begin_x) 586 return Window(_check_NULL(win)) 587 588 def scroll(self, nlines=None): 589 if nlines is None: 590 return _check_ERR(lib.scroll(self._win), "scroll") 591 else: 592 return _check_ERR(lib.wscrl(self._win, nlines), "scroll") 593 594 def touchline(self, st, cnt, val=None): 595 if val is None: 596 return _check_ERR(lib.touchline(self._win, st, cnt), "touchline") 597 else: 598 return _check_ERR(lib.wtouchln(self._win, st, cnt, val), 599 "touchline") 600 601 @_argspec(2, 1, 2) 602 def vline(self, y, x, ch, n, attr=None): 603 ch = _chtype(ch) 604 if attr is None: 605 attr = lib.A_NORMAL 606 if y is not None: 607 _check_ERR(lib.wmove(self._win, y, x), "wmove") 608 return _check_ERR(lib.wvline(self._win, ch | attr, n), "vline") 609 610 611beep = _mk_no_return("beep") 612def_prog_mode = _mk_no_return("def_prog_mode") 613def_shell_mode = _mk_no_return("def_shell_mode") 614doupdate = _mk_no_return("doupdate") 615endwin = _mk_no_return("endwin") 616flash = _mk_no_return("flash") 617nocbreak = _mk_no_return("nocbreak") 618noecho = _mk_no_return("noecho") 619nonl = _mk_no_return("nonl") 620noraw = _mk_no_return("noraw") 621reset_prog_mode = _mk_no_return("reset_prog_mode") 622reset_shell_mode = _mk_no_return("reset_shell_mode") 623resetty = _mk_no_return("resetty") 624savetty = _mk_no_return("savetty") 625 626cbreak = _mk_flag_func("cbreak") 627echo = _mk_flag_func("echo") 628nl = _mk_flag_func("nl") 629raw = _mk_flag_func("raw") 630 631baudrate = _mk_return_val("baudrate") 632termattrs = _mk_return_val("termattrs") 633 634termname = _mk_return_val("termname") 635longname = _mk_return_val("longname") 636 637can_change_color = _mk_return_val("can_change_color") 638has_colors = _mk_return_val("has_colors") 639has_ic = _mk_return_val("has_ic") 640has_il = _mk_return_val("has_il") 641isendwin = _mk_return_val("isendwin") 642flushinp = _mk_return_val("flushinp") 643noqiflush = _mk_return_val("noqiflush") 644 645 646def filter(): 647 lib.filter() 648 return None 649 650 651def color_content(color): 652 _ensure_initialised_color() 653 r, g, b = ffi.new("short *"), ffi.new("short *"), ffi.new("short *") 654 if lib.color_content(color, r, g, b) == lib.ERR: 655 raise error("Argument 1 was out of range. Check value of COLORS.") 656 return (r[0], g[0], b[0]) 657 658 659def color_pair(n): 660 _ensure_initialised_color() 661 return (n << 8) 662 663 664def curs_set(vis): 665 _ensure_initialised() 666 val = lib.curs_set(vis) 667 _check_ERR(val, "curs_set") 668 return val 669 670 671def delay_output(ms): 672 _ensure_initialised() 673 return _check_ERR(lib.delay_output(ms), "delay_output") 674 675 676def erasechar(): 677 _ensure_initialised() 678 return lib.erasechar() 679 680 681def getsyx(): 682 _ensure_initialised() 683 yx = ffi.new("int[2]") 684 lib._m_getsyx(yx) 685 return (yx[0], yx[1]) 686 687 688if lib._m_NCURSES_MOUSE_VERSION: 689 690 def getmouse(): 691 _ensure_initialised() 692 mevent = ffi.new("MEVENT *") 693 _check_ERR(lib.getmouse(mevent), "getmouse") 694 return (mevent.id, mevent.x, mevent.y, mevent.z, mevent.bstate) 695 696 def ungetmouse(id, x, y, z, bstate): 697 _ensure_initialised() 698 mevent = ffi.new("MEVENT *") 699 mevent.id, mevent.x, mevent.y, mevent.z, mevent.bstate = ( 700 id, x, y, z, bstate) 701 return _check_ERR(lib.ungetmouse(mevent), "ungetmouse") 702 703 704def getwin(filep): 705 return Window(_check_NULL(lib.getwin(filep))) 706 707 708def halfdelay(tenths): 709 _ensure_initialised() 710 return _check_ERR(lib.halfdelay(tenths), "halfdelay") 711 712 713if not lib._m_STRICT_SYSV_CURSES: 714 def has_key(ch): 715 _ensure_initialised() 716 return lib.has_key(ch) 717 718 719def init_color(color, r, g, b): 720 _ensure_initialised_color() 721 return _check_ERR(lib.init_color(color, r, g, b), "init_color") 722 723 724def init_pair(pair, f, b): 725 _ensure_initialised_color() 726 return _check_ERR(lib.init_pair(pair, f, b), "init_pair") 727 728 729def _mk_acs(name, ichar): 730 if len(ichar) == 1: 731 globals()[name] = lib.acs_map[ord(ichar)] 732 else: 733 globals()[name] = globals()[ichar] 734 735 736def _map_acs(): 737 _mk_acs("ACS_ULCORNER", 'l') 738 _mk_acs("ACS_LLCORNER", 'm') 739 _mk_acs("ACS_URCORNER", 'k') 740 _mk_acs("ACS_LRCORNER", 'j') 741 _mk_acs("ACS_LTEE", 't') 742 _mk_acs("ACS_RTEE", 'u') 743 _mk_acs("ACS_BTEE", 'v') 744 _mk_acs("ACS_TTEE", 'w') 745 _mk_acs("ACS_HLINE", 'q') 746 _mk_acs("ACS_VLINE", 'x') 747 _mk_acs("ACS_PLUS", 'n') 748 _mk_acs("ACS_S1", 'o') 749 _mk_acs("ACS_S9", 's') 750 _mk_acs("ACS_DIAMOND", '`') 751 _mk_acs("ACS_CKBOARD", 'a') 752 _mk_acs("ACS_DEGREE", 'f') 753 _mk_acs("ACS_PLMINUS", 'g') 754 _mk_acs("ACS_BULLET", '~') 755 _mk_acs("ACS_LARROW", ',') 756 _mk_acs("ACS_RARROW", '+') 757 _mk_acs("ACS_DARROW", '.') 758 _mk_acs("ACS_UARROW", '-') 759 _mk_acs("ACS_BOARD", 'h') 760 _mk_acs("ACS_LANTERN", 'i') 761 _mk_acs("ACS_BLOCK", '0') 762 _mk_acs("ACS_S3", 'p') 763 _mk_acs("ACS_S7", 'r') 764 _mk_acs("ACS_LEQUAL", 'y') 765 _mk_acs("ACS_GEQUAL", 'z') 766 _mk_acs("ACS_PI", '{') 767 _mk_acs("ACS_NEQUAL", '|') 768 _mk_acs("ACS_STERLING", '}') 769 _mk_acs("ACS_BSSB", "ACS_ULCORNER") 770 _mk_acs("ACS_SSBB", "ACS_LLCORNER") 771 _mk_acs("ACS_BBSS", "ACS_URCORNER") 772 _mk_acs("ACS_SBBS", "ACS_LRCORNER") 773 _mk_acs("ACS_SBSS", "ACS_RTEE") 774 _mk_acs("ACS_SSSB", "ACS_LTEE") 775 _mk_acs("ACS_SSBS", "ACS_BTEE") 776 _mk_acs("ACS_BSSS", "ACS_TTEE") 777 _mk_acs("ACS_BSBS", "ACS_HLINE") 778 _mk_acs("ACS_SBSB", "ACS_VLINE") 779 _mk_acs("ACS_SSSS", "ACS_PLUS") 780 781 782def initscr(): 783 if _initialised: 784 lib.wrefresh(lib.stdscr) 785 return Window(lib.stdscr) 786 787 win = _check_NULL(lib.initscr()) 788 globals()['_initialised_setupterm'] = True 789 globals()['_initialised'] = True 790 791 _map_acs() 792 793 globals()["LINES"] = lib.LINES 794 globals()["COLS"] = lib.COLS 795 796 return Window(win) 797 798 799def setupterm(term=None, fd=-1): 800 if fd == -1: 801 # XXX: Check for missing stdout here? 802 fd = sys.stdout.fileno() 803 804 if _initialised_setupterm: 805 return None 806 807 if term is None: 808 term = ffi.NULL 809 err = ffi.new("int *") 810 if lib.setupterm(term, fd, err) == lib.ERR: 811 err = err[0] 812 if err == 0: 813 raise error("setupterm: could not find terminal") 814 elif err == -1: 815 raise error("setupterm: could not find terminfo database") 816 else: 817 raise error("setupterm: unknown error") 818 819 globals()["_initialised_setupterm"] = True 820 return None 821 822 823def intrflush(ch): 824 _ensure_initialised() 825 return _check_ERR(lib.intrflush(ffi.NULL, ch), "intrflush") 826 827 828# XXX: #ifdef HAVE_CURSES_IS_TERM_RESIZED 829def is_term_resized(lines, columns): 830 _ensure_initialised() 831 return lib.is_term_resized(lines, columns) 832 833 834if not lib._m_NetBSD: 835 def keyname(ch): 836 _ensure_initialised() 837 if ch < 0: 838 raise error("invalid key number") 839 knp = lib.keyname(ch) 840 if knp == ffi.NULL: 841 return "" 842 return ffi.string(knp) 843 844 845def killchar(): 846 return lib.killchar() 847 848 849def meta(ch): 850 return _check_ERR(lib.meta(lib.stdscr, ch), "meta") 851 852 853if lib._m_NCURSES_MOUSE_VERSION: 854 855 def mouseinterval(interval): 856 _ensure_initialised() 857 return _check_ERR(lib.mouseinterval(interval), "mouseinterval") 858 859 def mousemask(newmask): 860 _ensure_initialised() 861 oldmask = ffi.new("mmask_t *") 862 availmask = lib.mousemask(newmask, oldmask) 863 return (availmask, oldmask) 864 865 866def napms(ms): 867 _ensure_initialised() 868 return lib.napms(ms) 869 870 871def newpad(nlines, ncols): 872 _ensure_initialised() 873 return Window(_check_NULL(lib.newpad(nlines, ncols))) 874 875 876def newwin(nlines, ncols, begin_y=None, begin_x=None): 877 _ensure_initialised() 878 if begin_x is None: 879 if begin_y is not None: 880 raise error("newwin requires 2 or 4 arguments") 881 begin_y = begin_x = 0 882 883 return Window(_check_NULL(lib.newwin(nlines, ncols, begin_y, begin_x))) 884 885 886def pair_content(pair): 887 _ensure_initialised_color() 888 f = ffi.new("short *") 889 b = ffi.new("short *") 890 if lib.pair_content(pair, f, b) == lib.ERR: 891 raise error("Argument 1 was out of range. (1..COLOR_PAIRS-1)") 892 return (f, b) 893 894 895def pair_number(pairvalue): 896 _ensure_initialised_color() 897 return (pairvalue & lib.A_COLOR) >> 8 898 899 900def putp(text): 901 text = _texttype(text) 902 return _check_ERR(lib.putp(text), "putp") 903 904 905def qiflush(flag=True): 906 _ensure_initialised() 907 if flag: 908 lib.qiflush() 909 else: 910 lib.noqiflush() 911 return None 912 913 914# XXX: Do something about the following? 915# /* Internal helper used for updating curses.LINES, curses.COLS, _curses.LINES 916# * and _curses.COLS */ 917# #if defined(HAVE_CURSES_RESIZETERM) || defined(HAVE_CURSES_RESIZE_TERM) 918# static int 919# update_lines_cols(void) 920# { 921# PyObject *o; 922# PyObject *m = PyImport_ImportModuleNoBlock("curses"); 923 924# if (!m) 925# return 0; 926 927# o = PyInt_FromLong(LINES); 928# if (!o) { 929# Py_DECREF(m); 930# return 0; 931# } 932# if (PyObject_SetAttrString(m, "LINES", o)) { 933# Py_DECREF(m); 934# Py_DECREF(o); 935# return 0; 936# } 937# if (PyDict_SetItemString(ModDict, "LINES", o)) { 938# Py_DECREF(m); 939# Py_DECREF(o); 940# return 0; 941# } 942# Py_DECREF(o); 943# o = PyInt_FromLong(COLS); 944# if (!o) { 945# Py_DECREF(m); 946# return 0; 947# } 948# if (PyObject_SetAttrString(m, "COLS", o)) { 949# Py_DECREF(m); 950# Py_DECREF(o); 951# return 0; 952# } 953# if (PyDict_SetItemString(ModDict, "COLS", o)) { 954# Py_DECREF(m); 955# Py_DECREF(o); 956# return 0; 957# } 958# Py_DECREF(o); 959# Py_DECREF(m); 960# return 1; 961# } 962# #endif 963 964# #ifdef HAVE_CURSES_RESIZETERM 965# static PyObject * 966# PyCurses_ResizeTerm(PyObject *self, PyObject *args) 967# { 968# int lines; 969# int columns; 970# PyObject *result; 971 972# PyCursesInitialised; 973 974# if (!PyArg_ParseTuple(args,"ii:resizeterm", &lines, &columns)) 975# return NULL; 976 977# result = PyCursesCheckERR(resizeterm(lines, columns), "resizeterm"); 978# if (!result) 979# return NULL; 980# if (!update_lines_cols()) 981# return NULL; 982# return result; 983# } 984 985# #endif 986 987# #ifdef HAVE_CURSES_RESIZE_TERM 988# static PyObject * 989# PyCurses_Resize_Term(PyObject *self, PyObject *args) 990# { 991# int lines; 992# int columns; 993 994# PyObject *result; 995 996# PyCursesInitialised; 997 998# if (!PyArg_ParseTuple(args,"ii:resize_term", &lines, &columns)) 999# return NULL; 1000 1001# result = PyCursesCheckERR(resize_term(lines, columns), "resize_term"); 1002# if (!result) 1003# return NULL; 1004# if (!update_lines_cols()) 1005# return NULL; 1006# return result; 1007# } 1008# #endif /* HAVE_CURSES_RESIZE_TERM */ 1009 1010 1011def setsyx(y, x): 1012 _ensure_initialised() 1013 lib.setsyx(y, x) 1014 return None 1015 1016 1017def start_color(): 1018 _check_ERR(lib.start_color(), "start_color") 1019 globals()["COLORS"] = lib.COLORS 1020 globals()["COLOR_PAIRS"] = lib.COLOR_PAIRS 1021 globals()["_initialised_color"] = True 1022 return None 1023 1024 1025def tigetflag(capname): 1026 _ensure_initialised_setupterm() 1027 return lib.tigetflag(capname) 1028 1029 1030def tigetnum(capname): 1031 _ensure_initialised_setupterm() 1032 return lib.tigetnum(capname) 1033 1034 1035def tigetstr(capname): 1036 _ensure_initialised_setupterm() 1037 val = lib.tigetstr(capname) 1038 if int(ffi.cast("intptr_t", val)) in (0, -1): 1039 return None 1040 return ffi.string(val) 1041 1042 1043def tparm(fmt, i1=0, i2=0, i3=0, i4=0, i5=0, i6=0, i7=0, i8=0, i9=0): 1044 args = [ffi.cast("int", i) for i in (i1, i2, i3, i4, i5, i6, i7, i8, i9)] 1045 result = lib.tparm(fmt, *args) 1046 if result == ffi.NULL: 1047 raise error("tparm() returned NULL") 1048 return ffi.string(result) 1049 1050 1051def typeahead(fd): 1052 _ensure_initialised() 1053 return _check_ERR(lib.typeahead(fd), "typeahead") 1054 1055 1056def unctrl(ch): 1057 _ensure_initialised() 1058 return lib.unctrl(_chtype(ch)) 1059 1060 1061def ungetch(ch): 1062 _ensure_initialised() 1063 return _check_ERR(lib.ungetch(_chtype(ch)), "ungetch") 1064 1065 1066def use_env(flag): 1067 lib.use_env(flag) 1068 return None 1069 1070 1071if not lib._m_STRICT_SYSV_CURSES: 1072 1073 def use_default_colors(): 1074 _ensure_initialised_color() 1075 return _check_ERR(lib.use_default_colors(), "use_default_colors") 1076