📄 key.c
字号:
}
return ERR;
}
} else if (c == ERR){
/* Maybe we got an incomplete match.
This we do only in delay mode, since otherwise
xgetch can return ERR at any time. */
if (seq_append) {
pending_keys = seq_buffer;
goto pend_send;
}
this = NULL;
return ERR;
}
/* Search the key on the root */
if (!no_delay || this == NULL) {
this = keys;
parent = NULL;
if ((c & 0x80) && use_8th_bit_as_meta) {
c &= ~0x7f;
/* The first sequence defined starts with esc */
parent = keys;
this = keys->child;
}
}
while (this){
if (c == this->ch){
if (this->child){
if (!push_char (c)){
pending_keys = seq_buffer;
goto pend_send;
}
parent = this;
this = this->child;
if (parent->action == MCKEY_ESCAPE && old_esc_mode) {
if (no_delay) {
GET_TIME (esctime);
if (this == NULL) {
/* Shouldn't happen */
fprintf (stderr, "Internal error\n");
exit (1);
}
goto nodelay_try_again;
}
esctime.tv_sec = -1;
c = xgetch_second ();
if (c == ERR) {
pending_keys = seq_append = NULL;
this = NULL;
return ESC_CHAR;
}
} else {
if (no_delay)
goto nodelay_try_again;
c = xgetch ();
}
} else {
/* We got a complete match, return and reset search */
int code;
pending_keys = seq_append = NULL;
code = this->code;
this = NULL;
return correct_key_code (code);
}
} else {
if (this->next)
this = this->next;
else {
if (parent != NULL && parent->action == MCKEY_ESCAPE) {
/* This is just to save a lot of define_sequences */
if (isalpha(c)
|| (c == '\n') || (c == '\t') || (c == XCTRL('h'))
|| (c == KEY_BACKSPACE) || (c == '!') || (c == '\r')
|| c == 127 || c == '+' || c == '-' || c == '\\'
|| c == '?')
c = ALT(c);
else if (isdigit(c))
c = KEY_F (c-'0');
else if (c == ' ')
c = ESC_CHAR;
pending_keys = seq_append = NULL;
this = NULL;
return correct_key_code (c);
}
/* Did not find a match or {c} was changed in the if above,
so we have to return everything we had skipped
*/
push_char (c);
pending_keys = seq_buffer;
goto pend_send;
}
}
}
this = NULL;
return correct_key_code (c);
#else
return ERR;
#endif /* HAVE_X */
}
#ifndef PORT_HAS_FILE_HANDLERS
/* If set timeout is set, then we wait 0.1 seconds, else, we block */
void try_channels (int set_timeout)
{
struct timeval timeout;
static fd_set select_set;
struct timeval *timeptr;
int v;
while (1){
FD_ZERO (&select_set);
FD_SET (input_fd, &select_set); /* Add stdin */
add_selects (&select_set);
if (set_timeout){
timeout.tv_sec = 0;
timeout.tv_usec = 100000;
timeptr = &timeout;
} else
timeptr = 0;
v = select (FD_SETSIZE, &select_set, NULL, NULL, timeptr);
if (v > 0){
check_selects (&select_set);
if (FD_ISSET (input_fd, &select_set))
return;
}
}
}
#ifndef HAVE_X
/* Workaround for System V Curses vt100 bug */
static int getch_with_delay (void)
{
int c;
/* This routine could be used on systems without mouse support,
so we need to do the select check :-( */
while (1){
if (!pending_keys)
try_channels (0);
/* Try to get a character */
c = get_key_code (0);
if (c != ERR)
break;
/* Failed -> wait 0.1 secs and try again */
try_channels (1);
}
/* Success -> return the character */
return c;
}
#endif /* !HAVE_X */
#ifndef HAVE_LIBGPM
#define gpm_flag 0
#endif
#endif /* !HAVE_FILE_HANDLERS */
extern int max_dirt_limit;
/* Returns a character read from stdin with appropriate interpretation */
/* Also takes care of generated mouse events */
/* Returns EV_MOUSE if it is a mouse event */
/* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
int get_event (Gpm_Event *event, int redo_event, int block)
{
#ifndef HAVE_X
int c;
static int flag; /* Return value from select */
#ifdef HAVE_LIBGPM
static Gpm_Event ev; /* Mouse event */
#endif
struct timeval timeout;
struct timeval *time_addr = NULL;
static int dirty = 3;
if ((dirty == 3) || is_idle ()){
mc_refresh ();
doupdate ();
dirty = 1;
} else
dirty++;
vfs_timeout_handler ();
/* Ok, we use (event->x < 0) to signal that the event does not contain
a suitable position for the mouse, so we can't use show_mouse_pointer
on it.
*/
if (event->x > 0){
show_mouse_pointer (event->x, event->y);
if (!redo_event)
event->x = -1;
}
/* Repeat if using mouse */
while ((xmouse_flag || gpm_flag) && !pending_keys)
{
if (xmouse_flag || gpm_flag)
{
FD_ZERO (&select_set);
FD_SET (input_fd, &select_set);
add_selects (&select_set);
#ifdef HAVE_LIBGPM
if (gpm_flag) {
FD_SET (gpm_fd, &select_set);
}
#endif
if (redo_event){
timeout.tv_usec = mou_auto_repeat * 1000;
timeout.tv_sec = 0;
time_addr = &timeout;
} else {
int seconds;
if ((seconds = vfs_timeouts ())){
/* the timeout could be improved and actually be
* the number of seconds until the next vfs entry
* timeouts in the stamp list.
*/
timeout.tv_sec = seconds;
timeout.tv_usec = 0;
time_addr = &timeout;
} else
time_addr = NULL;
}
if (!block){
time_addr = &timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
}
enable_interrupt_key ();
flag = select (FD_SETSIZE, &select_set, NULL, NULL, time_addr);
disable_interrupt_key ();
/* select timed out: it could be for any of the following reasons:
* redo_event -> it was because of the MOU_REPEAT handler
* !block -> we did not block in the select call
* else -> 10 second timeout to check the vfs status.
*/
if (flag == 0){
if (redo_event)
return EV_MOUSE;
if (!block)
return EV_NONE;
vfs_timeout_handler ();
}
if (flag == -1 && errno == EINTR)
return EV_NONE;
check_selects (&select_set);
if (FD_ISSET (input_fd, &select_set))
break;
}
#ifdef HAVE_LIBGPM
if (gpm_flag && FD_ISSET (gpm_fd, &select_set)){
if (gpm_flag){
Gpm_GetEvent (&ev);
Gpm_FitEvent (&ev);
}
*event = ev;
return EV_MOUSE;
}
#endif
}
# ifndef HAVE_SLANG
flag = is_wintouched(stdscr);
untouchwin (stdscr);
# endif
c = block ? getch_with_delay () : get_key_code(1);
# ifndef HAVE_SLANG
if (flag)
touchwin (stdscr);
# endif
if (c == MCKEY_MOUSE) { /* Mouse event */
xmouse_get_event (event);
return EV_MOUSE;
}
return c;
#else
return EV_NONE;
#endif /* HAVE_X */
}
#ifndef PORT_HAS_GETCH
/* Returns a key press, mouse events are discarded */
int mi_getch ()
{
Gpm_Event ev;
int key;
ev.x = -1;
while ((key = get_event (&ev, 0, 1)) == 0)
;
return key;
}
#endif
int xgetch_second (void)
{
fd_set Read_FD_Set;
int c;
struct timeval timeout;
timeout.tv_sec = ESCMODE_TIMEOUT / 1000000;
timeout.tv_usec = ESCMODE_TIMEOUT % 1000000;
#ifdef BUGGY_CURSES
wtimeout(stdscr, 500);
#else
nodelay (stdscr, TRUE);
#endif
FD_ZERO (&Read_FD_Set);
FD_SET (input_fd, &Read_FD_Set);
select (FD_SETSIZE, &Read_FD_Set, NULL, NULL, &timeout);
c = xgetch ();
#ifdef BUGGY_CURSES
notimeout (stdscr, TRUE);
#else
nodelay (stdscr, FALSE);
#endif
return c;
}
#ifndef HAVE_X
void learn_store_key (char *buffer, char **p, int c)
{
if (*p - buffer > 253)
return;
if (c == ESC_CHAR) {
*(*p)++ = '\\';
*(*p)++ = 'e';
} else if (c < ' ') {
*(*p)++ = '^';
*(*p)++ = c + 'a' - 1;
} else if (c == '^') {
*(*p)++ = '^';
*(*p)++ = '^';
} else
*(*p)++ = (char) c;
}
char *learn_key (void)
{
/* LEARN_TIMEOUT in usec */
#define LEARN_TIMEOUT 200000
fd_set Read_FD_Set;
struct timeval endtime;
struct timeval timeout;
int c = xgetch ();
char buffer [256];
char *p = buffer;
while (c == ERR)
c = xgetch (); /* Sanity check, should be unnecessary */
learn_store_key (buffer, &p, c);
GET_TIME (endtime);
endtime.tv_usec += LEARN_TIMEOUT;
if (endtime.tv_usec > 1000000) {
endtime.tv_usec -= 1000000;
endtime.tv_sec++;
}
#ifdef BUGGY_CURSES
wtimeout(stdscr, 500);
#else
nodelay (stdscr, TRUE);
#endif
for (;;) {
while ((c = xgetch ()) == ERR) {
GET_TIME (timeout);
timeout.tv_usec = endtime.tv_usec - timeout.tv_usec;
if (timeout.tv_usec < 0)
timeout.tv_sec++;
timeout.tv_sec = endtime.tv_sec - timeout.tv_sec;
if (timeout.tv_sec >= 0 && timeout.tv_usec > 0) {
FD_ZERO (&Read_FD_Set);
FD_SET (input_fd, &Read_FD_Set);
select (FD_SETSIZE, &Read_FD_Set, NULL, NULL, &timeout);
} else
break;
}
if (c == ERR)
break;
learn_store_key (buffer, &p, c);
}
#ifdef BUGGY_CURSES
notimeout (stdscr, TRUE);
#else
nodelay (stdscr, FALSE);
#endif
*p = 0;
return strdup (buffer);
}
/* xterm and linux console only: set keypad to numeric or application
mode. Only in application keypad mode it's possible to distinguish
the '+' key and the '+' on the keypad ('*' and '-' ditto)*/
void
numeric_keypad_mode (void)
{
if (console_flag || xterm_flag) {
fprintf (stdout, "\033>");
fflush (stdout);
}
}
void
application_keypad_mode (void)
{
if (console_flag || xterm_flag) {
fprintf (stdout, "\033=");
fflush (stdout);
}
}
#endif /* !HAVE_X */
/* A function to check if we're idle.
Currently checks only for key presses.
We could also check the mouse. */
int is_idle (void)
{
/* Check for incoming key presses *
* If there are any we say we're busy */
fd_set select_set;
struct timeval timeout;
FD_ZERO (&select_set);
FD_SET (0, &select_set);
timeout.tv_sec = 0;
timeout.tv_usec = 0;
select (FD_SETSIZE, &select_set, 0, 0, &timeout);
return ! FD_ISSET (0, &select_set);
}
int get_modifier ()
{
#ifdef __linux__
unsigned char modifiers;
modifiers = 6;
if (ioctl (0, TIOCLINUX, &modifiers) < 0)
return 0;
return (int) modifiers;
#else
return 0;
#endif
}
int ctrl_pressed ()
{
#ifdef __linux__
if (get_modifier () & CONTROL_PRESSED)
return 1;
#endif
return 0;
}
#ifdef HAVE_MAD
#ifndef HAVE_X
void k_dispose (key_def *k)
{
if (!k)
return;
k_dispose (k->child);
k_dispose (k->next);
free (k);
}
void s_dispose (SelectList *sel)
{
if (!sel)
return;
s_dispose (sel->next);
free (sel);
}
void done_key ()
{
k_dispose (keys);
s_dispose (select_list);
}
#else
void done_key ()
{
}
#endif /* HAVE_X */
#endif /* HAVE_MAD */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -