X-Git-Url: https://ncurses.scripts.mit.edu/?a=blobdiff_plain;f=ncurses%2Fbase%2Flib_getch.c;h=0d719cfcda97649d2f671ee5ca2d0ffa7558f771;hb=HEAD;hp=24acf055674c5a1020cc9c1c0d3616d52b8ace22;hpb=a2ea66477b08cf07200cf7c319447d61d1360d85;p=ncurses.git diff --git a/ncurses/base/lib_getch.c b/ncurses/base/lib_getch.c index 24acf055..8e476791 100644 --- a/ncurses/base/lib_getch.c +++ b/ncurses/base/lib_getch.c @@ -1,5 +1,6 @@ /**************************************************************************** - * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc. * + * Copyright 2018-2022,2023 Thomas E. Dickey * + * Copyright 1998-2015,2016 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * @@ -40,9 +41,10 @@ ** */ +#define NEED_KEY_EVENT #include -MODULE_ID("$Id: lib_getch.c,v 1.119 2010/05/22 20:00:35 tom Exp $") +MODULE_ID("$Id: lib_getch.c,v 1.146 2023/04/29 18:57:12 tom Exp $") #include @@ -69,16 +71,20 @@ NCURSES_EXPORT(int) NCURSES_SP_NAME(set_escdelay) (NCURSES_SP_DCLx int value) { int code = OK; -#if USE_REENTRANT - if (SP_PARM) { - SET_ESCDELAY(value); - } else { + if (value < 0) { code = ERR; - } + } else { +#if USE_REENTRANT + if (SP_PARM) { + SET_ESCDELAY(value); + } else { + code = ERR; + } #else - (void) SP_PARM; - ESCDELAY = value; + (void) SP_PARM; + ESCDELAY = value; #endif + } return code; } @@ -87,12 +93,16 @@ NCURSES_EXPORT(int) set_escdelay(int value) { int code; + if (value < 0) { + code = ERR; + } else { #if USE_REENTRANT - code = NCURSES_SP_NAME(set_escdelay) (CURRENT_SCREEN, value); + code = NCURSES_SP_NAME(set_escdelay) (CURRENT_SCREEN, value); #else - ESCDELAY = value; - code = OK; + ESCDELAY = value; + code = OK; #endif + } return code; } #endif @@ -124,6 +134,17 @@ _nc_use_meta(WINDOW *win) return (sp ? sp->_use_meta : 0); } +#ifdef USE_TERM_DRIVER +# if defined(_NC_WINDOWS) && !defined(EXP_WIN32_DRIVER) +static HANDLE +_nc_get_handle(int fd) +{ + intptr_t value = _get_osfhandle(fd); + return (HANDLE) value; +} +# endif +#endif + /* * Check for mouse activity, returning nonzero if we find any. */ @@ -133,37 +154,60 @@ check_mouse_activity(SCREEN *sp, int delay EVENTLIST_2nd(_nc_eventlist * evl)) int rc; #ifdef USE_TERM_DRIVER - rc = TCBOf(sp)->drv->testmouse(TCBOf(sp), delay); -#else -#if USE_SYSMOUSE + TERMINAL_CONTROL_BLOCK *TCB = TCBOf(sp); + rc = TCBOf(sp)->drv->td_testmouse(TCBOf(sp), delay EVENTLIST_2nd(evl)); +# if defined(EXP_WIN32_DRIVER) + /* if we emulate terminfo on console, we have to use the console routine */ + if (IsTermInfoOnConsole(sp)) { + rc = _nc_console_testmouse(sp, + _nc_console_handle(sp->_ifd), + delay EVENTLIST_2nd(evl)); + } else +# elif defined(_NC_WINDOWS) + /* if we emulate terminfo on console, we have to use the console routine */ + if (IsTermInfoOnConsole(sp)) { + HANDLE fd = _nc_get_handle(sp->_ifd); + rc = _nc_mingw_testmouse(sp, fd, delay EVENTLIST_2nd(evl)); + } else +# endif + rc = TCB->drv->td_testmouse(TCB, delay EVENTLIST_2nd(evl)); +#else /* !USE_TERM_DRIVER */ +# if USE_SYSMOUSE if ((sp->_mouse_type == M_SYSMOUSE) && (sp->_sysmouse_head < sp->_sysmouse_tail)) { rc = TW_MOUSE; } else -#endif +# endif { +# if defined(EXP_WIN32_DRIVER) + rc = _nc_console_testmouse(sp, + _nc_console_handle(sp->_ifd), + delay + EVENTLIST_2nd(evl)); +# else rc = _nc_timed_wait(sp, TWAIT_MASK, delay, (int *) 0 EVENTLIST_2nd(evl)); -#if USE_SYSMOUSE +# endif +# if USE_SYSMOUSE if ((sp->_mouse_type == M_SYSMOUSE) && (sp->_sysmouse_head < sp->_sysmouse_tail) && (rc == 0) && (errno == EINTR)) { rc |= TW_MOUSE; } -#endif +# endif } -#endif +#endif /* USE_TERM_DRIVER */ return rc; } static NCURSES_INLINE int fifo_peek(SCREEN *sp) { - int ch = sp->_fifo[peek]; + int ch = (peek >= 0) ? sp->_fifo[peek] : ERR; TR(TRACE_IEVENT, ("peeking at %d", peek)); p_inc(); @@ -173,15 +217,16 @@ fifo_peek(SCREEN *sp) static NCURSES_INLINE int fifo_pull(SCREEN *sp) { - int ch; - ch = sp->_fifo[head]; + int ch = (head >= 0) ? sp->_fifo[head] : ERR; + TR(TRACE_IEVENT, ("pulling %s from %d", _nc_tracechar(sp, ch), head)); if (peek == head) { h_inc(); peek = head; - } else + } else { h_inc(); + } #ifdef TRACE if (USE_TRACEF(TRACE_IEVENT)) { @@ -200,14 +245,9 @@ fifo_push(SCREEN *sp EVENTLIST_2nd(_nc_eventlist * evl)) int mask = 0; (void) mask; - if (tail == -1) + if (tail < 0) return ERR; -#ifdef HIDE_EINTR - again: - errno = 0; -#endif - #ifdef NCURSES_WGETCH_EVENTS if (evl #if USE_GPM_SUPPORT || USE_EMX_MOUSE || USE_SYSMOUSE @@ -256,46 +296,54 @@ fifo_push(SCREEN *sp EVENTLIST_2nd(_nc_eventlist * evl)) ch = KEY_MOUSE; n = 1; } else +#endif +#if USE_KLIBC_KBD + if (NC_ISATTY(sp->_ifd) && IsCbreak(sp)) { + ch = _read_kbd(0, 1, !IsRaw(sp)); + n = (ch == -1) ? -1 : 1; + sp->_extended_key = (ch == 0); + } else #endif { /* Can block... */ -#ifdef USE_TERM_DRIVER +#if defined(USE_TERM_DRIVER) int buf; - n = CallDriver_1(sp, read, &buf); +# if defined(EXP_WIN32_DRIVER) + if (NC_ISATTY(sp->_ifd) && IsTermInfoOnConsole(sp) && IsCbreak(sp)) { + _nc_set_read_thread(TRUE); + n = _nc_console_read(sp, + _nc_console_handle(sp->_ifd), + &buf); + _nc_set_read_thread(FALSE); + } else +# elif defined(_NC_WINDOWS) + if (NC_ISATTY(sp->_ifd) && IsTermInfoOnConsole(sp) && IsCbreak(sp)) + n = _nc_mingw_console_read(sp, + _nc_get_handle(sp->_ifd), + &buf); + else +# endif /* EXP_WIN32_DRIVER */ + n = CallDriver_1(sp, td_read, &buf); ch = buf; -#else +#else /* !USE_TERM_DRIVER */ +#if defined(EXP_WIN32_DRIVER) + int buf; +#endif unsigned char c2 = 0; -# if USE_PTHREADS_EINTR -# if USE_WEAK_SYMBOLS - if ((pthread_self) && (pthread_kill) && (pthread_equal)) -# endif - _nc_globals.read_thread = pthread_self(); -# endif - n = read(sp->_ifd, &c2, 1); -#if USE_PTHREADS_EINTR - _nc_globals.read_thread = 0; + + _nc_set_read_thread(TRUE); +#if defined(EXP_WIN32_DRIVER) + n = _nc_console_read(sp, + _nc_console_handle(sp->_ifd), + &buf); + c2 = buf; +#else + n = (int) read(sp->_ifd, &c2, (size_t) 1); #endif + _nc_set_read_thread(FALSE); ch = c2; -#endif +#endif /* USE_TERM_DRIVER */ } -#ifdef HIDE_EINTR - /* - * Under System V curses with non-restarting signals, getch() returns - * with value ERR when a handled signal keeps it from completing. - * If signals restart system calls, OTOH, the signal is invisible - * except to its handler. - * - * We don't want this difference to show. This piece of code - * tries to make it look like we always have restarting signals. - */ - if (n <= 0 && errno == EINTR -# if USE_PTHREADS_EINTR - && (_nc_globals.have_sigwinch == 0) -# endif - ) - goto again; -#endif - if ((n == -1) || (n == 0)) { TR(TRACE_IEVENT, ("read(%d,&ch,1)=%d, errno=%d", sp->_ifd, n, errno)); ch = ERR; @@ -325,14 +373,24 @@ fifo_clear(SCREEN *sp) tail = peek = 0; } -static int kgetch(SCREEN *EVENTLIST_2nd(_nc_eventlist * evl)); +static int kgetch(SCREEN *, bool EVENTLIST_2nd(_nc_eventlist *)); static void recur_wrefresh(WINDOW *win) { #ifdef USE_PTHREADS SCREEN *sp = _nc_screen_of(win); - if (_nc_use_pthreads && sp != CURRENT_SCREEN) { + bool same_sp; + + if (_nc_use_pthreads) { + _nc_lock_global(curses); + same_sp = (sp == CURRENT_SCREEN); + _nc_unlock_global(curses); + } else { + same_sp = (sp == CURRENT_SCREEN); + } + + if (_nc_use_pthreads && !same_sp) { SCREEN *save_SP; /* temporarily switch to the window's screen to check/refresh */ @@ -345,7 +403,7 @@ recur_wrefresh(WINDOW *win) } else #endif if ((is_wintouched(win) || (win->_flags & _HASMOVED)) - && !(win->_flags & _ISPAD)) { + && !IS_PAD(win)) { wrefresh(win); } } @@ -383,7 +441,7 @@ recur_wgetnstr(WINDOW *win, char *buf) NCURSES_EXPORT(int) _nc_wgetch(WINDOW *win, - unsigned long *result, + int *result, int use_meta EVENTLIST_2nd(_nc_eventlist * evl)) { @@ -391,7 +449,7 @@ _nc_wgetch(WINDOW *win, int ch; int rc = 0; #ifdef NCURSES_WGETCH_EVENTS - long event_delay = -1; + int event_delay = -1; #endif T((T_CALLED("_nc_wgetch(%p)"), (void *) win)); @@ -421,8 +479,8 @@ _nc_wgetch(WINDOW *win, */ if (head == -1 && !sp->_notty && - !sp->_raw && - !sp->_cbreak && + !IsRaw(sp) && + !IsCbreak(sp) && !sp->_called_wgetch) { char buf[MAXCOLUMNS], *bufp; @@ -431,11 +489,11 @@ _nc_wgetch(WINDOW *win, /* ungetch in reverse order */ #ifdef NCURSES_WGETCH_EVENTS rc = recur_wgetnstr(win, buf); - if (rc != KEY_EVENT) + if (rc != KEY_EVENT && rc != ERR) safe_ungetch(sp, '\n'); #else - (void) recur_wgetnstr(win, buf); - safe_ungetch(sp, '\n'); + if (recur_wgetnstr(win, buf) != ERR) + safe_ungetch(sp, '\n'); #endif for (bufp = buf + strlen(buf); bufp > buf; bufp--) safe_ungetch(sp, bufp[-1]); @@ -455,13 +513,13 @@ _nc_wgetch(WINDOW *win, recur_wrefresh(win); - if (win->_notimeout || (win->_delay >= 0) || (sp->_cbreak > 1)) { + if (win->_notimeout || (win->_delay >= 0) || (IsCbreak(sp) > 1)) { if (head == -1) { /* fifo is empty */ int delay; TR(TRACE_IEVENT, ("timed delay in wgetch()")); - if (sp->_cbreak > 1) - delay = (sp->_cbreak - 1) * 100; + if (IsCbreak(sp) > 1) + delay = (IsCbreak(sp) - 1) * 100; else delay = win->_delay; @@ -492,7 +550,7 @@ _nc_wgetch(WINDOW *win, * This is tricky. We only want to get special-key * events one at a time. But we want to accumulate * mouse events until either (a) the mouse logic tells - * us it's picked up a complete gesture, or (b) + * us it has picked up a complete gesture, or (b) * there's a detectable time lapse after one. * * Note: if the mouse code starts failing to compose @@ -502,7 +560,7 @@ _nc_wgetch(WINDOW *win, int runcount = 0; do { - ch = kgetch(sp EVENTLIST_2nd(evl)); + ch = kgetch(sp, win->_notimeout EVENTLIST_2nd(evl)); if (ch == KEY_MOUSE) { ++runcount; if (sp->_mouse_inline(sp)) @@ -569,7 +627,7 @@ _nc_wgetch(WINDOW *win, * * If carriage return is defined as a function key in the * terminfo, e.g., kent, then Solaris may return either ^J (or ^M - * if nonl() is set) or KEY_ENTER depending on the echo() mode. + * if nonl() is set) or KEY_ENTER depending on the echo() mode. * We echo before translating carriage return based on nonl(), * since the visual result simply moves the cursor to column 0. * @@ -580,8 +638,8 @@ _nc_wgetch(WINDOW *win, * However, we provide the same visual result as Solaris, moving the * cursor to the left. */ - if (sp->_echo && !(win->_flags & _ISPAD)) { - chtype backup = (ch == KEY_BACKSPACE) ? '\b' : ch; + if (IsEcho(sp) && !IS_PAD(win)) { + chtype backup = (chtype) ((ch == KEY_BACKSPACE) ? '\b' : ch); if (backup < KEY_MIN) wechochar(win, backup); } @@ -589,7 +647,7 @@ _nc_wgetch(WINDOW *win, /* * Simulate ICRNL mode */ - if ((ch == '\r') && sp->_nl) + if ((ch == '\r') && IsNl(sp)) ch = '\n'; /* Strip 8th-bit if so desired. We do this only for characters that @@ -612,9 +670,9 @@ NCURSES_EXPORT(int) wgetch_events(WINDOW *win, _nc_eventlist * evl) { int code; - unsigned long value; + int value; - T((T_CALLED("wgetch_events(%p,%p)"), win, evl)); + T((T_CALLED("wgetch_events(%p,%p)"), (void *) win, (void *) evl)); code = _nc_wgetch(win, &value, _nc_use_meta(win) @@ -629,7 +687,7 @@ NCURSES_EXPORT(int) wgetch(WINDOW *win) { int code; - unsigned long value; + int value; T((T_CALLED("wgetch(%p)"), (void *) win)); code = _nc_wgetch(win, @@ -657,11 +715,11 @@ wgetch(WINDOW *win) */ static int -kgetch(SCREEN *sp EVENTLIST_2nd(_nc_eventlist * evl)) +kgetch(SCREEN *sp, bool forever EVENTLIST_2nd(_nc_eventlist * evl)) { TRIES *ptr; int ch = 0; - int timeleft = GetEscdelay(sp); + int timeleft = forever ? 9999999 : GetEscdelay(sp); TR(TRACE_IEVENT, ("kgetch() called")); @@ -709,10 +767,11 @@ kgetch(SCREEN *sp EVENTLIST_2nd(_nc_eventlist * evl)) if (ptr->value != 0) { /* sequence terminated */ TR(TRACE_IEVENT, ("end of sequence")); - if (peek == tail) + if (peek == tail) { fifo_clear(sp); - else + } else { head = peek; + } return (ptr->value); }