Just a little correction at the it.po file.
[midnight-commander.git] / src / key.c
blob5a1d9354e1acec980aa28a2ae8e15c7b0e5541da
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 #ifdef HAVE_GMODULE
45 #include <gmodule.h>
46 #endif /* HAVE_GMODULE */
47 #include <X11/Xlib.h>
48 #endif
50 #ifdef __linux__
51 # if defined(__GLIBC__) && (__GLIBC__ < 2)
52 # include <linux/termios.h> /* TIOCLINUX */
53 # else
54 # include <termios.h>
55 # endif
56 # include <sys/ioctl.h>
57 #endif /* __linux__ */
59 #ifdef __QNXNTO__
60 # include <dlfcn.h>
61 # include <Ph.h>
62 # include <sys/dcmd_chr.h>
63 #endif
65 #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL))
66 #define DIF_TIME(t1,t2) ((t2.tv_sec -t1.tv_sec) *1000+ \
67 (t2.tv_usec-t1.tv_usec)/1000)
69 /* timeout for old_esc_mode in usec */
70 #define ESCMODE_TIMEOUT 1000000
72 /* Linux console keyboard modifiers */
73 #define SHIFT_PRESSED 1
74 #define ALTR_PRESSED 2
75 #define CONTROL_PRESSED 4
76 #define ALTL_PRESSED 8
79 int mou_auto_repeat = 100;
80 int double_click_speed = 250;
81 int old_esc_mode = 0;
83 int use_8th_bit_as_meta = 1;
85 typedef struct key_def {
86 char ch; /* Holds the matching char code */
87 int code; /* The code returned, valid if child == NULL */
88 struct key_def *next;
89 struct key_def *child; /* sequence continuation */
90 int action; /* optional action to be done. Now used only
91 to mark that we are just after the first
92 Escape */
93 } key_def;
95 /* This holds all the key definitions */
96 static key_def *keys = 0;
98 static int input_fd;
99 static int disabled_channels = 0; /* Disable channels checking */
100 static int xgetch_second (void);
101 static int get_modifier (void);
103 /* File descriptor monitoring add/remove routines */
104 typedef struct SelectList {
105 int fd;
106 select_fn callback;
107 void *info;
108 struct SelectList *next;
109 } SelectList;
111 #ifdef __QNXNTO__
112 typedef int (*ph_dv_f) (void *, void *);
113 typedef int (*ph_ov_f) (void *);
114 typedef int (*ph_pqc_f) (unsigned short, PhCursorInfo_t *);
115 ph_dv_f ph_attach;
116 ph_ov_f ph_input_group;
117 ph_pqc_f ph_query_cursor;
118 #endif
120 static SelectList *select_list = 0;
122 void add_select_channel (int fd, select_fn callback, void *info)
124 SelectList *new;
126 new = g_new (SelectList, 1);
127 new->fd = fd;
128 new->callback = callback;
129 new->info = info;
130 new->next = select_list;
131 select_list = new;
134 void delete_select_channel (int fd)
136 SelectList *p = select_list;
137 SelectList *p_prev = 0;
138 SelectList *p_next;
140 while (p) {
141 if (p->fd == fd) {
142 p_next = p->next;
144 if (p_prev)
145 p_prev->next = p_next;
146 else
147 select_list = p_next;
149 g_free (p);
150 p = p_next;
151 continue;
154 p_prev = p;
155 p = p->next;
159 inline static int add_selects (fd_set *select_set)
161 SelectList *p;
162 int top_fd = 0;
164 if (disabled_channels)
165 return 0;
167 for (p = select_list; p; p = p->next){
168 FD_SET (p->fd, select_set);
169 if (p->fd > top_fd)
170 top_fd = p->fd;
172 return top_fd;
175 static void check_selects (fd_set *select_set)
177 SelectList *p;
179 if (disabled_channels)
180 return;
182 for (p = select_list; p; p = p->next)
183 if (FD_ISSET (p->fd, select_set))
184 (*p->callback)(p->fd, p->info);
187 void channels_down (void)
189 disabled_channels ++;
192 void channels_up (void)
194 if (!disabled_channels)
195 fputs ("Error: channels_up called with disabled_channels = 0\n",
196 stderr);
197 disabled_channels--;
200 typedef const struct {
201 int code;
202 char *seq;
203 int action;
204 } key_define_t;
206 static key_define_t mc_bindings [] = {
207 { KEY_END, ESC_STR ">", MCKEY_NOACTION },
208 { KEY_HOME, ESC_STR "<", MCKEY_NOACTION },
209 { 0, 0, MCKEY_NOACTION },
212 /* Broken terminfo and termcap databases on xterminals */
213 static key_define_t xterm_key_defines [] = {
214 { KEY_F(1), ESC_STR "OP", MCKEY_NOACTION },
215 { KEY_F(2), ESC_STR "OQ", MCKEY_NOACTION },
216 { KEY_F(3), ESC_STR "OR", MCKEY_NOACTION },
217 { KEY_F(4), ESC_STR "OS", MCKEY_NOACTION },
218 { KEY_F(1), ESC_STR "[11~", MCKEY_NOACTION },
219 { KEY_F(2), ESC_STR "[12~", MCKEY_NOACTION },
220 { KEY_F(3), ESC_STR "[13~", MCKEY_NOACTION },
221 { KEY_F(4), ESC_STR "[14~", MCKEY_NOACTION },
222 { KEY_F(5), ESC_STR "[15~", MCKEY_NOACTION },
223 { KEY_F(6), ESC_STR "[17~", MCKEY_NOACTION },
224 { KEY_F(7), ESC_STR "[18~", MCKEY_NOACTION },
225 { KEY_F(8), ESC_STR "[19~", MCKEY_NOACTION },
226 { KEY_F(9), ESC_STR "[20~", MCKEY_NOACTION },
227 { KEY_F(10), ESC_STR "[21~", MCKEY_NOACTION },
229 /* xterm keys with modifiers */
230 { KEY_M_SHIFT | KEY_UP, ESC_STR "O2A", MCKEY_NOACTION },
231 { KEY_M_SHIFT | KEY_DOWN, ESC_STR "O2B", MCKEY_NOACTION },
232 { KEY_M_SHIFT | KEY_RIGHT, ESC_STR "O2C", MCKEY_NOACTION },
233 { KEY_M_SHIFT | KEY_LEFT, ESC_STR "O2D", MCKEY_NOACTION },
234 { KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5;5~", MCKEY_NOACTION },
235 { KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6;5~", MCKEY_NOACTION },
236 { KEY_M_CTRL | KEY_IC, ESC_STR "[2;5~", MCKEY_NOACTION },
237 { KEY_M_CTRL | KEY_DC, ESC_STR "[3;5~", MCKEY_NOACTION },
239 /* rxvt keys with modifiers */
240 { KEY_M_SHIFT | KEY_UP, ESC_STR "[a", MCKEY_NOACTION },
241 { KEY_M_SHIFT | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION },
242 { KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION },
243 { KEY_M_SHIFT | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION },
244 { KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5^", MCKEY_NOACTION },
245 { KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6^", MCKEY_NOACTION },
246 { KEY_M_CTRL | KEY_HOME, ESC_STR "[7^", MCKEY_NOACTION },
247 { KEY_M_CTRL | KEY_END, ESC_STR "[8^", MCKEY_NOACTION },
248 { KEY_M_SHIFT | KEY_HOME, ESC_STR "[7$", MCKEY_NOACTION },
249 { KEY_M_SHIFT | KEY_END, ESC_STR "[8$", MCKEY_NOACTION },
250 { KEY_M_CTRL | KEY_IC, ESC_STR "[2^", MCKEY_NOACTION },
251 { KEY_M_CTRL | KEY_DC, ESC_STR "[3^", MCKEY_NOACTION },
252 { KEY_M_SHIFT | KEY_DC, ESC_STR "[3$", MCKEY_NOACTION },
254 /* konsole keys with modifiers */
255 { KEY_M_SHIFT | KEY_HOME, ESC_STR "O2H", MCKEY_NOACTION },
256 { KEY_M_SHIFT | KEY_END, ESC_STR "O2F", MCKEY_NOACTION },
257 { KEY_M_SHIFT | KEY_DC, ESC_STR "[3;2~", MCKEY_NOACTION },
259 { 0, 0, MCKEY_NOACTION },
262 static key_define_t mc_default_keys [] = {
263 { ESC_CHAR, ESC_STR, MCKEY_ESCAPE },
264 { ESC_CHAR, ESC_STR ESC_STR, MCKEY_NOACTION },
265 { 0, 0, MCKEY_NOACTION },
268 static void
269 define_sequences (key_define_t *kd)
271 int i;
273 for (i = 0; kd [i].code; i++)
274 define_sequence(kd [i].code, kd [i].seq, kd [i].action);
277 #ifdef HAVE_TEXTMODE_X11_SUPPORT
279 #ifdef HAVE_GMODULE
280 static int (*func_XCloseDisplay) (Display *);
281 static Bool (*func_XQueryPointer) (Display *, Window, Window *, Window *,
282 int *, int *, int *, int *,
283 unsigned int *);
285 static GModule *x11_module;
286 #endif /* HAVE_GMODULE */
288 static Display *x11_display;
289 static Window x11_window;
291 static void
292 init_key_x11 (void)
294 #ifdef HAVE_GMODULE
295 static Display *(*func_XOpenDisplay) (_Xconst char *);
296 gchar *x11_module_fname;
297 #endif /* HAVE_GMODULE */
299 if (!getenv ("DISPLAY"))
300 return;
302 #ifdef HAVE_GMODULE
303 x11_module_fname = g_module_build_path (NULL, "X11");
305 if (!x11_module_fname)
306 return;
308 x11_module = g_module_open (x11_module_fname, G_MODULE_BIND_LAZY);
309 g_free (x11_module_fname);
311 if (!x11_module)
312 return;
314 if (g_module_symbol
315 (x11_module, "XOpenDisplay", (gpointer *) & func_XOpenDisplay)
316 && g_module_symbol (x11_module, "XCloseDisplay",
317 (gpointer *) & func_XCloseDisplay)
318 && g_module_symbol (x11_module, "XQueryPointer",
319 (gpointer *) & func_XQueryPointer)) {
320 x11_display = (*func_XOpenDisplay) (0);
322 #else
323 x11_display = XOpenDisplay (0);
324 #endif /* HAVE_GMODULE */
326 if (x11_display)
327 x11_window = DefaultRootWindow (x11_display);
329 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
332 /* This has to be called before slang_init or whatever routine
333 calls any define_sequence */
334 void init_key (void)
336 char *term = (char *) getenv ("TERM");
338 /* This has to be the first define_sequence */
339 /* So, we can assume that the first keys member has ESC */
340 define_sequences (mc_default_keys);
342 /* Terminfo on irix does not have some keys */
343 if ((!strncmp (term, "iris-ansi", 9)) || (!strncmp (term, "xterm", 5)))
344 define_sequences (xterm_key_defines);
346 define_sequences (mc_bindings);
348 /* load some additional keys (e.g. direct Alt-? support) */
349 load_xtra_key_defines();
351 #ifdef __QNX__
352 if (strncmp(term, "qnx", 3) == 0){
353 /* Modify the default value of use_8th_bit_as_meta: we would
354 * like to provide a working mc for a newbie who knows nothing
355 * about [Options|Display bits|Full 8 bits input]...
357 * Don't use 'meta'-bit, when we are dealing with a
358 * 'qnx*'-type terminal: clear the default value!
359 * These terminal types use 0xFF as an escape character,
360 * so use_8th_bit_as_meta==1 must not be enabled!
362 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
363 * is not used now (doesn't even depend on use_8th_bit_as_meta
364 * as in mc-3.1.2)...GREAT!...no additional code is required!]
366 use_8th_bit_as_meta = 0;
368 #endif /* __QNX__ */
370 #ifdef HAVE_TEXTMODE_X11_SUPPORT
371 init_key_x11 ();
372 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
375 /* This has to be called after SLang_init_tty/slint_init */
376 void init_key_input_fd (void)
378 #ifdef HAVE_SLANG
379 input_fd = SLang_TT_Read_FD;
380 #endif
384 static void
385 xmouse_get_event (Gpm_Event *ev)
387 int btn;
388 static struct timeval tv1 = { 0, 0 }; /* Force first click as single */
389 static struct timeval tv2;
390 static int clicks;
391 static int last_btn = 0;
393 /* Decode Xterm mouse information to a GPM style event */
395 /* Variable btn has following meaning: */
396 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
397 btn = getch () - 32;
399 /* There seems to be no way of knowing which button was released */
400 /* So we assume all the buttons were released */
402 if (btn == 3){
403 if (last_btn) {
404 ev->type = GPM_UP | (GPM_SINGLE << clicks);
405 ev->buttons = 0;
406 last_btn = 0;
407 GET_TIME (tv1);
408 clicks = 0;
409 } else {
410 /* Bogus event, maybe mouse wheel */
411 ev->type = 0;
413 } else {
414 ev->type = GPM_DOWN;
415 GET_TIME (tv2);
416 if (tv1.tv_sec && (DIF_TIME (tv1,tv2) < double_click_speed)){
417 clicks++;
418 clicks %= 3;
419 } else
420 clicks = 0;
422 switch (btn) {
423 case 0:
424 ev->buttons = GPM_B_LEFT;
425 break;
426 case 1:
427 ev->buttons = GPM_B_MIDDLE;
428 break;
429 case 2:
430 ev->buttons = GPM_B_RIGHT;
431 break;
432 case 64:
433 ev->buttons = GPM_B_UP;
434 break;
435 case 65:
436 ev->buttons = GPM_B_DOWN;
437 break;
438 default:
439 /* Nothing */
440 ev->type = 0;
441 ev->buttons = 0;
442 break;
444 last_btn = ev->buttons;
446 /* Coordinates are 33-based */
447 /* Transform them to 1-based */
448 ev->x = getch () - 32;
449 ev->y = getch () - 32;
452 static key_def *create_sequence (char *seq, int code, int action)
454 key_def *base, *p, *attach;
456 for (base = attach = NULL; *seq; seq++){
457 p = g_new (key_def, 1);
458 if (!base) base = p;
459 if (attach) attach->child = p;
461 p->ch = *seq;
462 p->code = code;
463 p->child = p->next = NULL;
464 if (!seq[1])
465 p->action = action;
466 else
467 p->action = MCKEY_NOACTION;
468 attach = p;
470 return base;
473 /* The maximum sequence length (32 + null terminator) */
474 #define SEQ_BUFFER_LEN 33
475 static int seq_buffer [SEQ_BUFFER_LEN];
476 static int *seq_append = 0;
478 static int push_char (int c)
480 if (!seq_append)
481 seq_append = seq_buffer;
483 if (seq_append == &(seq_buffer [SEQ_BUFFER_LEN-2]))
484 return 0;
485 *(seq_append++) = c;
486 *seq_append = 0;
487 return 1;
491 * Return 1 on success, 0 on error.
492 * An error happens if SEQ is a beginning of an existing longer sequence.
494 int define_sequence (int code, char *seq, int action)
496 key_def *base;
498 if (strlen (seq) > SEQ_BUFFER_LEN-1)
499 return 0;
501 for (base = keys; (base != 0) && *seq; ){
502 if (*seq == base->ch){
503 if (base->child == 0){
504 if (*(seq+1)){
505 base->child = create_sequence (seq+1, code, action);
506 return 1;
507 } else {
508 /* The sequence matches an existing one. */
509 base->code = code;
510 base->action = action;
511 return 1;
513 } else {
514 base = base->child;
515 seq++;
517 } else {
518 if (base->next)
519 base = base->next;
520 else {
521 base->next = create_sequence (seq, code, action);
522 return 1;
527 if (!*seq) {
528 /* Attempt to redefine a sequence with a shorter sequence. */
529 return 0;
532 keys = create_sequence (seq, code, action);
533 return 1;
536 static int *pending_keys;
538 /* Apply corrections for the keycode generated in get_key_code() */
539 static int
540 correct_key_code (int code)
542 unsigned int c = code & ~KEY_M_MASK; /* code without modifier */
543 unsigned int mod = code & KEY_M_MASK; /* modifier */
546 * Add key modifiers directly from X11 or OS.
547 * Ordinary characters only get modifiers from sequences.
549 if (c < 32 || c >= 256) {
550 mod |= get_modifier ();
553 /* This is needed if the newline is reported as carriage return */
554 if (c == '\r')
555 c = '\n';
557 /* This is reported to be useful on AIX */
558 if (c == KEY_SCANCEL)
559 c = '\t';
561 /* Convert Shift+Tab and Ctrl+Tab to Back Tab */
562 if ((c == '\t') && (mod & (KEY_M_SHIFT | KEY_M_CTRL))) {
563 c = KEY_BTAB;
564 mod = 0;
567 /* F0 is the same as F10 for out purposes */
568 if (c == KEY_F (0))
569 c = KEY_F (10);
572 * We are not interested if Ctrl was pressed when entering control
573 * characters, so assume that it was. When checking for such keys,
574 * XCTRL macro should be used. In some cases, we are interested,
575 * e.g. to distinguish Ctrl-Enter from Enter.
577 if (c < 32 && c != ESC_CHAR && c != '\t' && c != '\n') {
578 mod |= KEY_M_CTRL;
581 /* Unrecognized 0177 is delete (preserve Ctrl) */
582 if (c == 0177) {
583 c = KEY_BACKSPACE;
586 /* Unrecognized Ctrl-d is delete */
587 if (c == (31 & 'd')) {
588 c = KEY_DC;
589 mod &= ~KEY_M_CTRL;
592 /* Unrecognized Ctrl-h is backspace */
593 if (c == (31 & 'h')) {
594 c = KEY_BACKSPACE;
595 mod &= ~KEY_M_CTRL;
598 /* Convert Shift+Fn to F(n+10) */
599 if (c >= KEY_F (1) && c <= KEY_F (10) && (mod & KEY_M_SHIFT)) {
600 c += 10;
603 /* Remove Shift information from function keys */
604 if (c >= KEY_F (1) && c <= KEY_F (20)) {
605 mod &= ~KEY_M_SHIFT;
608 if (!alternate_plus_minus)
609 switch (c) {
610 case KEY_KP_ADD:
611 c = '+';
612 break;
613 case KEY_KP_SUBTRACT:
614 c = '-';
615 break;
616 case KEY_KP_MULTIPLY:
617 c = '*';
618 break;
621 return (mod | c);
624 int get_key_code (int no_delay)
626 int c;
627 static key_def *this = NULL, *parent;
628 static struct timeval esctime = { -1, -1 };
629 static int lastnodelay = -1;
631 if (no_delay != lastnodelay) {
632 this = NULL;
633 lastnodelay = no_delay;
636 pend_send:
637 if (pending_keys){
638 int d = *pending_keys++;
639 check_pend:
640 if (!*pending_keys){
641 pending_keys = 0;
642 seq_append = 0;
644 if (d == ESC_CHAR && pending_keys){
645 d = ALT(*pending_keys++);
646 goto check_pend;
648 if ((d & 0x80) && use_8th_bit_as_meta)
649 d = ALT(d & 0x7f);
650 this = NULL;
651 return correct_key_code (d);
654 nodelay_try_again:
655 if (no_delay) {
656 nodelay (stdscr, TRUE);
658 c = getch ();
659 #if defined(USE_NCURSES) && defined(KEY_RESIZE)
660 if (c == KEY_RESIZE)
661 goto nodelay_try_again;
662 #endif
663 if (no_delay) {
664 nodelay (stdscr, FALSE);
665 if (c == -1) {
666 if (this != NULL && parent != NULL &&
667 parent->action == MCKEY_ESCAPE && old_esc_mode) {
668 struct timeval current, timeout;
670 if (esctime.tv_sec == -1)
671 return -1;
672 GET_TIME (current);
673 timeout.tv_sec = ESCMODE_TIMEOUT / 1000000 + esctime.tv_sec;
674 timeout.tv_usec = ESCMODE_TIMEOUT % 1000000 + esctime.tv_usec;
675 if (timeout.tv_usec > 1000000) {
676 timeout.tv_usec -= 1000000;
677 timeout.tv_sec++;
679 if (current.tv_sec < timeout.tv_sec)
680 return -1;
681 if (current.tv_sec == timeout.tv_sec &&
682 current.tv_usec < timeout.tv_usec)
683 return -1;
684 this = NULL;
685 pending_keys = seq_append = NULL;
686 return ESC_CHAR;
688 return -1;
690 } else if (c == -1){
691 /* Maybe we got an incomplete match.
692 This we do only in delay mode, since otherwise
693 getch can return -1 at any time. */
694 if (seq_append) {
695 pending_keys = seq_buffer;
696 goto pend_send;
698 this = NULL;
699 return -1;
702 /* Search the key on the root */
703 if (!no_delay || this == NULL) {
704 this = keys;
705 parent = NULL;
707 if ((c & 0x80) && use_8th_bit_as_meta) {
708 c &= 0x7f;
710 /* The first sequence defined starts with esc */
711 parent = keys;
712 this = keys->child;
715 while (this){
716 if (c == this->ch){
717 if (this->child){
718 if (!push_char (c)){
719 pending_keys = seq_buffer;
720 goto pend_send;
722 parent = this;
723 this = this->child;
724 if (parent->action == MCKEY_ESCAPE && old_esc_mode) {
725 if (no_delay) {
726 GET_TIME (esctime);
727 if (this == NULL) {
728 /* Shouldn't happen */
729 fputs ("Internal error\n", stderr);
730 exit (1);
732 goto nodelay_try_again;
734 esctime.tv_sec = -1;
735 c = xgetch_second ();
736 if (c == -1) {
737 pending_keys = seq_append = NULL;
738 this = NULL;
739 return ESC_CHAR;
741 } else {
742 if (no_delay)
743 goto nodelay_try_again;
744 c = getch ();
746 } else {
747 /* We got a complete match, return and reset search */
748 int code;
750 pending_keys = seq_append = NULL;
751 code = this->code;
752 this = NULL;
753 return correct_key_code (code);
755 } else {
756 if (this->next)
757 this = this->next;
758 else {
759 if (parent != NULL && parent->action == MCKEY_ESCAPE) {
760 /* This is just to save a lot of define_sequences */
761 if (isalpha(c)
762 || (c == '\n') || (c == '\t') || (c == (31 & 'h'))
763 || (c == KEY_BACKSPACE) || (c == '!') || (c == '\r')
764 || c == 0177 || c == '+' || c == '-' || c == '\\'
765 || c == '?')
766 c = ALT(c);
767 else if (isdigit(c))
768 c = KEY_F (c - '0');
769 else if (c == ' ')
770 c = ESC_CHAR;
771 pending_keys = seq_append = NULL;
772 this = NULL;
773 return correct_key_code (c);
775 /* Did not find a match or {c} was changed in the if above,
776 so we have to return everything we had skipped
778 push_char (c);
779 pending_keys = seq_buffer;
780 goto pend_send;
784 this = NULL;
785 return correct_key_code (c);
788 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
789 static void
790 try_channels (int set_timeout)
792 struct timeval timeout;
793 static fd_set select_set;
794 struct timeval *timeptr;
795 int v;
796 int maxfdp;
798 while (1){
799 FD_ZERO (&select_set);
800 FD_SET (input_fd, &select_set); /* Add stdin */
801 maxfdp = max (add_selects (&select_set), input_fd);
803 if (set_timeout){
804 timeout.tv_sec = 0;
805 timeout.tv_usec = 100000;
806 timeptr = &timeout;
807 } else
808 timeptr = 0;
810 v = select (maxfdp + 1, &select_set, NULL, NULL, timeptr);
811 if (v > 0){
812 check_selects (&select_set);
813 if (FD_ISSET (input_fd, &select_set))
814 return;
819 /* Workaround for System V Curses vt100 bug */
820 static int getch_with_delay (void)
822 int c;
824 /* This routine could be used on systems without mouse support,
825 so we need to do the select check :-( */
826 while (1){
827 if (!pending_keys)
828 try_channels (0);
830 /* Try to get a character */
831 c = get_key_code (0);
832 if (c != -1)
833 break;
834 /* Failed -> wait 0.1 secs and try again */
835 try_channels (1);
837 /* Success -> return the character */
838 return c;
841 /* Returns a character read from stdin with appropriate interpretation */
842 /* Also takes care of generated mouse events */
843 /* Returns EV_MOUSE if it is a mouse event */
844 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
846 get_event (Gpm_Event * event, int redo_event, int block)
848 int c;
849 static int flag; /* Return value from select */
850 #ifdef HAVE_LIBGPM
851 static Gpm_Event ev; /* Mouse event */
852 #endif
853 struct timeval timeout;
854 struct timeval *time_addr = NULL;
855 static int dirty = 3;
857 if ((dirty == 3) || is_idle ()) {
858 mc_refresh ();
859 doupdate ();
860 dirty = 1;
861 } else
862 dirty++;
864 vfs_timeout_handler ();
866 /* Ok, we use (event->x < 0) to signal that the event does not contain
867 a suitable position for the mouse, so we can't use show_mouse_pointer
868 on it.
870 if (event->x > 0) {
871 show_mouse_pointer (event->x, event->y);
872 if (!redo_event)
873 event->x = -1;
876 /* Repeat if using mouse */
877 while (mouse_enabled && !pending_keys) {
878 int maxfdp;
879 fd_set select_set;
881 FD_ZERO (&select_set);
882 FD_SET (input_fd, &select_set);
883 maxfdp = max (add_selects (&select_set), input_fd);
885 #ifdef HAVE_LIBGPM
886 if (use_mouse_p == MOUSE_GPM) {
887 if (gpm_fd == -1) {
888 /* Connection to gpm broken, possibly gpm has died */
889 mouse_enabled = 0;
890 use_mouse_p = MOUSE_NONE;
891 break;
893 FD_SET (gpm_fd, &select_set);
894 maxfdp = max (maxfdp, gpm_fd);
896 #endif
898 if (redo_event) {
899 timeout.tv_usec = mou_auto_repeat * 1000;
900 timeout.tv_sec = 0;
902 time_addr = &timeout;
903 } else {
904 int seconds;
906 if ((seconds = vfs_timeouts ())) {
907 /* the timeout could be improved and actually be
908 * the number of seconds until the next vfs entry
909 * timeouts in the stamp list.
912 timeout.tv_sec = seconds;
913 timeout.tv_usec = 0;
914 time_addr = &timeout;
915 } else
916 time_addr = NULL;
919 if (!block) {
920 time_addr = &timeout;
921 timeout.tv_sec = 0;
922 timeout.tv_usec = 0;
924 enable_interrupt_key ();
925 flag = select (maxfdp + 1, &select_set, NULL, NULL, time_addr);
926 disable_interrupt_key ();
928 /* select timed out: it could be for any of the following reasons:
929 * redo_event -> it was because of the MOU_REPEAT handler
930 * !block -> we did not block in the select call
931 * else -> 10 second timeout to check the vfs status.
933 if (flag == 0) {
934 if (redo_event)
935 return EV_MOUSE;
936 if (!block)
937 return EV_NONE;
938 vfs_timeout_handler ();
940 if (flag == -1 && errno == EINTR)
941 return EV_NONE;
943 check_selects (&select_set);
945 if (FD_ISSET (input_fd, &select_set))
946 break;
947 #ifdef HAVE_LIBGPM
948 if (use_mouse_p == MOUSE_GPM && FD_ISSET (gpm_fd, &select_set)) {
949 Gpm_GetEvent (&ev);
950 Gpm_FitEvent (&ev);
951 *event = ev;
952 return EV_MOUSE;
954 #endif /* !HAVE_LIBGPM */
956 #ifndef HAVE_SLANG
957 flag = is_wintouched (stdscr);
958 untouchwin (stdscr);
959 #endif /* !HAVE_SLANG */
960 c = block ? getch_with_delay () : get_key_code (1);
962 #ifndef HAVE_SLANG
963 if (flag)
964 touchwin (stdscr);
965 #endif /* !HAVE_SLANG */
967 if (c == MCKEY_MOUSE
968 #ifdef KEY_MOUSE
969 || c == KEY_MOUSE
970 #endif /* KEY_MOUSE */
972 /* Mouse event */
973 xmouse_get_event (event);
974 if (event->type)
975 return EV_MOUSE;
976 else
977 return EV_NONE;
980 return c;
983 /* Returns a key press, mouse events are discarded */
984 int mi_getch ()
986 Gpm_Event ev;
987 int key;
989 ev.x = -1;
990 while ((key = get_event (&ev, 0, 1)) == EV_NONE)
992 return key;
995 static int xgetch_second (void)
997 fd_set Read_FD_Set;
998 int c;
999 struct timeval timeout;
1001 timeout.tv_sec = ESCMODE_TIMEOUT / 1000000;
1002 timeout.tv_usec = ESCMODE_TIMEOUT % 1000000;
1003 nodelay (stdscr, TRUE);
1004 FD_ZERO (&Read_FD_Set);
1005 FD_SET (input_fd, &Read_FD_Set);
1006 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &timeout);
1007 c = getch ();
1008 nodelay (stdscr, FALSE);
1009 return c;
1012 static void
1013 learn_store_key (char *buffer, char **p, int c)
1015 if (*p - buffer > 253)
1016 return;
1017 if (c == ESC_CHAR) {
1018 *(*p)++ = '\\';
1019 *(*p)++ = 'e';
1020 } else if (c < ' ') {
1021 *(*p)++ = '^';
1022 *(*p)++ = c + 'a' - 1;
1023 } else if (c == '^') {
1024 *(*p)++ = '^';
1025 *(*p)++ = '^';
1026 } else
1027 *(*p)++ = (char) c;
1030 char *learn_key (void)
1032 /* LEARN_TIMEOUT in usec */
1033 #define LEARN_TIMEOUT 200000
1035 fd_set Read_FD_Set;
1036 struct timeval endtime;
1037 struct timeval timeout;
1038 int c;
1039 char buffer [256];
1040 char *p = buffer;
1042 keypad(stdscr, FALSE); /* disable intepreting keys by ncurses */
1043 c = getch ();
1044 while (c == -1)
1045 c = getch (); /* Sanity check, should be unnecessary */
1046 learn_store_key (buffer, &p, c);
1047 GET_TIME (endtime);
1048 endtime.tv_usec += LEARN_TIMEOUT;
1049 if (endtime.tv_usec > 1000000) {
1050 endtime.tv_usec -= 1000000;
1051 endtime.tv_sec++;
1053 nodelay (stdscr, TRUE);
1054 for (;;) {
1055 while ((c = getch ()) == -1) {
1056 GET_TIME (timeout);
1057 timeout.tv_usec = endtime.tv_usec - timeout.tv_usec;
1058 if (timeout.tv_usec < 0)
1059 timeout.tv_sec++;
1060 timeout.tv_sec = endtime.tv_sec - timeout.tv_sec;
1061 if (timeout.tv_sec >= 0 && timeout.tv_usec > 0) {
1062 FD_ZERO (&Read_FD_Set);
1063 FD_SET (input_fd, &Read_FD_Set);
1064 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &timeout);
1065 } else
1066 break;
1068 if (c == -1)
1069 break;
1070 learn_store_key (buffer, &p, c);
1072 keypad(stdscr, TRUE);
1073 nodelay (stdscr, FALSE);
1074 *p = 0;
1075 return g_strdup (buffer);
1078 /* xterm and linux console only: set keypad to numeric or application
1079 mode. Only in application keypad mode it's possible to distinguish
1080 the '+' key and the '+' on the keypad ('*' and '-' ditto)*/
1081 void
1082 numeric_keypad_mode (void)
1084 if (console_flag || xterm_flag) {
1085 fputs ("\033>", stdout);
1086 fflush (stdout);
1090 void
1091 application_keypad_mode (void)
1093 if (console_flag || xterm_flag) {
1094 fputs ("\033=", stdout);
1095 fflush (stdout);
1101 * Check if we are idle, i.e. there are no pending keyboard or mouse
1102 * events. Return 1 is idle, 0 is there are pending events.
1105 is_idle (void)
1107 int maxfdp;
1108 fd_set select_set;
1109 struct timeval timeout;
1111 FD_ZERO (&select_set);
1112 FD_SET (input_fd, &select_set);
1113 maxfdp = input_fd;
1114 #ifdef HAVE_LIBGPM
1115 if (use_mouse_p == MOUSE_GPM && mouse_enabled && gpm_fd != -1) {
1116 FD_SET (gpm_fd, &select_set);
1117 maxfdp = max (maxfdp, gpm_fd);
1119 #endif
1120 timeout.tv_sec = 0;
1121 timeout.tv_usec = 0;
1122 return (select (maxfdp + 1, &select_set, 0, 0, &timeout) <= 0);
1127 * Get modifier state (shift, alt, ctrl) for the last key pressed.
1128 * We are assuming that the state didn't change since the key press.
1129 * This is only correct if get_modifier() is called very fast after
1130 * the input was received, so that the user didn't release the
1131 * modifier keys yet.
1133 static int
1134 get_modifier (void)
1136 int result = 0;
1137 #ifdef __QNXNTO__
1138 int mod_status, shift_ext_status;
1139 static int in_photon = 0;
1140 static int ph_ig = 0;
1141 char phlib_path[PATH_MAX];
1142 PhCursorInfo_t cursor_info;
1143 static void *ph_handle;
1144 char *ph_env;
1145 #endif /* __QNXNTO__ */
1147 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1148 if (x11_window) {
1149 Window root, child;
1150 int root_x, root_y;
1151 int win_x, win_y;
1152 unsigned int mask;
1154 #ifdef HAVE_GMODULE
1155 (*func_XQueryPointer) (x11_display, x11_window, &root, &child,
1156 &root_x, &root_y, &win_x, &win_y, &mask);
1157 #else
1158 XQueryPointer (x11_display, x11_window, &root, &child, &root_x,
1159 &root_y, &win_x, &win_y, &mask);
1160 #endif /* HAVE_GMODULE */
1162 if (mask & ShiftMask)
1163 result |= KEY_M_SHIFT;
1164 if (mask & ControlMask)
1165 result |= KEY_M_CTRL;
1166 return result;
1168 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
1169 #ifdef __QNXNTO__
1171 if (in_photon == 0) {
1172 /* First time here, let's load Photon library and attach
1173 to Photon */
1174 in_photon = -1;
1175 ph_env = getenv ("PHOTON2_PATH");
1176 if (ph_env != NULL) {
1177 g_snprintf (phlib_path, sizeof (phlib_path),
1178 "%s/lib/libph.so.1", ph_env);
1179 /* QNX 6.x has no support for RTLD_LAZY */
1180 ph_handle = dlopen (phlib_path, RTLD_NOW);
1181 if (ph_handle != NULL) {
1182 ph_attach = (ph_dv_f) dlsym (ph_handle, "PhAttach");
1183 ph_input_group =
1184 (ph_ov_f) dlsym (ph_handle, "PhInputGroup");
1185 ph_query_cursor =
1186 (ph_pqc_f) dlsym (ph_handle, "PhQueryCursor");
1187 if ((ph_attach != NULL) && (ph_input_group != NULL)
1188 && (ph_query_cursor != NULL)) {
1189 if ((*ph_attach) (0, 0)) { /* Attached */
1190 ph_ig = (*ph_input_group) (0);
1191 in_photon = 1;
1197 /* We do not have Photon running. Assume we are in text
1198 console or xterm */
1199 if (in_photon == -1) {
1200 if (devctl
1201 (fileno (stdin), DCMD_CHR_LINESTATUS, &mod_status,
1202 sizeof (int), NULL) == -1)
1203 return 0;
1204 shift_ext_status = mod_status & 0xffffff00UL;
1205 mod_status &= 0x7f;
1206 if (mod_status & _LINESTATUS_CON_ALT)
1207 result |= KEY_M_ALT;
1208 if (mod_status & _LINESTATUS_CON_CTRL)
1209 result |= KEY_M_CTRL;
1210 if ((mod_status & _LINESTATUS_CON_SHIFT)
1211 || (shift_ext_status & 0x00000800UL))
1212 result |= KEY_M_SHIFT;
1213 } else {
1214 (*ph_query_cursor) (ph_ig, &cursor_info);
1215 if (cursor_info.key_mods & 0x04)
1216 result |= KEY_M_ALT;
1217 if (cursor_info.key_mods & 0x02)
1218 result |= KEY_M_CTRL;
1219 if (cursor_info.key_mods & 0x01)
1220 result |= KEY_M_SHIFT;
1222 #endif /* __QNXNTO__ */
1223 #ifdef __linux__
1225 unsigned char modifiers = 6;
1227 if (ioctl (0, TIOCLINUX, &modifiers) < 0)
1228 return 0;
1230 /* Translate Linux modifiers into mc modifiers */
1231 if (modifiers & SHIFT_PRESSED)
1232 result |= KEY_M_SHIFT;
1233 if (modifiers & (ALTL_PRESSED | ALTR_PRESSED))
1234 result |= KEY_M_ALT;
1235 if (modifiers & CONTROL_PRESSED)
1236 result |= KEY_M_CTRL;
1238 return result;
1240 #else
1241 return result;
1242 #endif /* !__linux__ */
1245 static void k_dispose (key_def *k)
1247 if (!k)
1248 return;
1249 k_dispose (k->child);
1250 k_dispose (k->next);
1251 g_free (k);
1254 static void s_dispose (SelectList *sel)
1256 if (!sel)
1257 return;
1259 s_dispose (sel->next);
1260 g_free (sel);
1263 void done_key ()
1265 k_dispose (keys);
1266 s_dispose (select_list);
1268 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1269 #ifdef HAVE_GMODULE
1270 if (x11_display)
1271 (*func_XCloseDisplay) (x11_display);
1272 if (x11_module)
1273 g_module_close (x11_module);
1274 #else
1275 if (x11_display)
1276 XCloseDisplay (x11_display);
1277 #endif /* HAVE_GMODULE */
1278 #endif /* HAVE_TEXTMODE_X11_SUPPORT */