150276Speter/**************************************************************************** 2176187Srafan * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. * 350276Speter * * 450276Speter * Permission is hereby granted, free of charge, to any person obtaining a * 550276Speter * copy of this software and associated documentation files (the * 650276Speter * "Software"), to deal in the Software without restriction, including * 750276Speter * without limitation the rights to use, copy, modify, merge, publish, * 850276Speter * distribute, distribute with modifications, sublicense, and/or sell * 950276Speter * copies of the Software, and to permit persons to whom the Software is * 1050276Speter * furnished to do so, subject to the following conditions: * 1150276Speter * * 1250276Speter * The above copyright notice and this permission notice shall be included * 1350276Speter * in all copies or substantial portions of the Software. * 1450276Speter * * 1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 2250276Speter * * 2350276Speter * Except as contained in this notice, the name(s) of the above copyright * 2450276Speter * holders shall not be used in advertising or otherwise to promote the * 2550276Speter * sale, use or other dealings in this Software without prior written * 2650276Speter * authorization. * 2750276Speter ****************************************************************************/ 2850276Speter 2950276Speter/**************************************************************************** 3050276Speter * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 3150276Speter * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32166124Srafan * and: Thomas E. Dickey 1996-on * 3350276Speter ****************************************************************************/ 3450276Speter 3550276Speter/* 3650276Speter** lib_getch.c 3750276Speter** 3850276Speter** The routine getch(). 3950276Speter** 4050276Speter*/ 4150276Speter 4250276Speter#include <curses.priv.h> 4350276Speter 44184989SrafanMODULE_ID("$Id: lib_getch.c,v 1.99 2008/09/20 19:46:13 tom Exp $") 4550276Speter 4650276Speter#include <fifo_defs.h> 4750276Speter 48174993Srafan#if USE_REENTRANT 49178866Srafan#define GetEscdelay(sp) (sp)->_ESCDELAY 50174993SrafanNCURSES_EXPORT(int) 51174993SrafanNCURSES_PUBLIC_VAR(ESCDELAY) (void) 52174993Srafan{ 53178866Srafan return SP ? GetEscdelay(SP) : 1000; 54174993Srafan} 55174993Srafan#else 56178866Srafan#define GetEscdelay(sp) ESCDELAY 5776726SpeterNCURSES_EXPORT_VAR(int) 5876726SpeterESCDELAY = 1000; /* max interval betw. chars in funkeys, in millisecs */ 59174993Srafan#endif 6050276Speter 61176187Srafan#if NCURSES_EXT_FUNCS 62176187SrafanNCURSES_EXPORT(int) 63176187Srafanset_escdelay(int value) 64176187Srafan{ 65176187Srafan int code = OK; 66176187Srafan#if USE_REENTRANT 67176187Srafan if (SP) { 68176187Srafan SP->_ESCDELAY = value; 69176187Srafan } else { 70176187Srafan code = ERR; 71176187Srafan } 72176187Srafan#else 73176187Srafan ESCDELAY = value; 74176187Srafan#endif 75176187Srafan return code; 76176187Srafan} 77176187Srafan#endif 78176187Srafan 79184989Srafanstatic int 80184989Srafan_nc_use_meta(WINDOW *win) 81184989Srafan{ 82184989Srafan SCREEN *sp = _nc_screen_of(win); 83184989Srafan return (sp ? sp->_use_meta : 0); 84184989Srafan} 85184989Srafan 86166124Srafan#ifdef NCURSES_WGETCH_EVENTS 87166124Srafan#define TWAIT_MASK 7 88166124Srafan#else 89166124Srafan#define TWAIT_MASK 3 90166124Srafan#endif 91166124Srafan 92166124Srafan/* 93166124Srafan * Check for mouse activity, returning nonzero if we find any. 94166124Srafan */ 95166124Srafanstatic int 96178866Srafancheck_mouse_activity(SCREEN *sp, int delay EVENTLIST_2nd(_nc_eventlist * evl)) 97166124Srafan{ 98166124Srafan int rc; 99166124Srafan 100166124Srafan#if USE_SYSMOUSE 101178866Srafan if ((sp->_mouse_type == M_SYSMOUSE) 102178866Srafan && (sp->_sysmouse_head < sp->_sysmouse_tail)) { 103166124Srafan return 2; 104166124Srafan } 105166124Srafan#endif 106178866Srafan rc = _nc_timed_wait(sp, TWAIT_MASK, delay, (int *) 0 EVENTLIST_2nd(evl)); 107166124Srafan#if USE_SYSMOUSE 108178866Srafan if ((sp->_mouse_type == M_SYSMOUSE) 109178866Srafan && (sp->_sysmouse_head < sp->_sysmouse_tail) 110166124Srafan && (rc == 0) 111166124Srafan && (errno == EINTR)) { 112166124Srafan rc |= 2; 113166124Srafan } 114166124Srafan#endif 115166124Srafan return rc; 116166124Srafan} 117166124Srafan 118166124Srafanstatic NCURSES_INLINE int 119178866Srafanfifo_peek(SCREEN *sp) 12050276Speter{ 121178866Srafan int ch = sp->_fifo[peek]; 12266963Speter TR(TRACE_IEVENT, ("peeking at %d", peek)); 12350276Speter 12462449Speter p_inc(); 12562449Speter return ch; 12650276Speter} 12750276Speter 128166124Srafanstatic NCURSES_INLINE int 129178866Srafanfifo_pull(SCREEN *sp) 13050276Speter{ 13162449Speter int ch; 132178866Srafan ch = sp->_fifo[head]; 133184989Srafan TR(TRACE_IEVENT, ("pulling %s from %d", _nc_tracechar(sp, ch), head)); 13450276Speter 13562449Speter if (peek == head) { 13662449Speter h_inc(); 13762449Speter peek = head; 13862449Speter } else 13962449Speter h_inc(); 14050276Speter 14150276Speter#ifdef TRACE 142174993Srafan if (USE_TRACEF(TRACE_IEVENT)) { 143178866Srafan _nc_fifo_dump(sp); 144174993Srafan _nc_unlock_global(tracef); 145174993Srafan } 14650276Speter#endif 14762449Speter return ch; 14850276Speter} 14950276Speter 150166124Srafanstatic NCURSES_INLINE int 151178866Srafanfifo_push(SCREEN *sp EVENTLIST_2nd(_nc_eventlist * evl)) 15250276Speter{ 15362449Speter int n; 154166124Srafan int ch = 0; 155166124Srafan int mask = 0; 15650276Speter 157166124Srafan (void) mask; 15862449Speter if (tail == -1) 15962449Speter return ERR; 16050276Speter 16150276Speter#ifdef HIDE_EINTR 16262449Speter again: 16362449Speter errno = 0; 16450276Speter#endif 16550276Speter 166166124Srafan#ifdef NCURSES_WGETCH_EVENTS 167166124Srafan if (evl 168166124Srafan#if USE_GPM_SUPPORT || USE_EMX_MOUSE || USE_SYSMOUSE 169178866Srafan || (sp->_mouse_fd >= 0) 170166124Srafan#endif 171166124Srafan ) { 172178866Srafan mask = check_mouse_activity(sp, -1 EVENTLIST_2nd(evl)); 173166124Srafan } else 174166124Srafan mask = 0; 175166124Srafan 176166124Srafan if (mask & 4) { 177166124Srafan T(("fifo_push: ungetch KEY_EVENT")); 178178866Srafan _nc_ungetch(sp, KEY_EVENT); 179166124Srafan return KEY_EVENT; 180166124Srafan } 181166124Srafan#elif USE_GPM_SUPPORT || USE_EMX_MOUSE || USE_SYSMOUSE 182178866Srafan if (sp->_mouse_fd >= 0) { 183178866Srafan mask = check_mouse_activity(sp, -1 EVENTLIST_2nd(evl)); 184166124Srafan } 185166124Srafan#endif 186166124Srafan 187166124Srafan#if USE_GPM_SUPPORT || USE_EMX_MOUSE 188178866Srafan if ((sp->_mouse_fd >= 0) && (mask & 2)) { 189178866Srafan sp->_mouse_event(sp); 19062449Speter ch = KEY_MOUSE; 19162449Speter n = 1; 19262449Speter } else 19350276Speter#endif 194166124Srafan#if USE_SYSMOUSE 195178866Srafan if ((sp->_mouse_type == M_SYSMOUSE) 196178866Srafan && (sp->_sysmouse_head < sp->_sysmouse_tail)) { 197178866Srafan sp->_mouse_event(sp); 198166124Srafan ch = KEY_MOUSE; 199166124Srafan n = 1; 200178866Srafan } else if ((sp->_mouse_type == M_SYSMOUSE) 201166124Srafan && (mask <= 0) && errno == EINTR) { 202178866Srafan sp->_mouse_event(sp); 203166124Srafan ch = KEY_MOUSE; 204166124Srafan n = 1; 205166124Srafan } else 206166124Srafan#endif 207166124Srafan { /* Can block... */ 20862449Speter unsigned char c2 = 0; 209178866Srafan n = read(sp->_ifd, &c2, 1); 21097049Speter ch = c2; 21162449Speter } 21250276Speter 21350276Speter#ifdef HIDE_EINTR 21462449Speter /* 21562449Speter * Under System V curses with non-restarting signals, getch() returns 21662449Speter * with value ERR when a handled signal keeps it from completing. 21762449Speter * If signals restart system calls, OTOH, the signal is invisible 21862449Speter * except to its handler. 21962449Speter * 22062449Speter * We don't want this difference to show. This piece of code 22162449Speter * tries to make it look like we always have restarting signals. 22262449Speter */ 22362449Speter if (n <= 0 && errno == EINTR) 22462449Speter goto again; 22550276Speter#endif 22650276Speter 22762449Speter if ((n == -1) || (n == 0)) { 228178866Srafan TR(TRACE_IEVENT, ("read(%d,&ch,1)=%d, errno=%d", sp->_ifd, n, errno)); 22966963Speter ch = ERR; 23062449Speter } 23166963Speter TR(TRACE_IEVENT, ("read %d characters", n)); 23250276Speter 233178866Srafan sp->_fifo[tail] = ch; 234178866Srafan sp->_fifohold = 0; 23562449Speter if (head == -1) 23662449Speter head = peek = tail; 23762449Speter t_inc(); 238184989Srafan TR(TRACE_IEVENT, ("pushed %s at %d", _nc_tracechar(sp, ch), tail)); 23950276Speter#ifdef TRACE 240174993Srafan if (USE_TRACEF(TRACE_IEVENT)) { 241178866Srafan _nc_fifo_dump(sp); 242174993Srafan _nc_unlock_global(tracef); 243174993Srafan } 24450276Speter#endif 24562449Speter return ch; 24650276Speter} 24750276Speter 248166124Srafanstatic NCURSES_INLINE void 249178866Srafanfifo_clear(SCREEN *sp) 25050276Speter{ 251178866Srafan memset(sp->_fifo, 0, sizeof(sp->_fifo)); 25262449Speter head = -1; 25362449Speter tail = peek = 0; 25450276Speter} 25550276Speter 256178866Srafanstatic int kgetch(SCREEN *EVENTLIST_2nd(_nc_eventlist * evl)); 25750276Speter 258184989Srafanstatic void 259184989Srafanrecur_wrefresh(WINDOW *win) 260184989Srafan{ 261184989Srafan#ifdef USE_PTHREADS 262184989Srafan SCREEN *sp = _nc_screen_of(win); 263184989Srafan if (_nc_use_pthreads && sp != SP) { 264184989Srafan SCREEN *save_SP; 26550276Speter 266184989Srafan /* temporarily switch to the window's screen to check/refresh */ 267184989Srafan _nc_lock_global(curses); 268184989Srafan save_SP = SP; 269184989Srafan _nc_set_screen(sp); 270184989Srafan recur_wrefresh(win); 271184989Srafan _nc_set_screen(save_SP); 272184989Srafan _nc_unlock_global(curses); 273184989Srafan } else 274184989Srafan#endif 275184989Srafan if ((is_wintouched(win) || (win->_flags & _HASMOVED)) 276184989Srafan && !(win->_flags & _ISPAD)) { 277184989Srafan wrefresh(win); 278184989Srafan } 279184989Srafan} 280184989Srafan 281184989Srafanstatic int 282184989Srafanrecur_wgetnstr(WINDOW *win, char *buf) 283184989Srafan{ 284184989Srafan SCREEN *sp = _nc_screen_of(win); 285184989Srafan int rc; 286184989Srafan 287184989Srafan if (sp != 0) { 288184989Srafan#ifdef USE_PTHREADS 289184989Srafan if (_nc_use_pthreads && sp != SP) { 290184989Srafan SCREEN *save_SP; 291184989Srafan 292184989Srafan /* temporarily switch to the window's screen to get cooked input */ 293184989Srafan _nc_lock_global(curses); 294184989Srafan save_SP = SP; 295184989Srafan _nc_set_screen(sp); 296184989Srafan rc = recur_wgetnstr(win, buf); 297184989Srafan _nc_set_screen(save_SP); 298184989Srafan _nc_unlock_global(curses); 299184989Srafan } else 300184989Srafan#endif 301184989Srafan { 302184989Srafan sp->_called_wgetch = TRUE; 303184989Srafan rc = wgetnstr(win, buf, MAXCOLUMNS); 304184989Srafan sp->_called_wgetch = FALSE; 305184989Srafan } 306184989Srafan } else { 307184989Srafan rc = ERR; 308184989Srafan } 309184989Srafan return rc; 310184989Srafan} 311184989Srafan 31276726SpeterNCURSES_EXPORT(int) 313166124Srafan_nc_wgetch(WINDOW *win, 314166124Srafan unsigned long *result, 315166124Srafan int use_meta 316166124Srafan EVENTLIST_2nd(_nc_eventlist * evl)) 31750276Speter{ 318184989Srafan SCREEN *sp; 31962449Speter int ch; 320166124Srafan#ifdef NCURSES_WGETCH_EVENTS 321166124Srafan long event_delay = -1; 322166124Srafan#endif 32350276Speter 324166124Srafan T((T_CALLED("_nc_wgetch(%p)"), win)); 32550276Speter 32697049Speter *result = 0; 327184989Srafan 328184989Srafan sp = _nc_screen_of(win); 329178866Srafan if (win == 0 || sp == 0) { 33062449Speter returnCode(ERR); 331174993Srafan } 33250276Speter 33362449Speter if (cooked_key_in_fifo()) { 334184989Srafan recur_wrefresh(win); 335178866Srafan *result = fifo_pull(sp); 336174993Srafan returnCode(*result >= KEY_MIN ? KEY_CODE_YES : OK); 33762449Speter } 338166124Srafan#ifdef NCURSES_WGETCH_EVENTS 339166124Srafan if (evl && (evl->count == 0)) 340166124Srafan evl = NULL; 341166124Srafan event_delay = _nc_eventlist_timeout(evl); 342166124Srafan#endif 34350276Speter 34462449Speter /* 34562449Speter * Handle cooked mode. Grab a string from the screen, 34662449Speter * stuff its contents in the FIFO queue, and pop off 34762449Speter * the first character to return it. 34862449Speter */ 349166124Srafan if (head == -1 && 350178866Srafan !sp->_notty && 351178866Srafan !sp->_raw && 352178866Srafan !sp->_cbreak && 353178866Srafan !sp->_called_wgetch) { 354178866Srafan char buf[MAXCOLUMNS], *bufp; 355166124Srafan int rc; 35650276Speter 35766963Speter TR(TRACE_IEVENT, ("filling queue in cooked mode")); 35850276Speter 359184989Srafan rc = recur_wgetnstr(win, buf); 36050276Speter 36162449Speter /* ungetch in reverse order */ 362166124Srafan#ifdef NCURSES_WGETCH_EVENTS 363166124Srafan if (rc != KEY_EVENT) 364166124Srafan#endif 365178866Srafan _nc_ungetch(sp, '\n'); 366178866Srafan for (bufp = buf + strlen(buf); bufp > buf; bufp--) 367178866Srafan _nc_ungetch(sp, bufp[-1]); 36850276Speter 369166124Srafan#ifdef NCURSES_WGETCH_EVENTS 370166124Srafan /* Return it first */ 371166124Srafan if (rc == KEY_EVENT) { 372166124Srafan *result = rc; 373174993Srafan } else 374166124Srafan#endif 375178866Srafan *result = fifo_pull(sp); 376174993Srafan returnCode(*result >= KEY_MIN ? KEY_CODE_YES : OK); 37762449Speter } 37850276Speter 379178866Srafan if (win->_use_keypad != sp->_keypad_on) 380178866Srafan _nc_keypad(sp, win->_use_keypad); 38197049Speter 382184989Srafan recur_wrefresh(win); 38350276Speter 384184989Srafan if (win->_notimeout || (win->_delay >= 0) || (sp->_cbreak > 1)) { 385166124Srafan if (head == -1) { /* fifo is empty */ 386166124Srafan int delay; 387166124Srafan int rc; 38850276Speter 389166124Srafan TR(TRACE_IEVENT, ("timed delay in wgetch()")); 390178866Srafan if (sp->_cbreak > 1) 391178866Srafan delay = (sp->_cbreak - 1) * 100; 392166124Srafan else 393166124Srafan delay = win->_delay; 39450276Speter 395166124Srafan#ifdef NCURSES_WGETCH_EVENTS 396166124Srafan if (event_delay >= 0 && delay > event_delay) 397166124Srafan delay = event_delay; 398166124Srafan#endif 39950276Speter 400166124Srafan TR(TRACE_IEVENT, ("delay is %d milliseconds", delay)); 401166124Srafan 402178866Srafan rc = check_mouse_activity(sp, delay EVENTLIST_2nd(evl)); 403166124Srafan 404166124Srafan#ifdef NCURSES_WGETCH_EVENTS 405166124Srafan if (rc & 4) { 406166124Srafan *result = KEY_EVENT; 407174993Srafan returnCode(KEY_CODE_YES); 408166124Srafan } 409166124Srafan#endif 410184989Srafan if (!rc) { 41162449Speter returnCode(ERR); 412184989Srafan } 413166124Srafan } 41462449Speter /* else go on to read data available */ 41562449Speter } 41650276Speter 41762449Speter if (win->_use_keypad) { 41862449Speter /* 41962449Speter * This is tricky. We only want to get special-key 42062449Speter * events one at a time. But we want to accumulate 42162449Speter * mouse events until either (a) the mouse logic tells 42262449Speter * us it's picked up a complete gesture, or (b) 42362449Speter * there's a detectable time lapse after one. 42462449Speter * 42562449Speter * Note: if the mouse code starts failing to compose 42662449Speter * press/release events into clicks, you should probably 42762449Speter * increase the wait with mouseinterval(). 42862449Speter */ 42962449Speter int runcount = 0; 430166124Srafan int rc; 43150276Speter 43262449Speter do { 433178866Srafan ch = kgetch(sp EVENTLIST_2nd(evl)); 43462449Speter if (ch == KEY_MOUSE) { 43562449Speter ++runcount; 436178866Srafan if (sp->_mouse_inline(sp)) 43762449Speter break; 43862449Speter } 439178866Srafan if (sp->_maxclick < 0) 44097049Speter break; 44162449Speter } while 44262449Speter (ch == KEY_MOUSE 443178866Srafan && (((rc = check_mouse_activity(sp, sp->_maxclick 444166124Srafan EVENTLIST_2nd(evl))) != 0 445166124Srafan && !(rc & 4)) 446184989Srafan || !sp->_mouse_parse(sp, runcount))); 447166124Srafan#ifdef NCURSES_WGETCH_EVENTS 448166124Srafan if ((rc & 4) && !ch == KEY_EVENT) { 449178866Srafan _nc_ungetch(sp, ch); 450166124Srafan ch = KEY_EVENT; 45150276Speter } 452166124Srafan#endif 453166124Srafan if (runcount > 0 && ch != KEY_MOUSE) { 454166124Srafan#ifdef NCURSES_WGETCH_EVENTS 455166124Srafan /* mouse event sequence ended by an event, report event */ 456166124Srafan if (ch == KEY_EVENT) { 457178866Srafan _nc_ungetch(sp, KEY_MOUSE); /* FIXME This interrupts a gesture... */ 458166124Srafan } else 459166124Srafan#endif 460166124Srafan { 461166124Srafan /* mouse event sequence ended by keystroke, store keystroke */ 462178866Srafan _nc_ungetch(sp, ch); 463166124Srafan ch = KEY_MOUSE; 464166124Srafan } 465166124Srafan } 46662449Speter } else { 46762449Speter if (head == -1) 468178866Srafan fifo_push(sp EVENTLIST_2nd(evl)); 469178866Srafan ch = fifo_pull(sp); 47062449Speter } 47150276Speter 47262449Speter if (ch == ERR) { 47350276Speter#if USE_SIZECHANGE 474178866Srafan if (_nc_handle_sigwinch(sp)) { 475178866Srafan _nc_update_screensize(sp); 47662449Speter /* resizeterm can push KEY_RESIZE */ 47762449Speter if (cooked_key_in_fifo()) { 478178866Srafan *result = fifo_pull(sp); 479198490Srafan /* 480198490Srafan * Get the ERR from queue -- it is from WINCH, 481198490Srafan * so we should take it out, the "error" is handled. 482198490Srafan */ 483198490Srafan if (fifo_peek(sp) == -1) 484198490Srafan fifo_pull(sp); 48598503Speter returnCode(*result >= KEY_MIN ? KEY_CODE_YES : OK); 48650276Speter } 48762449Speter } 48850276Speter#endif 48962449Speter returnCode(ERR); 49062449Speter } 49150276Speter 49262449Speter /* 49362449Speter * If echo() is in effect, display the printable version of the 49462449Speter * key on the screen. Carriage return and backspace are treated 49562449Speter * specially by Solaris curses: 49662449Speter * 49762449Speter * If carriage return is defined as a function key in the 49862449Speter * terminfo, e.g., kent, then Solaris may return either ^J (or ^M 49962449Speter * if nonl() is set) or KEY_ENTER depending on the echo() mode. 50062449Speter * We echo before translating carriage return based on nonl(), 50162449Speter * since the visual result simply moves the cursor to column 0. 50262449Speter * 50362449Speter * Backspace is a different matter. Solaris curses does not 50462449Speter * translate it to KEY_BACKSPACE if kbs=^H. This does not depend 50562449Speter * on the stty modes, but appears to be a hardcoded special case. 50662449Speter * This is a difference from ncurses, which uses the terminfo entry. 50762449Speter * However, we provide the same visual result as Solaris, moving the 50862449Speter * cursor to the left. 50962449Speter */ 510178866Srafan if (sp->_echo && !(win->_flags & _ISPAD)) { 51162449Speter chtype backup = (ch == KEY_BACKSPACE) ? '\b' : ch; 51262449Speter if (backup < KEY_MIN) 51362449Speter wechochar(win, backup); 51462449Speter } 51550276Speter 51662449Speter /* 51762449Speter * Simulate ICRNL mode 51862449Speter */ 519178866Srafan if ((ch == '\r') && sp->_nl) 52062449Speter ch = '\n'; 52150276Speter 52262449Speter /* Strip 8th-bit if so desired. We do this only for characters that 52362449Speter * are in the range 128-255, to provide compatibility with terminals 52462449Speter * that display only 7-bit characters. Note that 'ch' may be a 52562449Speter * function key at this point, so we mustn't strip _those_. 52662449Speter */ 52797049Speter if (!use_meta) 52897049Speter if ((ch < KEY_MIN) && (ch & 0x80)) 52962449Speter ch &= 0x7f; 53050276Speter 531184989Srafan T(("wgetch returning : %s", _nc_tracechar(sp, ch))); 53250276Speter 53397049Speter *result = ch; 53497049Speter returnCode(ch >= KEY_MIN ? KEY_CODE_YES : OK); 53550276Speter} 53650276Speter 537166124Srafan#ifdef NCURSES_WGETCH_EVENTS 53897049SpeterNCURSES_EXPORT(int) 539166124Srafanwgetch_events(WINDOW *win, _nc_eventlist * evl) 540166124Srafan{ 541166124Srafan int code; 542166124Srafan unsigned long value; 543166124Srafan 544166124Srafan T((T_CALLED("wgetch_events(%p,%p)"), win, evl)); 545166124Srafan code = _nc_wgetch(win, 546166124Srafan &value, 547184989Srafan _nc_use_meta(win) 548166124Srafan EVENTLIST_2nd(evl)); 549166124Srafan if (code != ERR) 550166124Srafan code = value; 551166124Srafan returnCode(code); 552166124Srafan} 553166124Srafan#endif 554166124Srafan 555166124SrafanNCURSES_EXPORT(int) 55697049Speterwgetch(WINDOW *win) 55797049Speter{ 55897049Speter int code; 55997049Speter unsigned long value; 56097049Speter 56197049Speter T((T_CALLED("wgetch(%p)"), win)); 562166124Srafan code = _nc_wgetch(win, 563166124Srafan &value, 564184989Srafan _nc_use_meta(win) 565166124Srafan EVENTLIST_2nd((_nc_eventlist *) 0)); 56697049Speter if (code != ERR) 56797049Speter code = value; 56897049Speter returnCode(code); 56997049Speter} 57097049Speter 57150276Speter/* 57250276Speter** int 57350276Speter** kgetch() 57450276Speter** 57550276Speter** Get an input character, but take care of keypad sequences, returning 57650276Speter** an appropriate code when one matches the input. After each character 57750276Speter** is received, set an alarm call based on ESCDELAY. If no more of the 57850276Speter** sequence is received by the time the alarm goes off, pass through 57950276Speter** the sequence gotten so far. 58050276Speter** 58197049Speter** This function must be called when there are no cooked keys in queue. 58250276Speter** (that is head==-1 || peek==head) 58350276Speter** 58450276Speter*/ 58550276Speter 58650276Speterstatic int 587178866Srafankgetch(SCREEN *sp EVENTLIST_2nd(_nc_eventlist * evl)) 58850276Speter{ 589174993Srafan TRIES *ptr; 59062449Speter int ch = 0; 591178866Srafan int timeleft = GetEscdelay(sp); 59250276Speter 59397049Speter TR(TRACE_IEVENT, ("kgetch() called")); 59450276Speter 595178866Srafan ptr = sp->_keytry; 59650276Speter 59762449Speter for (;;) { 598178866Srafan if (cooked_key_in_fifo() && sp->_fifo[head] >= KEY_MIN) { 599166124Srafan break; 600166124Srafan } else if (!raw_key_in_fifo()) { 601178866Srafan ch = fifo_push(sp EVENTLIST_2nd(evl)); 602166124Srafan if (ch == ERR) { 60362449Speter peek = head; /* the keys stay uninterpreted */ 60462449Speter return ERR; 60562449Speter } 606166124Srafan#ifdef NCURSES_WGETCH_EVENTS 607166124Srafan else if (ch == KEY_EVENT) { 608166124Srafan peek = head; /* the keys stay uninterpreted */ 609178866Srafan return fifo_pull(sp); /* Remove KEY_EVENT from the queue */ 610166124Srafan } 611166124Srafan#endif 61262449Speter } 613166124Srafan 614178866Srafan ch = fifo_peek(sp); 61562449Speter if (ch >= KEY_MIN) { 616166124Srafan /* If not first in queue, somebody put this key there on purpose in 617166124Srafan * emergency. Consider it higher priority than the unfinished 618166124Srafan * keysequence we are parsing. 619166124Srafan */ 62062449Speter peek = head; 62162449Speter /* assume the key is the last in fifo */ 62262449Speter t_dec(); /* remove the key */ 62362449Speter return ch; 62462449Speter } 62550276Speter 626184989Srafan TR(TRACE_IEVENT, ("ch: %s", _nc_tracechar(sp, (unsigned char) ch))); 62762449Speter while ((ptr != NULL) && (ptr->ch != (unsigned char) ch)) 62862449Speter ptr = ptr->sibling; 62997049Speter 63062449Speter if (ptr == NULL) { 63162449Speter TR(TRACE_IEVENT, ("ptr is null")); 63262449Speter break; 63397049Speter } 63497049Speter TR(TRACE_IEVENT, ("ptr=%p, ch=%d, value=%d", 63597049Speter ptr, ptr->ch, ptr->value)); 63650276Speter 63762449Speter if (ptr->value != 0) { /* sequence terminated */ 63862449Speter TR(TRACE_IEVENT, ("end of sequence")); 63962449Speter if (peek == tail) 640178866Srafan fifo_clear(sp); 64162449Speter else 64262449Speter head = peek; 64362449Speter return (ptr->value); 64462449Speter } 64550276Speter 64662449Speter ptr = ptr->child; 64750276Speter 64862449Speter if (!raw_key_in_fifo()) { 649166124Srafan int rc; 650166124Srafan 65162449Speter TR(TRACE_IEVENT, ("waiting for rest of sequence")); 652178866Srafan rc = check_mouse_activity(sp, timeleft EVENTLIST_2nd(evl)); 653166124Srafan#ifdef NCURSES_WGETCH_EVENTS 654166124Srafan if (rc & 4) { 655166124Srafan TR(TRACE_IEVENT, ("interrupted by a user event")); 656166124Srafan /* FIXME Should have preserved remainder timeleft for reuse... */ 657166124Srafan peek = head; /* Restart interpreting later */ 658166124Srafan return KEY_EVENT; 659166124Srafan } 660166124Srafan#endif 661166124Srafan if (!rc) { 66262449Speter TR(TRACE_IEVENT, ("ran out of time")); 66362449Speter break; 66462449Speter } 66550276Speter } 66662449Speter } 667178866Srafan ch = fifo_pull(sp); 66862449Speter peek = head; 66962449Speter return ch; 67050276Speter} 671