📄 ui_getc.c
字号:
/* * $Id: ui_getc.c,v 1.19 2003/11/26 16:42:38 tom Exp $ * * ui_getc.c - user interface glue for getc() * * Copyright 2001-2002,2003 Thomas E. Dickey * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "dialog.h"#if TIME_WITH_SYS_TIME# include <sys/time.h># include <time.h>#else# if HAVE_SYS_TIME_H# include <sys/time.h># else# include <time.h># endif#endif#ifdef HAVE_SYS_WAIT_H#include <sys/wait.h>#endif#ifndef WEXITSTATUS# ifdef HAVE_TYPE_UNIONWAIT# define WEXITSTATUS(status) (status.w_retcode)# else# define WEXITSTATUS(status) (((status) & 0xff00) >> 8)# endif#endif#ifndef WTERMSIG# ifdef HAVE_TYPE_UNIONWAIT# define WTERMSIG(status) (status.w_termsig)# else# define WTERMSIG(status) ((status) & 0x7f)# endif#endifvoiddlg_add_callback(DIALOG_CALLBACK * p){ p->next = dialog_state.getc_callbacks; dialog_state.getc_callbacks = p; wtimeout(p->win, WTIMEOUT_VAL);}voiddlg_remove_callback(DIALOG_CALLBACK * p){ DIALOG_CALLBACK *q; if (p->input != 0) { fclose(p->input); p->input = 0; } dlg_del_window(p->win); if ((q = dialog_state.getc_callbacks) == p) { dialog_state.getc_callbacks = p->next; } else { while (q != 0) { if (q->next == p) { q->next = p->next; break; } q = q->next; } } free(p);}/* * FIXME: this could be replaced by a select/poll on several file descriptors */static intdlg_getc_ready(DIALOG_CALLBACK * p){ fd_set read_fds; int fd = fileno(p->input); struct timeval test; FD_ZERO(&read_fds); FD_SET(fd, &read_fds); test.tv_sec = 0; /* Seconds. */ test.tv_usec = WTIMEOUT_VAL * 1000; /* Microseconds. */ return (select(fd + 1, &read_fds, (fd_set *) 0, (fd_set *) 0, &test) == 1) && (FD_ISSET(fd, &read_fds));}intdlg_getc_callbacks(int ch, int fkey, int *result){ DIALOG_CALLBACK *p, *q; if ((p = dialog_state.getc_callbacks) != 0) { do { q = p->next; if (dlg_getc_ready(p)) { if (!(p->handle_getc(p, ch, fkey, result))) { dlg_remove_callback(p); } } } while ((p = q) != 0); return TRUE; } return FALSE;}static voiddlg_raise_window(WINDOW *win){ touchwin(win); wmove(win, getcury(win), getcurx(win)); wnoutrefresh(win); doupdate();}/* * This is a work-around for the case where we actually need the wide-character * code versus a byte stream. */static int last_getc = ERR;#ifdef USE_WIDE_CURSESstatic char last_getc_bytes[80];static int have_last_getc;static int used_last_getc;#endifintdlg_last_getc(void){#ifdef USE_WIDE_CURSES if (used_last_getc != 1) return ERR; /* not really an error... */#endif return last_getc;}voiddlg_flush_getc(void){ last_getc = ERR;#ifdef USE_WIDE_CURSES have_last_getc = 0; used_last_getc = 0;#endif}/* * Read a character from the given window. Handle repainting here (to simplify * things in the calling application). Also, if input-callback(s) are set up, * poll the corresponding files and handle the updates, e.g., for displaying a * tailbox. */intdlg_getc(WINDOW *win, int *fkey){ WINDOW *save_win = win; int ch = ERR; int result; bool done = FALSE; DIALOG_CALLBACK *p; int interval = MIN(dialog_vars.timeout_secs, WTIMEOUT_VAL); time_t expired = time((time_t *) 0) + dialog_vars.timeout_secs; time_t current; if (dialog_state.getc_callbacks != 0) wtimeout(win, WTIMEOUT_VAL); else if (interval > 0) wtimeout(win, interval); while (!done) {#ifdef USE_WIDE_CURSES int code; mbstate_t state; wchar_t my_wchar; wint_t my_wint; /* * We get a wide character, translate it to multibyte form to avoid * having to change the rest of the code to use wide-characters. */ if (used_last_getc >= have_last_getc) { used_last_getc = 0; have_last_getc = 0; ch = ERR; *fkey = 0; code = wget_wch(win, &my_wint); my_wchar = my_wint; switch (code) { case KEY_CODE_YES: ch = *fkey = my_wchar; last_getc = my_wchar; break; case OK: memset(&state, 0, sizeof(state)); have_last_getc = wcrtomb(last_getc_bytes, my_wchar, &state); if (have_last_getc < 0) { have_last_getc = used_last_getc = 0; last_getc_bytes[0] = my_wchar; } ch = CharOf(last_getc_bytes[used_last_getc++]); last_getc = my_wchar; break; case ERR: ch = ERR; last_getc = ERR; break; default: break; } } else { ch = CharOf(last_getc_bytes[used_last_getc++]); }#else ch = wgetch(win); last_getc = ch; *fkey = (ch > KEY_MIN && ch < KEY_MAX);#endif current = time((time_t *) 0); switch (ch) { case CHR_REPAINT: (void) touchwin(win); (void) wrefresh(curscr); break; case ERR: /* wtimeout() in effect; check for file I/O */ if (interval > 0 && current >= expired) { dlg_exiterr("timeout"); } if (dlg_getc_callbacks(ch, *fkey, &result)) { dlg_raise_window(win); } else { done = (interval <= 0); } break; case TAB: /* Handle tab as a special case for traversing between the nominal * "current" window, and other windows having callbacks. If the * nominal (control) window closes, we'll close the windows with * callbacks. */ if (dialog_state.getc_callbacks != 0) { if ((p = dialog_state.getc_redirect) != 0) { p = p->next; } else { p = dialog_state.getc_callbacks; } if ((dialog_state.getc_redirect = p) != 0) { win = p->win; } else { win = save_win; } dlg_raise_window(win); break; } /* FALLTHRU */ default: if ((p = dialog_state.getc_redirect) != 0) { if (!(p->handle_getc(p, ch, *fkey, &result))) { dlg_remove_callback(p); dialog_state.getc_redirect = 0; win = save_win; } break; } else { done = TRUE; } } } return ch;}static voidfinish_bg(int sig GCC_UNUSED){ dlg_exit(DLG_EXIT_ERROR);}/* * If we have callbacks active, purge the list of all that are not marked * to keep in the background. If any remain, run those in a background * process. */voiddlg_killall_bg(int *retval){ DIALOG_CALLBACK *cb; int pid;#ifdef HAVE_TYPE_UNIONWAIT union wait wstatus;#else int wstatus;#endif if ((cb = dialog_state.getc_callbacks) != 0) { while (cb != 0) { if (cb->keep_bg) { cb = cb->next; } else { dlg_remove_callback(cb); cb = dialog_state.getc_callbacks; } } if (dialog_state.getc_callbacks != 0) { refresh(); fflush(stdout); fflush(stderr); if ((pid = fork()) != 0) { _exit(pid > 0 ? DLG_EXIT_OK : DLG_EXIT_ERROR); } else if (pid == 0) { /* child */ if ((pid = fork()) != 0) { /* * Echo the process-id of the grandchild so a shell script * can read that, and kill that process. We'll wait around * until then. Our parent has already left, leaving us * temporarily orphaned. */ if (pid > 0) { /* parent */ fprintf(stderr, "%d\n", pid); fflush(stderr); } /* wait for child */#ifdef HAVE_WAITPID while (-1 == waitpid(pid, &wstatus, 0)) {#ifdef EINTR if (errno == EINTR) continue;#endif /* EINTR */#ifdef ERESTARTSYS if (errno == ERESTARTSYS) continue;#endif /* ERESTARTSYS */ break; }#else while (wait(&wstatus) != pid) /* do nothing */ ;#endif _exit(WEXITSTATUS(wstatus)); } else if (pid == 0) { if (!dialog_vars.cant_kill) (void) signal(SIGHUP, finish_bg); (void) signal(SIGINT, finish_bg); (void) signal(SIGQUIT, finish_bg); while (dialog_state.getc_callbacks != 0) { int fkey = 0; dlg_getc_callbacks(ERR, fkey, retval); napms(1000); } } } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -