it.po converted in UTF-8, changed some upper/lower convention in a more 'italian...
[midnight-commander.git] / src / key.c
blob10515e9a2bc607a579ab7bd0f9b0a2efcc025913
1 /* Keyboard support routines.
3 Copyright (C) 1994,1995 the Free Software Foundation.
5 Written by: 1994, 1995 Miguel de Icaza.
6 1994, 1995 Janne Kukonlehto.
7 1995 Jakub Jelinek.
8 1997 Norbert Warmuth
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
24 #include <config.h>
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <string.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif
31 #include <ctype.h>
32 #include <errno.h>
34 #include "global.h"
35 #include "tty.h"
36 #include "mouse.h"
37 #include "key.h"
38 #include "main.h"
39 #include "win.h"
40 #include "cons.saver.h"
41 #include "../vfs/vfs.h"
43 #ifdef HAVE_TEXTMODE_X11_SUPPORT
44 #include <X11/Xlib.h>
45 #endif
47 #ifdef __linux__
48 # if defined(__GLIBC__) && (__GLIBC__ < 2)
49 # include <linux/termios.h> /* This is needed for TIOCLINUX */
50 # else
51 # include <termios.h>
52 # endif
53 # include <sys/ioctl.h>
54 #endif
56 #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL))
57 #define DIF_TIME(t1,t2) ((t2.tv_sec -t1.tv_sec) *1000+ \
58 (t2.tv_usec-t1.tv_usec)/1000)
60 /* timeout for old_esc_mode in usec */
61 #define ESCMODE_TIMEOUT 1000000
63 /* Linux console keyboard modifiers */
64 #define SHIFT_PRESSED 1
65 #define ALTR_PRESSED 2
66 #define CONTROL_PRESSED 4
67 #define ALTL_PRESSED 8
70 int mou_auto_repeat = 100;
71 int double_click_speed = 250;
72 int old_esc_mode = 0;
74 int use_8th_bit_as_meta = 1;
76 typedef struct key_def {
77 char ch; /* Holds the matching char code */
78 int code; /* The code returned, valid if child == NULL */
79 struct key_def *next;
80 struct key_def *child; /* sequence continuation */
81 int action; /* optional action to be done. Now used only
82 to mark that we are just after the first
83 Escape */
84 } key_def;
86 /* This holds all the key definitions */
87 static key_def *keys = 0;
89 static int input_fd;
90 static int disabled_channels = 0; /* Disable channels checking */
91 static int xgetch_second (void);
92 static int get_modifier (void);
94 /* File descriptor monitoring add/remove routines */
95 typedef struct SelectList {
96 int fd;
97 select_fn callback;
98 void *info;
99 struct SelectList *next;
100 } SelectList;
102 static SelectList *select_list = 0;
104 void add_select_channel (int fd, select_fn callback, void *info)
106 SelectList *new;
108 new = g_new (SelectList, 1);
109 new->fd = fd;
110 new->callback = callback;
111 new->info = info;
112 new->next = select_list;
113 select_list = new;
116 void delete_select_channel (int fd)
118 SelectList *p = select_list;
119 SelectList *p_prev = 0;
120 SelectList *p_next;
122 while (p) {
123 if (p->fd == fd) {
124 p_next = p->next;
126 if (p_prev)
127 p_prev->next = p_next;
128 else
129 select_list = p_next;
131 g_free (p);
132 p = p_next;
133 continue;
136 p_prev = p;
137 p = p->next;
141 inline static int add_selects (fd_set *select_set)
143 SelectList *p;
144 int top_fd = 0;
146 if (disabled_channels)
147 return 0;
149 for (p = select_list; p; p = p->next){
150 FD_SET (p->fd, select_set);
151 if (p->fd > top_fd)
152 top_fd = p->fd;
154 return top_fd;
157 static void check_selects (fd_set *select_set)
159 SelectList *p;
161 if (disabled_channels)
162 return;
164 for (p = select_list; p; p = p->next)
165 if (FD_ISSET (p->fd, select_set))
166 (*p->callback)(p->fd, p->info);
169 void channels_down (void)
171 disabled_channels ++;
174 void channels_up (void)
176 if (!disabled_channels)
177 fprintf (stderr,
178 "Error: channels_up called with disabled_channels = 0\n");
179 disabled_channels--;
182 typedef const struct {
183 int code;
184 char *seq;
185 int action;
186 } key_define_t;
188 static key_define_t mc_bindings [] = {
189 { KEY_END, ESC_STR ">", MCKEY_NOACTION },
190 { KEY_HOME, ESC_STR "<", MCKEY_NOACTION },
191 { 0, 0, MCKEY_NOACTION },
194 /* Broken terminfo and termcap databases on xterminals */
195 static key_define_t xterm_key_defines [] = {
196 { KEY_F(1), ESC_STR "OP", MCKEY_NOACTION },
197 { KEY_F(2), ESC_STR "OQ", MCKEY_NOACTION },
198 { KEY_F(3), ESC_STR "OR", MCKEY_NOACTION },
199 { KEY_F(4), ESC_STR "OS", MCKEY_NOACTION },
200 { KEY_F(1), ESC_STR "[11~", MCKEY_NOACTION },
201 { KEY_F(2), ESC_STR "[12~", MCKEY_NOACTION },
202 { KEY_F(3), ESC_STR "[13~", MCKEY_NOACTION },
203 { KEY_F(4), ESC_STR "[14~", MCKEY_NOACTION },
204 { KEY_F(5), ESC_STR "[15~", MCKEY_NOACTION },
205 { KEY_F(6), ESC_STR "[17~", MCKEY_NOACTION },
206 { KEY_F(7), ESC_STR "[18~", MCKEY_NOACTION },
207 { KEY_F(8), ESC_STR "[19~", MCKEY_NOACTION },
208 { KEY_F(9), ESC_STR "[20~", MCKEY_NOACTION },
209 { KEY_F(10), ESC_STR "[21~", MCKEY_NOACTION },
211 /* xterm keys with modifiers */
212 { KEY_M_SHIFT | KEY_UP, ESC_STR "O2A", MCKEY_NOACTION },
213 { KEY_M_SHIFT | KEY_DOWN, ESC_STR "O2B", MCKEY_NOACTION },
214 { KEY_M_SHIFT | KEY_RIGHT, ESC_STR "O2C", MCKEY_NOACTION },
215 { KEY_M_SHIFT | KEY_LEFT, ESC_STR "O2D", MCKEY_NOACTION },
216 { KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5;5~", MCKEY_NOACTION },
217 { KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6;5~", MCKEY_NOACTION },
219 /* rxvt keys with modifiers */
220 { KEY_M_SHIFT | KEY_UP, ESC_STR "[a", MCKEY_NOACTION },
221 { KEY_M_SHIFT | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION },
222 { KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION },
223 { KEY_M_SHIFT | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION },
224 { KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5^", MCKEY_NOACTION },
225 { KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6^", MCKEY_NOACTION },
226 { KEY_M_CTRL | KEY_HOME, ESC_STR "[7^", MCKEY_NOACTION },
227 { KEY_M_CTRL | KEY_END, ESC_STR "[8^", MCKEY_NOACTION },
228 { KEY_M_SHIFT | KEY_HOME, ESC_STR "[7$", MCKEY_NOACTION },
229 { KEY_M_SHIFT | KEY_END, ESC_STR "[8$", MCKEY_NOACTION },
231 { 0, 0, MCKEY_NOACTION },
234 static key_define_t mc_default_keys [] = {
235 { ESC_CHAR, ESC_STR, MCKEY_ESCAPE },
236 { ESC_CHAR, ESC_STR ESC_STR, MCKEY_NOACTION },
237 { 0, 0, MCKEY_NOACTION },
240 static void
241 define_sequences (key_define_t *kd)
243 int i;
245 for (i = 0; kd [i].code; i++)
246 define_sequence(kd [i].code, kd [i].seq, kd [i].action);
249 #ifdef HAVE_TEXTMODE_X11_SUPPORT
250 static Display *x11_display;
251 static Window x11_window;
252 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
254 /* This has to be called before slang_init or whatever routine
255 calls any define_sequence */
256 void init_key (void)
258 char *term = (char *) getenv ("TERM");
260 /* This has to be the first define_sequence */
261 /* So, we can assume that the first keys member has ESC */
262 define_sequences (mc_default_keys);
264 /* Terminfo on irix does not have some keys */
265 if ((!strncmp (term, "iris-ansi", 9)) || (!strncmp (term, "xterm", 5)))
266 define_sequences (xterm_key_defines);
268 define_sequences (mc_bindings);
270 /* load some additional keys (e.g. direct Alt-? support) */
271 load_xtra_key_defines();
273 #ifdef __QNX__
274 if (strncmp(term, "qnx", 3) == 0){
275 /* Modify the default value of use_8th_bit_as_meta: we would
276 * like to provide a working mc for a newbie who knows nothing
277 * about [Options|Display bits|Full 8 bits input]...
279 * Don't use 'meta'-bit, when we are dealing with a
280 * 'qnx*'-type terminal: clear the default value!
281 * These terminal types use 0xFF as an escape character,
282 * so use_8th_bit_as_meta==1 must not be enabled!
284 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
285 * is not used now (doesn't even depend on use_8th_bit_as_meta
286 * as in mc-3.1.2)...GREAT!...no additional code is required!]
288 use_8th_bit_as_meta = 0;
290 #endif /* __QNX__ */
292 #ifdef HAVE_TEXTMODE_X11_SUPPORT
293 x11_display = XOpenDisplay (0);
294 if (x11_display)
295 x11_window = DefaultRootWindow (x11_display);
296 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
299 /* This has to be called after SLang_init_tty/slint_init */
300 void init_key_input_fd (void)
302 #ifdef HAVE_SLANG
303 input_fd = SLang_TT_Read_FD;
304 #endif
308 static void
309 xmouse_get_event (Gpm_Event *ev)
311 int btn;
312 static struct timeval tv1 = { 0, 0 }; /* Force first click as single */
313 static struct timeval tv2;
314 static int clicks;
315 static int last_btn = 0;
317 /* Decode Xterm mouse information to a GPM style event */
319 /* Variable btn has following meaning: */
320 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
321 btn = getch () - 32;
323 /* There seems to be no way of knowing which button was released */
324 /* So we assume all the buttons were released */
326 if (btn == 3){
327 if (last_btn) {
328 ev->type = GPM_UP | (GPM_SINGLE << clicks);
329 ev->buttons = 0;
330 last_btn = 0;
331 GET_TIME (tv1);
332 clicks = 0;
333 } else {
334 /* Bogus event, maybe mouse wheel */
335 ev->type = 0;
337 } else {
338 ev->type = GPM_DOWN;
339 GET_TIME (tv2);
340 if (tv1.tv_sec && (DIF_TIME (tv1,tv2) < double_click_speed)){
341 clicks++;
342 clicks %= 3;
343 } else
344 clicks = 0;
346 switch (btn) {
347 case 0:
348 ev->buttons = GPM_B_LEFT;
349 break;
350 case 1:
351 ev->buttons = GPM_B_MIDDLE;
352 break;
353 case 2:
354 ev->buttons = GPM_B_RIGHT;
355 break;
356 case 64:
357 ev->buttons = GPM_B_UP;
358 break;
359 case 65:
360 ev->buttons = GPM_B_DOWN;
361 break;
362 default:
363 /* Nothing */
364 ev->type = 0;
365 ev->buttons = 0;
366 break;
368 last_btn = ev->buttons;
370 /* Coordinates are 33-based */
371 /* Transform them to 1-based */
372 ev->x = getch () - 32;
373 ev->y = getch () - 32;
376 static key_def *create_sequence (char *seq, int code, int action)
378 key_def *base, *p, *attach;
380 for (base = attach = NULL; *seq; seq++){
381 p = g_new (key_def, 1);
382 if (!base) base = p;
383 if (attach) attach->child = p;
385 p->ch = *seq;
386 p->code = code;
387 p->child = p->next = NULL;
388 if (!seq[1])
389 p->action = action;
390 else
391 p->action = MCKEY_NOACTION;
392 attach = p;
394 return base;
397 /* The maximum sequence length (32 + null terminator) */
398 #define SEQ_BUFFER_LEN 33
399 static int seq_buffer [SEQ_BUFFER_LEN];
400 static int *seq_append = 0;
402 static int push_char (int c)
404 if (!seq_append)
405 seq_append = seq_buffer;
407 if (seq_append == &(seq_buffer [SEQ_BUFFER_LEN-2]))
408 return 0;
409 *(seq_append++) = c;
410 *seq_append = 0;
411 return 1;
415 * Return 1 on success, 0 on error.
416 * An error happens if SEQ is a beginning of an existing longer sequence.
418 int define_sequence (int code, char *seq, int action)
420 key_def *base;
422 if (strlen (seq) > SEQ_BUFFER_LEN-1)
423 return 0;
425 for (base = keys; (base != 0) && *seq; ){
426 if (*seq == base->ch){
427 if (base->child == 0){
428 if (*(seq+1)){
429 base->child = create_sequence (seq+1, code, action);
430 return 1;
431 } else {
432 /* The sequence matches an existing one. */
433 base->code = code;
434 base->action = action;
435 return 1;
437 } else {
438 base = base->child;
439 seq++;
441 } else {
442 if (base->next)
443 base = base->next;
444 else {
445 base->next = create_sequence (seq, code, action);
446 return 1;
451 if (!*seq) {
452 /* Attempt to redefine a sequence with a shorter sequence. */
453 return 0;
456 keys = create_sequence (seq, code, action);
457 return 1;
460 static int *pending_keys;
462 /* Apply corrections for the keycode generated in get_key_code() */
463 static int
464 correct_key_code (int code)
466 unsigned int c = code & ~KEY_M_MASK; /* code without modifier */
467 unsigned int mod = code & KEY_M_MASK; /* modifier */
470 * Add key modifiers directly from X11 or OS.
471 * Ordinary characters only get modifiers from sequences.
473 if (c < 32 || c >= 256) {
474 mod |= get_modifier ();
477 /* This is needed if the newline is reported as carriage return */
478 if (c == '\r')
479 c = '\n';
481 /* This is reported to be useful on AIX */
482 if (c == KEY_SCANCEL)
483 c = '\t';
485 /* Convert Shift+Tab and Ctrl+Tab to Back Tab */
486 if ((c == '\t') && (mod & (KEY_M_SHIFT | KEY_M_CTRL))) {
487 c = KEY_BTAB;
488 mod = 0;
491 /* F0 is the same as F10 for out purposes */
492 if (c == KEY_F (0))
493 c = KEY_F (10);
496 * We are not interested if Ctrl was pressed when entering control
497 * characters, so assume that it was. When checking for such keys,
498 * XCTRL macro should be used. In some cases, we are interested,
499 * e.g. to distinguish Ctrl-Enter from Enter.
501 if (c < 32 && c != ESC_CHAR && c != '\t' && c != '\n') {
502 mod |= KEY_M_CTRL;
505 /* Convert Shift+Fn to F(n+10) */
506 if (c >= KEY_F (1) && c <= KEY_F (10) && (mod & KEY_M_SHIFT)) {
507 c += 10;
510 /* Remove Shift information from function keys */
511 if (c >= KEY_F (1) && c <= KEY_F (20)) {
512 mod &= ~KEY_M_SHIFT;
515 if (!alternate_plus_minus)
516 switch (c) {
517 case KEY_KP_ADD:
518 c = '+';
519 break;
520 case KEY_KP_SUBTRACT:
521 c = '-';
522 break;
523 case KEY_KP_MULTIPLY:
524 c = '*';
525 break;
528 return (mod | c);
531 int get_key_code (int no_delay)
533 int c;
534 static key_def *this = NULL, *parent;
535 static struct timeval esctime = { -1, -1 };
536 static int lastnodelay = -1;
538 if (no_delay != lastnodelay) {
539 this = NULL;
540 lastnodelay = no_delay;
543 pend_send:
544 if (pending_keys){
545 int d = *pending_keys++;
546 check_pend:
547 if (!*pending_keys){
548 pending_keys = 0;
549 seq_append = 0;
551 if (d == ESC_CHAR && pending_keys){
552 d = ALT(*pending_keys++);
553 goto check_pend;
555 if ((d & 0x80) && use_8th_bit_as_meta)
556 d = ALT(d & 0x7f);
557 this = NULL;
558 return correct_key_code (d);
561 nodelay_try_again:
562 if (no_delay) {
563 nodelay (stdscr, TRUE);
565 c = getch ();
566 #if defined(USE_NCURSES) && defined(KEY_RESIZE)
567 if (c == KEY_RESIZE)
568 goto nodelay_try_again;
569 #endif
570 if (no_delay) {
571 nodelay (stdscr, FALSE);
572 if (c == -1) {
573 if (this != NULL && parent != NULL &&
574 parent->action == MCKEY_ESCAPE && old_esc_mode) {
575 struct timeval current, timeout;
577 if (esctime.tv_sec == -1)
578 return -1;
579 GET_TIME (current);
580 timeout.tv_sec = ESCMODE_TIMEOUT / 1000000 + esctime.tv_sec;
581 timeout.tv_usec = ESCMODE_TIMEOUT % 1000000 + esctime.tv_usec;
582 if (timeout.tv_usec > 1000000) {
583 timeout.tv_usec -= 1000000;
584 timeout.tv_sec++;
586 if (current.tv_sec < timeout.tv_sec)
587 return -1;
588 if (current.tv_sec == timeout.tv_sec &&
589 current.tv_usec < timeout.tv_usec)
590 return -1;
591 this = NULL;
592 pending_keys = seq_append = NULL;
593 return ESC_CHAR;
595 return -1;
597 } else if (c == -1){
598 /* Maybe we got an incomplete match.
599 This we do only in delay mode, since otherwise
600 getch can return -1 at any time. */
601 if (seq_append) {
602 pending_keys = seq_buffer;
603 goto pend_send;
605 this = NULL;
606 return -1;
609 /* Search the key on the root */
610 if (!no_delay || this == NULL) {
611 this = keys;
612 parent = NULL;
614 if ((c & 0x80) && use_8th_bit_as_meta) {
615 c &= 0x7f;
617 /* The first sequence defined starts with esc */
618 parent = keys;
619 this = keys->child;
622 while (this){
623 if (c == this->ch){
624 if (this->child){
625 if (!push_char (c)){
626 pending_keys = seq_buffer;
627 goto pend_send;
629 parent = this;
630 this = this->child;
631 if (parent->action == MCKEY_ESCAPE && old_esc_mode) {
632 if (no_delay) {
633 GET_TIME (esctime);
634 if (this == NULL) {
635 /* Shouldn't happen */
636 fprintf (stderr, "Internal error\n");
637 exit (1);
639 goto nodelay_try_again;
641 esctime.tv_sec = -1;
642 c = xgetch_second ();
643 if (c == -1) {
644 pending_keys = seq_append = NULL;
645 this = NULL;
646 return ESC_CHAR;
648 } else {
649 if (no_delay)
650 goto nodelay_try_again;
651 c = getch ();
653 } else {
654 /* We got a complete match, return and reset search */
655 int code;
657 pending_keys = seq_append = NULL;
658 code = this->code;
659 this = NULL;
660 return correct_key_code (code);
662 } else {
663 if (this->next)
664 this = this->next;
665 else {
666 if (parent != NULL && parent->action == MCKEY_ESCAPE) {
667 /* This is just to save a lot of define_sequences */
668 if (isalpha(c)
669 || (c == '\n') || (c == '\t') || (c == XCTRL('h'))
670 || (c == KEY_BACKSPACE) || (c == '!') || (c == '\r')
671 || c == 127 || c == '+' || c == '-' || c == '\\'
672 || c == '?')
673 c = ALT(c);
674 else if (isdigit(c))
675 c = KEY_F (c-'0');
676 else if (c == ' ')
677 c = ESC_CHAR;
678 pending_keys = seq_append = NULL;
679 this = NULL;
680 return correct_key_code (c);
682 /* Did not find a match or {c} was changed in the if above,
683 so we have to return everything we had skipped
685 push_char (c);
686 pending_keys = seq_buffer;
687 goto pend_send;
691 this = NULL;
692 return correct_key_code (c);
695 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
696 static void
697 try_channels (int set_timeout)
699 struct timeval timeout;
700 static fd_set select_set;
701 struct timeval *timeptr;
702 int v;
703 int maxfdp;
705 while (1){
706 FD_ZERO (&select_set);
707 FD_SET (input_fd, &select_set); /* Add stdin */
708 maxfdp = max (add_selects (&select_set), input_fd);
710 if (set_timeout){
711 timeout.tv_sec = 0;
712 timeout.tv_usec = 100000;
713 timeptr = &timeout;
714 } else
715 timeptr = 0;
717 v = select (maxfdp + 1, &select_set, NULL, NULL, timeptr);
718 if (v > 0){
719 check_selects (&select_set);
720 if (FD_ISSET (input_fd, &select_set))
721 return;
726 /* Workaround for System V Curses vt100 bug */
727 static int getch_with_delay (void)
729 int c;
731 /* This routine could be used on systems without mouse support,
732 so we need to do the select check :-( */
733 while (1){
734 if (!pending_keys)
735 try_channels (0);
737 /* Try to get a character */
738 c = get_key_code (0);
739 if (c != -1)
740 break;
741 /* Failed -> wait 0.1 secs and try again */
742 try_channels (1);
744 /* Success -> return the character */
745 return c;
748 /* Returns a character read from stdin with appropriate interpretation */
749 /* Also takes care of generated mouse events */
750 /* Returns EV_MOUSE if it is a mouse event */
751 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
753 get_event (Gpm_Event * event, int redo_event, int block)
755 int c;
756 static int flag; /* Return value from select */
757 #ifdef HAVE_LIBGPM
758 static Gpm_Event ev; /* Mouse event */
759 #endif
760 struct timeval timeout;
761 struct timeval *time_addr = NULL;
762 static int dirty = 3;
764 if ((dirty == 3) || is_idle ()) {
765 mc_refresh ();
766 doupdate ();
767 dirty = 1;
768 } else
769 dirty++;
771 vfs_timeout_handler ();
773 /* Ok, we use (event->x < 0) to signal that the event does not contain
774 a suitable position for the mouse, so we can't use show_mouse_pointer
775 on it.
777 if (event->x > 0) {
778 show_mouse_pointer (event->x, event->y);
779 if (!redo_event)
780 event->x = -1;
783 /* Repeat if using mouse */
784 while (mouse_enabled && !pending_keys) {
785 int maxfdp;
786 fd_set select_set;
788 FD_ZERO (&select_set);
789 FD_SET (input_fd, &select_set);
790 maxfdp = max (add_selects (&select_set), input_fd);
792 #ifdef HAVE_LIBGPM
793 if (use_mouse_p == MOUSE_GPM) {
794 if (gpm_fd == -1) {
795 /* Connection to gpm broken, possibly gpm has died */
796 mouse_enabled = 0;
797 use_mouse_p = MOUSE_NONE;
798 break;
800 FD_SET (gpm_fd, &select_set);
801 maxfdp = max (maxfdp, gpm_fd);
803 #endif
805 if (redo_event) {
806 timeout.tv_usec = mou_auto_repeat * 1000;
807 timeout.tv_sec = 0;
809 time_addr = &timeout;
810 } else {
811 int seconds;
813 if ((seconds = vfs_timeouts ())) {
814 /* the timeout could be improved and actually be
815 * the number of seconds until the next vfs entry
816 * timeouts in the stamp list.
819 timeout.tv_sec = seconds;
820 timeout.tv_usec = 0;
821 time_addr = &timeout;
822 } else
823 time_addr = NULL;
826 if (!block) {
827 time_addr = &timeout;
828 timeout.tv_sec = 0;
829 timeout.tv_usec = 0;
831 enable_interrupt_key ();
832 flag = select (maxfdp + 1, &select_set, NULL, NULL, time_addr);
833 disable_interrupt_key ();
835 /* select timed out: it could be for any of the following reasons:
836 * redo_event -> it was because of the MOU_REPEAT handler
837 * !block -> we did not block in the select call
838 * else -> 10 second timeout to check the vfs status.
840 if (flag == 0) {
841 if (redo_event)
842 return EV_MOUSE;
843 if (!block)
844 return EV_NONE;
845 vfs_timeout_handler ();
847 if (flag == -1 && errno == EINTR)
848 return EV_NONE;
850 check_selects (&select_set);
852 if (FD_ISSET (input_fd, &select_set))
853 break;
854 #ifdef HAVE_LIBGPM
855 if (use_mouse_p == MOUSE_GPM && FD_ISSET (gpm_fd, &select_set)) {
856 Gpm_GetEvent (&ev);
857 Gpm_FitEvent (&ev);
858 *event = ev;
859 return EV_MOUSE;
861 #endif /* !HAVE_LIBGPM */
863 #ifndef HAVE_SLANG
864 flag = is_wintouched (stdscr);
865 untouchwin (stdscr);
866 #endif /* !HAVE_SLANG */
867 c = block ? getch_with_delay () : get_key_code (1);
869 #ifndef HAVE_SLANG
870 if (flag)
871 touchwin (stdscr);
872 #endif /* !HAVE_SLANG */
874 if (c == MCKEY_MOUSE
875 #ifdef KEY_MOUSE
876 || c == KEY_MOUSE
877 #endif /* KEY_MOUSE */
879 /* Mouse event */
880 xmouse_get_event (event);
881 if (event->type)
882 return EV_MOUSE;
883 else
884 return EV_NONE;
887 return c;
890 /* Returns a key press, mouse events are discarded */
891 int mi_getch ()
893 Gpm_Event ev;
894 int key;
896 ev.x = -1;
897 while ((key = get_event (&ev, 0, 1)) == EV_NONE)
899 return key;
902 static int xgetch_second (void)
904 fd_set Read_FD_Set;
905 int c;
906 struct timeval timeout;
908 timeout.tv_sec = ESCMODE_TIMEOUT / 1000000;
909 timeout.tv_usec = ESCMODE_TIMEOUT % 1000000;
910 nodelay (stdscr, TRUE);
911 FD_ZERO (&Read_FD_Set);
912 FD_SET (input_fd, &Read_FD_Set);
913 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &timeout);
914 c = getch ();
915 nodelay (stdscr, FALSE);
916 return c;
919 static void
920 learn_store_key (char *buffer, char **p, int c)
922 if (*p - buffer > 253)
923 return;
924 if (c == ESC_CHAR) {
925 *(*p)++ = '\\';
926 *(*p)++ = 'e';
927 } else if (c < ' ') {
928 *(*p)++ = '^';
929 *(*p)++ = c + 'a' - 1;
930 } else if (c == '^') {
931 *(*p)++ = '^';
932 *(*p)++ = '^';
933 } else
934 *(*p)++ = (char) c;
937 char *learn_key (void)
939 /* LEARN_TIMEOUT in usec */
940 #define LEARN_TIMEOUT 200000
942 fd_set Read_FD_Set;
943 struct timeval endtime;
944 struct timeval timeout;
945 int c;
946 char buffer [256];
947 char *p = buffer;
949 keypad(stdscr, FALSE); /* disable intepreting keys by ncurses */
950 c = getch ();
951 while (c == -1)
952 c = getch (); /* Sanity check, should be unnecessary */
953 learn_store_key (buffer, &p, c);
954 GET_TIME (endtime);
955 endtime.tv_usec += LEARN_TIMEOUT;
956 if (endtime.tv_usec > 1000000) {
957 endtime.tv_usec -= 1000000;
958 endtime.tv_sec++;
960 nodelay (stdscr, TRUE);
961 for (;;) {
962 while ((c = getch ()) == -1) {
963 GET_TIME (timeout);
964 timeout.tv_usec = endtime.tv_usec - timeout.tv_usec;
965 if (timeout.tv_usec < 0)
966 timeout.tv_sec++;
967 timeout.tv_sec = endtime.tv_sec - timeout.tv_sec;
968 if (timeout.tv_sec >= 0 && timeout.tv_usec > 0) {
969 FD_ZERO (&Read_FD_Set);
970 FD_SET (input_fd, &Read_FD_Set);
971 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &timeout);
972 } else
973 break;
975 if (c == -1)
976 break;
977 learn_store_key (buffer, &p, c);
979 keypad(stdscr, TRUE);
980 nodelay (stdscr, FALSE);
981 *p = 0;
982 return g_strdup (buffer);
985 /* xterm and linux console only: set keypad to numeric or application
986 mode. Only in application keypad mode it's possible to distinguish
987 the '+' key and the '+' on the keypad ('*' and '-' ditto)*/
988 void
989 numeric_keypad_mode (void)
991 if (console_flag || xterm_flag) {
992 fprintf (stdout, "\033>");
993 fflush (stdout);
997 void
998 application_keypad_mode (void)
1000 if (console_flag || xterm_flag) {
1001 fprintf (stdout, "\033=");
1002 fflush (stdout);
1008 * Check if we are idle, i.e. there are no pending keyboard or mouse
1009 * events. Return 1 is idle, 0 is there are pending events.
1012 is_idle (void)
1014 int maxfdp;
1015 fd_set select_set;
1016 struct timeval timeout;
1018 FD_ZERO (&select_set);
1019 FD_SET (input_fd, &select_set);
1020 maxfdp = input_fd;
1021 #ifdef HAVE_LIBGPM
1022 if (use_mouse_p == MOUSE_GPM && mouse_enabled && gpm_fd != -1) {
1023 FD_SET (gpm_fd, &select_set);
1024 maxfdp = max (maxfdp, gpm_fd);
1026 #endif
1027 timeout.tv_sec = 0;
1028 timeout.tv_usec = 0;
1029 return (select (maxfdp + 1, &select_set, 0, 0, &timeout) <= 0);
1034 * Get modifier state (shift, alt, ctrl) for the last key pressed.
1035 * We are assuming that the state didn't change since the key press.
1036 * This is only correct if get_modifier() is called very fast after
1037 * the input was received, so that the user didn't release the
1038 * modifier keys yet.
1040 static int
1041 get_modifier (void)
1043 int result = 0;
1045 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1046 if (x11_display) {
1047 Window root, child;
1048 int root_x, root_y;
1049 int win_x, win_y;
1050 unsigned int mask;
1052 XQueryPointer (x11_display, x11_window, &root, &child, &root_x,
1053 &root_y, &win_x, &win_y, &mask);
1055 if (mask & ShiftMask)
1056 result |= KEY_M_SHIFT;
1057 if (mask & ControlMask)
1058 result |= KEY_M_CTRL;
1059 return result;
1061 #endif
1062 #ifdef __linux__
1064 unsigned char modifiers = 6;
1066 if (ioctl (0, TIOCLINUX, &modifiers) < 0)
1067 return 0;
1069 /* Translate Linux modifiers into mc modifiers */
1070 if (modifiers & SHIFT_PRESSED)
1071 result |= KEY_M_SHIFT;
1072 if (modifiers & (ALTL_PRESSED | ALTR_PRESSED))
1073 result |= KEY_M_ALT;
1074 if (modifiers & CONTROL_PRESSED)
1075 result |= KEY_M_CTRL;
1077 return result;
1079 #else
1080 return result;
1081 #endif
1084 static void k_dispose (key_def *k)
1086 if (!k)
1087 return;
1088 k_dispose (k->child);
1089 k_dispose (k->next);
1090 g_free (k);
1093 static void s_dispose (SelectList *sel)
1095 if (!sel)
1096 return;
1098 s_dispose (sel->next);
1099 g_free (sel);
1102 void done_key ()
1104 k_dispose (keys);
1105 s_dispose (select_list);
1107 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1108 if (x11_display)
1109 XCloseDisplay (x11_display);
1110 #endif /* HAVE_TEXTMODE_X11_SUPPORT */