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.
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
27 #include <sys/types.h>
32 #include <sys/types.h> /* FD_ZERO et al */
34 /* alex: sys/select.h defines struct timeval */
35 # include <sys/time.h> /* struct timeval */
36 #endif /* SCO_FLAVOR */
38 # include <sys/select.h>
44 #include "util.h" /* For xmalloc prototype */
45 #include "mad.h" /* The memory debugger */
52 #include "cons.saver.h"
53 #include "../vfs/vfs.h"
56 # if defined(__GLIBC__) && (__GLIBC__ < 2)
57 # include <linux/termios.h> /* This is needed for TIOCLINUX */
61 # include <sys/ioctl.h>
68 /* This macros were stolen from gpm 0.15 */
69 #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL))
70 #define DIF_TIME(t1,t2) ((t2.tv_sec -t1.tv_sec) *1000+ \
71 (t2.tv_usec-t1.tv_usec)/1000)
73 /* timeout for old_esc_mode in usec */
74 #define ESCMODE_TIMEOUT 1000000
76 int mou_auto_repeat
= 100;
77 int double_click_speed
= 250;
80 int use_8th_bit_as_meta
= 1;
83 typedef struct key_def
{
84 char ch
; /* Holds the matching char code */
85 int code
; /* The code returned, valid if child == NULL */
87 struct key_def
*child
; /* sequence continuation */
88 int action
; /* optional action to be done. Now used only
89 to mark that we are just after the first
93 /* This holds all the key definitions */
94 static key_def
*keys
= 0;
98 static fd_set select_set
;
99 static int disabled_channels
= 0; /* Disable channels checking */
100 int xgetch_second (void);
102 #ifndef PORT_HAS_FILE_HANDLERS
103 /* File descriptor monitoring add/remove routines */
104 typedef struct SelectList
{
108 struct SelectList
*next
;
111 SelectList
*select_list
= 0;
113 void add_select_channel (int fd
, select_fn callback
, void *info
)
117 new = xmalloc (sizeof (SelectList
), "add_select_channel");
119 new->callback
= callback
;
121 new->next
= select_list
;
125 void delete_select_channel (int fd
)
127 SelectList
*p
= select_list
;
128 SelectList
*prev
= 0;
133 prev
->next
= p
->next
;
135 select_list
= p
->next
;
143 inline static int add_selects (fd_set
*select_set
)
148 if (disabled_channels
)
151 for (p
= select_list
; p
; p
= p
->next
){
152 FD_SET (p
->fd
, select_set
);
159 static void check_selects (fd_set
*select_set
)
163 if (disabled_channels
)
166 for (p
= select_list
; p
; p
= p
->next
)
167 if (FD_ISSET (p
->fd
, select_set
))
168 (*p
->callback
)(p
->fd
, p
->info
);
172 void channels_down (void)
174 disabled_channels
++;
177 void channels_up (void)
179 if (!disabled_channels
)
181 "Error: channels_up called with disabled_channels = 0\n");
192 key_define_t mc_bindings
[] = {
193 { KEY_END
, ESC_STR
">", MCKEY_NOACTION
},
194 { KEY_HOME
, ESC_STR
"<", MCKEY_NOACTION
},
197 /* Incredible, but many Linuxes still have old databases */
198 { KEY_IC
, ESC_STR
"[2~", MCKEY_NOACTION
},
200 { 0, 0, MCKEY_NOACTION
},
203 /* Broken terminfo and termcap databases on xterminals */
204 key_define_t xterm_key_defines
[] = {
205 { KEY_F(1), ESC_STR
"OP", MCKEY_NOACTION
},
206 { KEY_F(2), ESC_STR
"OQ", MCKEY_NOACTION
},
207 { KEY_F(3), ESC_STR
"OR", MCKEY_NOACTION
},
208 { KEY_F(4), ESC_STR
"OS", MCKEY_NOACTION
},
209 { KEY_F(1), ESC_STR
"[11~", MCKEY_NOACTION
},
210 { KEY_F(2), ESC_STR
"[12~", MCKEY_NOACTION
},
211 { KEY_F(3), ESC_STR
"[13~", MCKEY_NOACTION
},
212 { KEY_F(4), ESC_STR
"[14~", MCKEY_NOACTION
},
213 { KEY_F(5), ESC_STR
"[15~", MCKEY_NOACTION
},
214 { KEY_F(6), ESC_STR
"[17~", MCKEY_NOACTION
},
215 { KEY_F(7), ESC_STR
"[18~", MCKEY_NOACTION
},
216 { KEY_F(8), ESC_STR
"[19~", MCKEY_NOACTION
},
217 { KEY_F(9), ESC_STR
"[20~", MCKEY_NOACTION
},
218 { KEY_F(10), ESC_STR
"[21~", MCKEY_NOACTION
},
219 { 0, 0, MCKEY_NOACTION
},
222 key_define_t mc_default_keys
[] = {
223 { ESC_CHAR
, ESC_STR
, MCKEY_ESCAPE
},
224 { ESC_CHAR
, ESC_STR ESC_STR
, MCKEY_NOACTION
},
225 { 0, 0, MCKEY_NOACTION
},
229 void define_sequences (key_define_t
*kd
)
234 for (i
= 0; kd
[i
].code
; i
++)
235 define_sequence(kd
[i
].code
, kd
[i
].seq
, kd
[i
].action
);
239 /* This has to be called before slang_init or whatever routine
240 calls any define_sequence */
244 char *term
= (char *) getenv ("TERM");
246 /* This has to be the first define_sequence */
247 /* So, we can assume that the first keys member has ESC */
248 define_sequences (mc_default_keys
);
250 /* Terminfo on irix does not have some keys */
251 if ((!strncmp (term
, "iris-ansi", 9)) || (!strncmp (term
, "xterm", 5)))
252 define_sequences (xterm_key_defines
);
254 define_sequences (mc_bindings
);
256 /* load some additional keys (e.g. direct Alt-? support) */
257 load_xtra_key_defines();
260 if (strncmp(term
, "qnx", 3) == 0){
261 /* Modify the default value of use_8th_bit_as_meta: we would
262 * like to provide a working mc for a newbie who knows nothing
263 * about [Options|Display bits|Full 8 bits input]...
265 * Don't use 'meta'-bit, when we are dealing with a
266 * 'qnx*'-type terminal: clear the default value!
267 * These terminal types use 0xFF as an escape character,
268 * so use_8th_bit_as_meta==1 must not be enabled!
270 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
271 * is not used now (doesn't even depend on use_8th_bit_as_meta
272 * as in mc-3.1.2)...GREAT!...no additional code is required!]
274 use_8th_bit_as_meta
= 0;
280 /* This has to be called after SLang_init_tty/slint_init */
281 void init_key_input_fd (void)
285 input_fd
= SLang_TT_Read_FD
;
292 void xmouse_get_event (Gpm_Event
*ev
)
295 static struct timeval tv1
= { 0, 0 }; /* Force first click as single */
296 static struct timeval tv2
;
299 /* Decode Xterm mouse information to a GPM style event */
301 /* Variable btn has following meaning: */
302 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
303 btn
= xgetch () - 32;
305 /* There seems to be no way of knowing which button was released */
306 /* So we assume all the buttons were released */
309 ev
->type
= GPM_UP
| (GPM_SINGLE
<< clicks
);
316 if (tv1
.tv_sec
&& (DIF_TIME (tv1
,tv2
) < double_click_speed
)){
324 ev
->buttons
= GPM_B_LEFT
;
327 ev
->buttons
= GPM_B_MIDDLE
;
330 ev
->buttons
= GPM_B_RIGHT
;
337 /* Coordinates are 33-based */
338 /* Transform them to 1-based */
339 ev
->x
= xgetch () - 32;
340 ev
->y
= xgetch () - 32;
343 static key_def
*create_sequence (char *seq
, int code
, int action
)
345 key_def
*base
, *p
, *attach
;
347 for (base
= attach
= NULL
; *seq
; seq
++){
348 p
= xmalloc (sizeof (key_def
), "create_sequence");
350 if (attach
) attach
->child
= p
;
354 p
->child
= p
->next
= NULL
;
358 p
->action
= MCKEY_NOACTION
;
364 /* The maximum sequence length (32 + null terminator) */
365 static int seq_buffer
[33];
366 static int *seq_append
= 0;
368 static int push_char (int c
)
371 seq_append
= seq_buffer
;
373 if (seq_append
== &(seq_buffer
[sizeof (seq_buffer
)-2]))
381 void define_sequence (int code
, char *seq
, int action
)
386 if (strlen (seq
) > sizeof (seq_buffer
)-1)
389 for (base
= keys
; (base
!= 0) && *seq
; ){
390 if (*seq
== base
->ch
){
391 if (base
->child
== 0){
393 base
->child
= create_sequence (seq
+1, code
, action
);
396 /* The sequence clashes */
407 base
->next
= create_sequence (seq
, code
, action
);
412 keys
= create_sequence (seq
, code
, action
);
417 static int *pending_keys
;
420 int correct_key_code (int c
)
422 /* This is needed on some OS that do not support ncurses and */
423 /* do some magic after read()ing the data */
428 if (c
== KEY_SCANCEL
)
435 if (!alternate_plus_minus
)
437 case KEY_KP_ADD
: c
= '+'; break;
438 case KEY_KP_SUBTRACT
: c
= '-'; break;
439 case KEY_KP_MULTIPLY
: c
= '*'; break;
445 int get_key_code (int no_delay
)
449 static key_def
*this = NULL
, *parent
;
450 static struct timeval esctime
= { -1, -1 };
451 static int lastnodelay
= -1;
453 if (no_delay
!= lastnodelay
) {
455 lastnodelay
= no_delay
;
460 int d
= *pending_keys
++;
466 if (d
== ESC_CHAR
&& pending_keys
){
467 d
= ALT(*pending_keys
++);
470 if ((d
& 0x80) && use_8th_bit_as_meta
)
473 return correct_key_code (d
);
479 wtimeout(stdscr
, 500);
481 nodelay (stdscr
, TRUE
);
487 notimeout (stdscr
, TRUE
);
489 nodelay (stdscr
, FALSE
);
492 if (this != NULL
&& parent
!= NULL
&&
493 parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
) {
494 struct timeval current
, timeout
;
496 if (esctime
.tv_sec
== -1)
499 timeout
.tv_sec
= ESCMODE_TIMEOUT
/ 1000000 + esctime
.tv_sec
;
500 timeout
.tv_usec
= ESCMODE_TIMEOUT
% 1000000 + esctime
.tv_usec
;
501 if (timeout
.tv_usec
> 1000000) {
502 timeout
.tv_usec
-= 1000000;
505 if (current
.tv_sec
< timeout
.tv_sec
)
507 if (current
.tv_sec
== timeout
.tv_sec
&&
508 current
.tv_usec
< timeout
.tv_usec
)
511 pending_keys
= seq_append
= NULL
;
516 } else if (c
== ERR
){
517 /* Maybe we got an incomplete match.
518 This we do only in delay mode, since otherwise
519 xgetch can return ERR at any time. */
521 pending_keys
= seq_buffer
;
528 /* Search the key on the root */
529 if (!no_delay
|| this == NULL
) {
533 if ((c
& 0x80) && use_8th_bit_as_meta
) {
536 /* The first sequence defined starts with esc */
545 pending_keys
= seq_buffer
;
550 if (parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
) {
554 /* Shouldn't happen */
555 fprintf (stderr
, "Internal error\n");
558 goto nodelay_try_again
;
561 c
= xgetch_second ();
563 pending_keys
= seq_append
= NULL
;
569 goto nodelay_try_again
;
573 /* We got a complete match, return and reset search */
576 pending_keys
= seq_append
= NULL
;
579 return correct_key_code (code
);
585 if (parent
!= NULL
&& parent
->action
== MCKEY_ESCAPE
) {
586 /* This is just to save a lot of define_sequences */
588 || (c
== '\n') || (c
== '\t') || (c
== XCTRL('h'))
589 || (c
== KEY_BACKSPACE
) || (c
== '!') || (c
== '\r')
590 || c
== 127 || c
== '+' || c
== '-' || c
== '\\'
597 pending_keys
= seq_append
= NULL
;
599 return correct_key_code (c
);
601 /* Did not find a match or {c} was changed in the if above,
602 so we have to return everything we had skipped
605 pending_keys
= seq_buffer
;
611 return correct_key_code (c
);
617 #ifndef PORT_HAS_FILE_HANDLERS
618 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
619 void try_channels (int set_timeout
)
621 struct timeval timeout
;
622 static fd_set select_set
;
623 struct timeval
*timeptr
;
627 FD_ZERO (&select_set
);
628 FD_SET (input_fd
, &select_set
); /* Add stdin */
629 add_selects (&select_set
);
633 timeout
.tv_usec
= 100000;
638 v
= select (FD_SETSIZE
, &select_set
, NULL
, NULL
, timeptr
);
640 check_selects (&select_set
);
641 if (FD_ISSET (input_fd
, &select_set
))
648 /* Workaround for System V Curses vt100 bug */
649 static int getch_with_delay (void)
653 /* This routine could be used on systems without mouse support,
654 so we need to do the select check :-( */
659 /* Try to get a character */
660 c
= get_key_code (0);
663 /* Failed -> wait 0.1 secs and try again */
666 /* Success -> return the character */
674 #endif /* !HAVE_FILE_HANDLERS */
676 extern int max_dirt_limit
;
678 /* Returns a character read from stdin with appropriate interpretation */
679 /* Also takes care of generated mouse events */
680 /* Returns EV_MOUSE if it is a mouse event */
681 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
682 int get_event (Gpm_Event
*event
, int redo_event
, int block
)
686 static int flag
; /* Return value from select */
688 static Gpm_Event ev
; /* Mouse event */
690 struct timeval timeout
;
691 struct timeval
*time_addr
= NULL
;
692 static int dirty
= 3;
694 if ((dirty
== 3) || is_idle ()){
701 vfs_timeout_handler ();
703 /* Ok, we use (event->x < 0) to signal that the event does not contain
704 a suitable position for the mouse, so we can't use show_mouse_pointer
708 show_mouse_pointer (event
->x
, event
->y
);
713 /* Repeat if using mouse */
714 while ((xmouse_flag
|| gpm_flag
) && !pending_keys
)
716 if (xmouse_flag
|| gpm_flag
)
718 FD_ZERO (&select_set
);
719 FD_SET (input_fd
, &select_set
);
720 add_selects (&select_set
);
724 FD_SET (gpm_fd
, &select_set
);
729 timeout
.tv_usec
= mou_auto_repeat
* 1000;
732 time_addr
= &timeout
;
736 if ((seconds
= vfs_timeouts ())){
737 /* the timeout could be improved and actually be
738 * the number of seconds until the next vfs entry
739 * timeouts in the stamp list.
742 timeout
.tv_sec
= seconds
;
744 time_addr
= &timeout
;
750 time_addr
= &timeout
;
754 enable_interrupt_key ();
755 flag
= select (FD_SETSIZE
, &select_set
, NULL
, NULL
, time_addr
);
756 disable_interrupt_key ();
758 /* select timed out: it could be for any of the following reasons:
759 * redo_event -> it was because of the MOU_REPEAT handler
760 * !block -> we did not block in the select call
761 * else -> 10 second timeout to check the vfs status.
768 vfs_timeout_handler ();
770 if (flag
== -1 && errno
== EINTR
)
773 check_selects (&select_set
);
775 if (FD_ISSET (input_fd
, &select_set
))
779 if (gpm_flag
&& FD_ISSET (gpm_fd
, &select_set
)){
790 flag
= is_wintouched(stdscr
);
794 c
= block
? getch_with_delay () : get_key_code(1);
801 if (c
== MCKEY_MOUSE
) { /* Mouse event */
802 xmouse_get_event (event
);
812 #ifndef PORT_HAS_GETCH
813 /* Returns a key press, mouse events are discarded */
820 while ((key
= get_event (&ev
, 0, 1)) == 0)
826 int xgetch_second (void)
830 struct timeval timeout
;
832 timeout
.tv_sec
= ESCMODE_TIMEOUT
/ 1000000;
833 timeout
.tv_usec
= ESCMODE_TIMEOUT
% 1000000;
835 wtimeout(stdscr
, 500);
837 nodelay (stdscr
, TRUE
);
839 FD_ZERO (&Read_FD_Set
);
840 FD_SET (input_fd
, &Read_FD_Set
);
841 select (FD_SETSIZE
, &Read_FD_Set
, NULL
, NULL
, &timeout
);
844 notimeout (stdscr
, TRUE
);
846 nodelay (stdscr
, FALSE
);
852 void learn_store_key (char *buffer
, char **p
, int c
)
854 if (*p
- buffer
> 253)
859 } else if (c
< ' ') {
861 *(*p
)++ = c
+ 'a' - 1;
862 } else if (c
== '^') {
869 char *learn_key (void)
871 /* LEARN_TIMEOUT in usec */
872 #define LEARN_TIMEOUT 200000
875 struct timeval endtime
;
876 struct timeval timeout
;
882 c
= xgetch (); /* Sanity check, should be unnecessary */
883 learn_store_key (buffer
, &p
, c
);
885 endtime
.tv_usec
+= LEARN_TIMEOUT
;
886 if (endtime
.tv_usec
> 1000000) {
887 endtime
.tv_usec
-= 1000000;
891 wtimeout(stdscr
, 500);
893 nodelay (stdscr
, TRUE
);
896 while ((c
= xgetch ()) == ERR
) {
898 timeout
.tv_usec
= endtime
.tv_usec
- timeout
.tv_usec
;
899 if (timeout
.tv_usec
< 0)
901 timeout
.tv_sec
= endtime
.tv_sec
- timeout
.tv_sec
;
902 if (timeout
.tv_sec
>= 0 && timeout
.tv_usec
> 0) {
903 FD_ZERO (&Read_FD_Set
);
904 FD_SET (input_fd
, &Read_FD_Set
);
905 select (FD_SETSIZE
, &Read_FD_Set
, NULL
, NULL
, &timeout
);
911 learn_store_key (buffer
, &p
, c
);
914 notimeout (stdscr
, TRUE
);
916 nodelay (stdscr
, FALSE
);
919 return strdup (buffer
);
922 /* xterm and linux console only: set keypad to numeric or application
923 mode. Only in application keypad mode it's possible to distinguish
924 the '+' key and the '+' on the keypad ('*' and '-' ditto)*/
926 numeric_keypad_mode (void)
928 if (console_flag
|| xterm_flag
) {
929 fprintf (stdout
, "\033>");
935 application_keypad_mode (void)
937 if (console_flag
|| xterm_flag
) {
938 fprintf (stdout
, "\033=");
945 /* A function to check if we're idle.
946 Currently checks only for key presses.
947 We could also check the mouse. */
950 /* Check for incoming key presses *
951 * If there are any we say we're busy */
954 struct timeval timeout
;
955 FD_ZERO (&select_set
);
956 FD_SET (0, &select_set
);
959 select (FD_SETSIZE
, &select_set
, 0, 0, &timeout
);
960 return ! FD_ISSET (0, &select_set
);
967 unsigned char modifiers
;
971 if (ioctl (0, TIOCLINUX
, &modifiers
) < 0)
974 return (int) modifiers
;
983 if (get_modifier () & CONTROL_PRESSED
)
991 void k_dispose (key_def
*k
)
995 k_dispose (k
->child
);
1000 void s_dispose (SelectList
*sel
)
1005 s_dispose (sel
->next
);
1012 s_dispose (select_list
);
1022 #endif /* HAVE_MAD */