/*!A cross-platform build utility based on Lua * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (C) 2015-present, Xmake Open Source Community. * * @author ruki * @file curses.c * */ /* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "curses" #define TB_TRACE_MODULE_DEBUG (0) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #ifdef XM_CONFIG_API_HAVE_CURSES #include "prefix.h" #include #if defined(PDCURSES) // fix macro redefinition #undef MOUSE_MOVED #endif #define NCURSES_MOUSE_VERSION 2 #ifdef TB_COMPILER_IS_MINGW #include #else #include #endif #if defined(NCURSES_VERSION) #include #endif /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #define XM_CURSES_STDSCR "curses.stdscr" #define XM_CURSES_WINDOW "curses.window" #define XM_CURSES_OK(v) (((v) == ERR) ? 0 : 1) // define functions #define XM_CURSES_NUMBER(n) \ static int xm_curses_##n(lua_State *lua) { \ lua_pushnumber(lua, n()); \ return 1; \ } #define XM_CURSES_NUMBER2(n, v) \ static int xm_curses_##n(lua_State *lua) { \ lua_pushnumber(lua, v); \ return 1; \ } #define XM_CURSES_BOOL(n) \ static int xm_curses_##n(lua_State *lua) { \ lua_pushboolean(lua, n()); \ return 1; \ } #define XM_CURSES_BOOLOK(n) \ static int xm_curses_##n(lua_State *lua) { \ lua_pushboolean(lua, XM_CURSES_OK(n())); \ return 1; \ } #define XM_CURSES_WINDOW_BOOLOK(n) \ static int xm_curses_window_##n(lua_State *lua) { \ WINDOW *w = xm_curses_window_check(lua, 1); \ lua_pushboolean(lua, XM_CURSES_OK(n(w))); \ return 1; \ } // define constants #define XM_CURSES_CONST_(n, v) \ lua_pushstring(lua, n); \ lua_pushnumber(lua, v); \ lua_settable(lua, lua_upvalueindex(1)); #define XM_CURSES_CONST(s) XM_CURSES_CONST_(#s, s) #define XM_CURSES_CONST2(s, v) XM_CURSES_CONST_(#s, v) /* ////////////////////////////////////////////////////////////////////////////////////// * globals */ // map key for pdcurses, keeping the keys consistent with ncurses static int g_mapkey = 0; /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static chtype xm_curses_checkch(lua_State *lua, int index) { if (lua_type(lua, index) == LUA_TNUMBER) { return (chtype)luaL_checknumber(lua, index); } if (lua_type(lua, index) == LUA_TSTRING) { return *lua_tostring(lua, index); } #ifdef USE_LUAJIT luaL_typerror(lua, index, "chtype"); #endif return (chtype)0; } // get character and map key static int xm_curses_window_getch_impl(WINDOW *w) { #ifdef PDCURSES static int has_key = 0; static int temp_key = 0; int key; if (g_mapkey && has_key) { has_key = 0; return temp_key; } key = wgetch(w); if (key == KEY_RESIZE) resize_term(0, 0); if (key == ERR || !g_mapkey) return key; if (key >= ALT_A && key <= ALT_Z) { has_key = 1; temp_key = key - ALT_A + 'A'; } else if (key >= ALT_0 && key <= ALT_9) { has_key = 1; temp_key = key - ALT_0 + '0'; } else { switch (key) { case ALT_DEL: temp_key = KEY_DC; break; case ALT_INS: temp_key = KEY_IC; break; case ALT_HOME: temp_key = KEY_HOME; break; case ALT_END: temp_key = KEY_END; break; case ALT_PGUP: temp_key = KEY_PPAGE; break; case ALT_PGDN: temp_key = KEY_NPAGE; break; case ALT_UP: temp_key = KEY_UP; break; case ALT_DOWN: temp_key = KEY_DOWN; break; case ALT_RIGHT: temp_key = KEY_RIGHT; break; case ALT_LEFT: temp_key = KEY_LEFT; break; case ALT_BKSP: temp_key = KEY_BACKSPACE; break; default: return key; } } has_key = 1; return 27; #else return wgetch(w); #endif } // new a window object static void xm_curses_window_new(lua_State *lua, WINDOW *nw) { if (nw) { WINDOW **w = (WINDOW **)lua_newuserdata(lua, sizeof(WINDOW *)); luaL_getmetatable(lua, XM_CURSES_WINDOW); lua_setmetatable(lua, -2); *w = nw; } else { lua_pushliteral(lua, "failed to create window"); lua_error(lua); } } // get window static WINDOW **xm_curses_window_get(lua_State *lua, int index) { WINDOW **w = (WINDOW **)luaL_checkudata(lua, index, XM_CURSES_WINDOW); if (w == NULL) luaL_argerror(lua, index, "bad curses window"); return w; } // get and check window static WINDOW *xm_curses_window_check(lua_State *lua, int index) { WINDOW **w = xm_curses_window_get(lua, index); if (*w == NULL) luaL_argerror(lua, index, "attempt to use closed curses window"); return *w; } // tostring(window) static int xm_curses_window_tostring(lua_State *lua) { WINDOW **w = xm_curses_window_get(lua, 1); char const *s = NULL; if (*w) s = (char const *)lua_touserdata(lua, 1); lua_pushfstring(lua, "curses window (%s)", s ? s : "closed"); return 1; } // window:move(y, x) static int xm_curses_window_move(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int y = (int)luaL_checkinteger(lua, 2); int x = (int)luaL_checkinteger(lua, 3); lua_pushboolean(lua, XM_CURSES_OK(wmove(w, y, x))); return 1; } // window:getyx(y, x) static int xm_curses_window_getyx(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int y, x; getyx(w, y, x); lua_pushnumber(lua, y); lua_pushnumber(lua, x); return 2; } // window:getmaxyx(y, x) static int xm_curses_window_getmaxyx(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int y, x; getmaxyx(w, y, x); lua_pushnumber(lua, y); lua_pushnumber(lua, x); return 2; } // window:delwin() static int xm_curses_window_delwin(lua_State *lua) { WINDOW **w = xm_curses_window_get(lua, 1); if (*w && *w != stdscr) { delwin(*w); *w = NULL; } return 0; } // window:addch(ch) static int xm_curses_window_addch(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); chtype ch = xm_curses_checkch(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(waddch(w, ch))); return 1; } // window:addnstr(str) static int xm_curses_window_addnstr(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); const char *str = luaL_checkstring(lua, 2); int n = (int)luaL_optinteger(lua, 3, -1); if (n < 0) n = (int)lua_strlen(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(waddnstr(w, str, n))); return 1; } // window:keypad(true) static int xm_curses_window_keypad(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int enabled = lua_isnoneornil(lua, 2) ? 1 : lua_toboolean(lua, 2); if (enabled) { // on WIN32 ALT keys need to be mapped, so to make sure you get the wanted keys, // only makes sense when using keypad(true) and echo(false) g_mapkey = 1; } lua_pushboolean(lua, XM_CURSES_OK(keypad(w, enabled))); return 1; } // window:meta(true) static int xm_curses_window_meta(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int enabled = lua_toboolean(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(meta(w, enabled))); return 1; } // window:nodelay(true) static int xm_curses_window_nodelay(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int enabled = lua_toboolean(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(nodelay(w, enabled))); return 1; } // window:leaveok(true) static int xm_curses_window_leaveok(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int enabled = lua_toboolean(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(leaveok(w, enabled))); return 1; } // window:getch() static int xm_curses_window_getch(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int c = xm_curses_window_getch_impl(w); if (c == ERR) return 0; lua_pushnumber(lua, c); return 1; } // window:attroff(attrs) static int xm_curses_window_attroff(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int attrs = (int)luaL_checkinteger(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(wattroff(w, attrs))); return 1; } // window:attron(attrs) static int xm_curses_window_attron(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int attrs = (int)luaL_checkinteger(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(wattron(w, attrs))); return 1; } // window:attrset(attrs) static int xm_curses_window_attrset(lua_State *lua) { WINDOW *w = xm_curses_window_check(lua, 1); int attrs = (int)luaL_checkinteger(lua, 2); lua_pushboolean(lua, XM_CURSES_OK(wattrset(w, attrs))); return 1; } // window:copywin(...) static int xm_curses_window_copywin(lua_State *lua) { WINDOW *srcwin = xm_curses_window_check(lua, 1); WINDOW *dstwin = xm_curses_window_check(lua, 2); int sminrow = (int)luaL_checkinteger(lua, 3); int smincol = (int)luaL_checkinteger(lua, 4); int dminrow = (int)luaL_checkinteger(lua, 5); int dmincol = (int)luaL_checkinteger(lua, 6); int dmaxrow = (int)luaL_checkinteger(lua, 7); int dmaxcol = (int)luaL_checkinteger(lua, 8); int overlay = lua_toboolean(lua, 9); lua_pushboolean(lua, XM_CURSES_OK( copywin(srcwin, dstwin, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol, overlay))); return 1; } // clean window after exiting program static void xm_curses_cleanup() { if (!isendwin()) { wclear(stdscr); wrefresh(stdscr); endwin(); } } // register constants static void xm_curses_register_constants(lua_State *lua) { // colors XM_CURSES_CONST(COLOR_BLACK) XM_CURSES_CONST(COLOR_RED) XM_CURSES_CONST(COLOR_GREEN) XM_CURSES_CONST(COLOR_YELLOW) XM_CURSES_CONST(COLOR_BLUE) XM_CURSES_CONST(COLOR_MAGENTA) XM_CURSES_CONST(COLOR_CYAN) XM_CURSES_CONST(COLOR_WHITE) // alternate character set XM_CURSES_CONST(ACS_BLOCK) XM_CURSES_CONST(ACS_BOARD) XM_CURSES_CONST(ACS_BTEE) XM_CURSES_CONST(ACS_TTEE) XM_CURSES_CONST(ACS_LTEE) XM_CURSES_CONST(ACS_RTEE) XM_CURSES_CONST(ACS_LLCORNER) XM_CURSES_CONST(ACS_LRCORNER) XM_CURSES_CONST(ACS_URCORNER) XM_CURSES_CONST(ACS_ULCORNER) XM_CURSES_CONST(ACS_LARROW) XM_CURSES_CONST(ACS_RARROW) XM_CURSES_CONST(ACS_UARROW) XM_CURSES_CONST(ACS_DARROW) XM_CURSES_CONST(ACS_HLINE) XM_CURSES_CONST(ACS_VLINE) XM_CURSES_CONST(ACS_BULLET) XM_CURSES_CONST(ACS_CKBOARD) XM_CURSES_CONST(ACS_LANTERN) XM_CURSES_CONST(ACS_DEGREE) XM_CURSES_CONST(ACS_DIAMOND) XM_CURSES_CONST(ACS_PLMINUS) XM_CURSES_CONST(ACS_PLUS) XM_CURSES_CONST(ACS_S1) XM_CURSES_CONST(ACS_S9) // attributes XM_CURSES_CONST(A_NORMAL) XM_CURSES_CONST(A_STANDOUT) XM_CURSES_CONST(A_UNDERLINE) XM_CURSES_CONST(A_REVERSE) XM_CURSES_CONST(A_BLINK) XM_CURSES_CONST(A_DIM) XM_CURSES_CONST(A_BOLD) XM_CURSES_CONST(A_PROTECT) XM_CURSES_CONST(A_INVIS) XM_CURSES_CONST(A_ALTCHARSET) XM_CURSES_CONST(A_CHARTEXT) // key functions XM_CURSES_CONST(KEY_BREAK) XM_CURSES_CONST(KEY_DOWN) XM_CURSES_CONST(KEY_UP) XM_CURSES_CONST(KEY_LEFT) XM_CURSES_CONST(KEY_RIGHT) XM_CURSES_CONST(KEY_HOME) XM_CURSES_CONST(KEY_BACKSPACE) XM_CURSES_CONST(KEY_DL) XM_CURSES_CONST(KEY_IL) XM_CURSES_CONST(KEY_DC) XM_CURSES_CONST(KEY_IC) XM_CURSES_CONST(KEY_EIC) XM_CURSES_CONST(KEY_CLEAR) XM_CURSES_CONST(KEY_EOS) XM_CURSES_CONST(KEY_EOL) XM_CURSES_CONST(KEY_SF) XM_CURSES_CONST(KEY_SR) XM_CURSES_CONST(KEY_NPAGE) XM_CURSES_CONST(KEY_PPAGE) XM_CURSES_CONST(KEY_STAB) XM_CURSES_CONST(KEY_CTAB) XM_CURSES_CONST(KEY_CATAB) XM_CURSES_CONST(KEY_ENTER) XM_CURSES_CONST(KEY_SRESET) XM_CURSES_CONST(KEY_RESET) XM_CURSES_CONST(KEY_PRINT) XM_CURSES_CONST(KEY_LL) XM_CURSES_CONST(KEY_A1) XM_CURSES_CONST(KEY_A3) XM_CURSES_CONST(KEY_B2) XM_CURSES_CONST(KEY_C1) XM_CURSES_CONST(KEY_C3) XM_CURSES_CONST(KEY_BTAB) XM_CURSES_CONST(KEY_BEG) XM_CURSES_CONST(KEY_CANCEL) XM_CURSES_CONST(KEY_CLOSE) XM_CURSES_CONST(KEY_COMMAND) XM_CURSES_CONST(KEY_COPY) XM_CURSES_CONST(KEY_CREATE) XM_CURSES_CONST(KEY_END) XM_CURSES_CONST(KEY_EXIT) XM_CURSES_CONST(KEY_FIND) XM_CURSES_CONST(KEY_HELP) XM_CURSES_CONST(KEY_MARK) XM_CURSES_CONST(KEY_MESSAGE) #ifdef PDCURSES // https://github.com/xmake-io/xmake/issues/1610#issuecomment-971149885 XM_CURSES_CONST(KEY_C2) XM_CURSES_CONST(KEY_A2) XM_CURSES_CONST(KEY_B1) XM_CURSES_CONST(KEY_B3) #endif #if !defined(XCURSES) #ifndef NOMOUSE XM_CURSES_CONST(KEY_MOUSE) #endif #endif XM_CURSES_CONST(KEY_MOVE) XM_CURSES_CONST(KEY_NEXT) XM_CURSES_CONST(KEY_OPEN) XM_CURSES_CONST(KEY_OPTIONS) XM_CURSES_CONST(KEY_PREVIOUS) XM_CURSES_CONST(KEY_REDO) XM_CURSES_CONST(KEY_REFERENCE) XM_CURSES_CONST(KEY_REFRESH) XM_CURSES_CONST(KEY_REPLACE) XM_CURSES_CONST(KEY_RESIZE) XM_CURSES_CONST(KEY_RESTART) XM_CURSES_CONST(KEY_RESUME) XM_CURSES_CONST(KEY_SAVE) XM_CURSES_CONST(KEY_SBEG) XM_CURSES_CONST(KEY_SCANCEL) XM_CURSES_CONST(KEY_SCOMMAND) XM_CURSES_CONST(KEY_SCOPY) XM_CURSES_CONST(KEY_SCREATE) XM_CURSES_CONST(KEY_SDC) XM_CURSES_CONST(KEY_SDL) XM_CURSES_CONST(KEY_SELECT) XM_CURSES_CONST(KEY_SEND) XM_CURSES_CONST(KEY_SEOL) XM_CURSES_CONST(KEY_SEXIT) XM_CURSES_CONST(KEY_SFIND) XM_CURSES_CONST(KEY_SHELP) XM_CURSES_CONST(KEY_SHOME) XM_CURSES_CONST(KEY_SIC) XM_CURSES_CONST(KEY_SLEFT) XM_CURSES_CONST(KEY_SMESSAGE) XM_CURSES_CONST(KEY_SMOVE) XM_CURSES_CONST(KEY_SNEXT) XM_CURSES_CONST(KEY_SOPTIONS) XM_CURSES_CONST(KEY_SPREVIOUS) XM_CURSES_CONST(KEY_SPRINT) XM_CURSES_CONST(KEY_SREDO) XM_CURSES_CONST(KEY_SREPLACE) XM_CURSES_CONST(KEY_SRIGHT) XM_CURSES_CONST(KEY_SRSUME) XM_CURSES_CONST(KEY_SSAVE) XM_CURSES_CONST(KEY_SSUSPEND) XM_CURSES_CONST(KEY_SUNDO) XM_CURSES_CONST(KEY_SUSPEND) XM_CURSES_CONST(KEY_UNDO) // KEY_Fx 0 <= x <= 63 XM_CURSES_CONST(KEY_F0) XM_CURSES_CONST2(KEY_F1, KEY_F(1)) XM_CURSES_CONST2(KEY_F2, KEY_F(2)) XM_CURSES_CONST2(KEY_F3, KEY_F(3)) XM_CURSES_CONST2(KEY_F4, KEY_F(4)) XM_CURSES_CONST2(KEY_F5, KEY_F(5)) XM_CURSES_CONST2(KEY_F6, KEY_F(6)) XM_CURSES_CONST2(KEY_F7, KEY_F(7)) XM_CURSES_CONST2(KEY_F8, KEY_F(8)) XM_CURSES_CONST2(KEY_F9, KEY_F(9)) XM_CURSES_CONST2(KEY_F10, KEY_F(10)) XM_CURSES_CONST2(KEY_F11, KEY_F(11)) XM_CURSES_CONST2(KEY_F12, KEY_F(12)) #if !defined(XCURSES) #ifndef NOMOUSE // mouse constants XM_CURSES_CONST(BUTTON1_RELEASED) XM_CURSES_CONST(BUTTON1_PRESSED) XM_CURSES_CONST(BUTTON1_CLICKED) XM_CURSES_CONST(BUTTON1_DOUBLE_CLICKED) XM_CURSES_CONST(BUTTON1_TRIPLE_CLICKED) XM_CURSES_CONST(BUTTON2_RELEASED) XM_CURSES_CONST(BUTTON2_PRESSED) XM_CURSES_CONST(BUTTON2_CLICKED) XM_CURSES_CONST(BUTTON2_DOUBLE_CLICKED) XM_CURSES_CONST(BUTTON2_TRIPLE_CLICKED) XM_CURSES_CONST(BUTTON3_RELEASED) XM_CURSES_CONST(BUTTON3_PRESSED) XM_CURSES_CONST(BUTTON3_CLICKED) XM_CURSES_CONST(BUTTON3_DOUBLE_CLICKED) XM_CURSES_CONST(BUTTON3_TRIPLE_CLICKED) XM_CURSES_CONST(BUTTON4_RELEASED) XM_CURSES_CONST(BUTTON4_PRESSED) XM_CURSES_CONST(BUTTON4_CLICKED) XM_CURSES_CONST(BUTTON4_DOUBLE_CLICKED) XM_CURSES_CONST(BUTTON4_TRIPLE_CLICKED) XM_CURSES_CONST(BUTTON_CTRL) XM_CURSES_CONST(BUTTON_SHIFT) XM_CURSES_CONST(BUTTON_ALT) XM_CURSES_CONST(REPORT_MOUSE_POSITION) XM_CURSES_CONST(ALL_MOUSE_EVENTS) #if NCURSES_MOUSE_VERSION > 1 XM_CURSES_CONST(BUTTON5_RELEASED) XM_CURSES_CONST(BUTTON5_PRESSED) XM_CURSES_CONST(BUTTON5_CLICKED) XM_CURSES_CONST(BUTTON5_DOUBLE_CLICKED) XM_CURSES_CONST(BUTTON5_TRIPLE_CLICKED) #endif #endif #endif } // init curses static int xm_curses_initscr(lua_State *lua) { WINDOW *w = initscr(); if (!w) return 0; xm_curses_window_new(lua, w); #if defined(NCURSES_VERSION) // ESCDELAY = 0; set_escdelay(0); #endif lua_pushstring(lua, XM_CURSES_STDSCR); lua_pushvalue(lua, -2); lua_rawset(lua, LUA_REGISTRYINDEX); xm_curses_register_constants(lua); #ifndef PDCURSES atexit(xm_curses_cleanup); #endif return 1; } static int xm_curses_endwin(lua_State *lua) { endwin(); #ifdef XCURSES XCursesExit(); exit(0); #endif return 0; } static int xm_curses_stdscr(lua_State *lua) { lua_pushstring(lua, XM_CURSES_STDSCR); lua_rawget(lua, LUA_REGISTRYINDEX); return 1; } #if !defined(XCURSES) && !defined(NOMOUSE) static int xm_curses_getmouse(lua_State *lua) { MEVENT e; if (getmouse(&e) == OK) { lua_pushinteger(lua, e.bstate); lua_pushinteger(lua, e.x); lua_pushinteger(lua, e.y); lua_pushinteger(lua, e.z); lua_pushinteger(lua, e.id); return 5; } lua_pushnil(lua); return 1; } static int xm_curses_mousemask(lua_State *lua) { mmask_t m = (mmask_t)luaL_checkinteger(lua, 1); mmask_t om; m = mousemask(m, &om); lua_pushinteger(lua, m); lua_pushinteger(lua, om); return 2; } #endif static int xm_curses_init_pair(lua_State *lua) { short pair = (short)luaL_checkinteger(lua, 1); short f = (short)luaL_checkinteger(lua, 2); short b = (short)luaL_checkinteger(lua, 3); lua_pushboolean(lua, XM_CURSES_OK(init_pair(pair, f, b))); return 1; } static int xm_curses_COLOR_PAIR(lua_State *lua) { int n = (int)luaL_checkinteger(lua, 1); lua_pushnumber(lua, COLOR_PAIR(n)); return 1; } static int xm_curses_curs_set(lua_State *lua) { int vis = (int)luaL_checkinteger(lua, 1); int state = curs_set(vis); if (state == ERR) return 0; lua_pushnumber(lua, state); return 1; } static int xm_curses_napms(lua_State *lua) { int ms = (int)luaL_checkinteger(lua, 1); lua_pushboolean(lua, XM_CURSES_OK(napms(ms))); return 1; } static int xm_curses_cbreak(lua_State *lua) { if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1)) { lua_pushboolean(lua, XM_CURSES_OK(cbreak())); } else { lua_pushboolean(lua, XM_CURSES_OK(nocbreak())); } return 1; } static int xm_curses_echo(lua_State *lua) { if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1)) { lua_pushboolean(lua, XM_CURSES_OK(echo())); } else { lua_pushboolean(lua, XM_CURSES_OK(noecho())); } return 1; } static int xm_curses_nl(lua_State *lua) { if (lua_isnoneornil(lua, 1) || lua_toboolean(lua, 1)) { lua_pushboolean(lua, XM_CURSES_OK(nl())); } else { lua_pushboolean(lua, XM_CURSES_OK(nonl())); } return 1; } static int xm_curses_newpad(lua_State *lua) { int nlines = (int)luaL_checkinteger(lua, 1); int ncols = (int)luaL_checkinteger(lua, 2); xm_curses_window_new(lua, newpad(nlines, ncols)); return 1; } XM_CURSES_NUMBER2(COLS, COLS) XM_CURSES_NUMBER2(LINES, LINES) XM_CURSES_BOOL(isendwin) XM_CURSES_BOOLOK(start_color) XM_CURSES_BOOL(has_colors) XM_CURSES_BOOLOK(doupdate) XM_CURSES_WINDOW_BOOLOK(wclear) XM_CURSES_WINDOW_BOOLOK(wnoutrefresh) /* ////////////////////////////////////////////////////////////////////////////////////// * globals */ static const luaL_Reg g_window_functions[] = { { "close", xm_curses_window_delwin }, { "keypad", xm_curses_window_keypad }, { "meta", xm_curses_window_meta }, { "nodelay", xm_curses_window_nodelay }, { "leaveok", xm_curses_window_leaveok }, { "move", xm_curses_window_move }, { "clear", xm_curses_window_wclear }, { "noutrefresh", xm_curses_window_wnoutrefresh }, { "attroff", xm_curses_window_attroff }, { "attron", xm_curses_window_attron }, { "attrset", xm_curses_window_attrset }, { "getch", xm_curses_window_getch }, { "getyx", xm_curses_window_getyx }, { "getmaxyx", xm_curses_window_getmaxyx }, { "addch", xm_curses_window_addch }, { "addstr", xm_curses_window_addnstr }, { "copy", xm_curses_window_copywin }, { "__gc", xm_curses_window_delwin }, { "__tostring", xm_curses_window_tostring }, { NULL, NULL }, }; static const luaL_Reg g_curses_functions[] = { { "done", xm_curses_endwin }, { "isdone", xm_curses_isendwin }, { "main_window", xm_curses_stdscr }, { "columns", xm_curses_COLS }, { "lines", xm_curses_LINES }, { "start_color", xm_curses_start_color }, { "has_colors", xm_curses_has_colors }, { "init_pair", xm_curses_init_pair }, { "color_pair", xm_curses_COLOR_PAIR }, { "napms", xm_curses_napms }, { "cursor_set", xm_curses_curs_set }, { "new_pad", xm_curses_newpad }, { "doupdate", xm_curses_doupdate }, { "cbreak", xm_curses_cbreak }, { "echo", xm_curses_echo }, { "nl", xm_curses_nl }, #if !defined(XCURSES) #ifndef NOMOUSE { "mousemask", xm_curses_mousemask }, { "getmouse", xm_curses_getmouse }, #endif #endif { NULL, NULL }, }; /* ////////////////////////////////////////////////////////////////////////////////////// * implementations */ int xm_lua_curses_register(lua_State *lua, const char *module) { // create new metatable for window objects luaL_newmetatable(lua, XM_CURSES_WINDOW); lua_pushliteral(lua, "__index"); lua_pushvalue(lua, -2); /* push metatable */ lua_rawset(lua, -3); /* metatable.__index = metatable */ luaL_setfuncs(lua, g_window_functions, 0); lua_pop(lua, 1); /* remove metatable from stack */ // create global table with curses methods/variables/constants lua_newtable(lua); luaL_setfuncs(lua, g_curses_functions, 0); // add curses.init() lua_pushstring(lua, "init"); lua_pushvalue(lua, -2); lua_pushcclosure(lua, xm_curses_initscr, 1); lua_settable(lua, -3); // register global curses module lua_setglobal(lua, module); /* since version 5.4, the ncurses library decides how to interpret non-ASCII data using the nl_langinfo function. * that means that you have to call setlocale() in the application and encode Unicode strings using one of the system’s available encodings. * * and we need to link libncurses_window.so for drawing vline, hline characters */ #if defined(NCURSES_VERSION) setlocale(LC_ALL, ""); #endif return 1; } #endif