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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
26 #include <sys/types.h>
40 #include "cons.saver.h"
41 #include "../vfs/vfs.h"
43 #ifdef HAVE_TEXTMODE_X11_SUPPORT
48 # if defined(__GLIBC__) && (__GLIBC__ < 2)
49 # include <linux/termios.h> /* This is needed for TIOCLINUX */
53 # include <sys/ioctl.h>
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 int mou_auto_repeat
= 100;
64 int double_click_speed
= 250;
67 int use_8th_bit_as_meta
= 1;
69 typedef struct key_def
{
70 char ch
; /* Holds the matching char code */
71 int code
; /* The code returned, valid if child == NULL */
73 struct key_def
*child
; /* sequence continuation */
74 int action
; /* optional action to be done. Now used only
75 to mark that we are just after the first
79 /* This holds all the key definitions */
80 static key_def
*keys
= 0;
83 static int disabled_channels
= 0; /* Disable channels checking */
84 static int xgetch_second (void);
86 /* File descriptor monitoring add/remove routines */
87 typedef struct SelectList
{
91 struct SelectList
*next
;
94 static SelectList
*select_list
= 0;
96 void add_select_channel (int fd
, select_fn callback
, void *info
)
100 new = g_new (SelectList
, 1);
102 new->callback
= callback
;
104 new->next
= select_list
;
108 void delete_select_channel (int fd
)
110 SelectList
*p
= select_list
;
111 SelectList
*p_prev
= 0;
119 p_prev
->next
= p_next
;
121 select_list
= p_next
;
133 inline static int add_selects (fd_set
*select_set
)
138 if (disabled_channels
)
141 for (p
= select_list
; p
; p
= p
->next
){
142 FD_SET (p
->fd
, select_set
);
149 static void check_selects (fd_set
*select_set
)
153 if (disabled_channels
)
156 for (p
= select_list
; p
; p
= p
->next
)
157 if (FD_ISSET (p
->fd
, select_set
))
158 (*p
->callback
)(p
->fd
, p
->info
);
161 void channels_down (void)
163 disabled_channels
++;
166 void channels_up (void)
168 if (!disabled_channels
)
170 "Error: channels_up called with disabled_channels = 0\n");
174 typedef const struct {
180 static key_define_t mc_bindings
[] = {
181 { KEY_END
, ESC_STR
">", MCKEY_NOACTION
},
182 { KEY_HOME
, ESC_STR
"<", MCKEY_NOACTION
},
183 { 0, 0, MCKEY_NOACTION
},
186 /* Broken terminfo and termcap databases on xterminals */
187 static key_define_t xterm_key_defines
[] = {
188 { KEY_F(1), ESC_STR
"OP", MCKEY_NOACTION
},
189 { KEY_F(2), ESC_STR
"OQ", MCKEY_NOACTION
},
190 { KEY_F(3), ESC_STR
"OR", MCKEY_NOACTION
},
191 { KEY_F(4), ESC_STR
"OS", MCKEY_NOACTION
},
192 { KEY_F(1), ESC_STR
"[11~", MCKEY_NOACTION
},
193 { KEY_F(2), ESC_STR
"[12~", MCKEY_NOACTION
},
194 { KEY_F(3), ESC_STR
"[13~", MCKEY_NOACTION
},
195 { KEY_F(4), ESC_STR
"[14~", MCKEY_NOACTION
},
196 { KEY_F(5), ESC_STR
"[15~", MCKEY_NOACTION
},
197 { KEY_F(6), ESC_STR
"[17~", MCKEY_NOACTION
},
198 { KEY_F(7), ESC_STR
"[18~", MCKEY_NOACTION
},
199 { KEY_F(8), ESC_STR
"[19~", MCKEY_NOACTION
},
200 { KEY_F(9), ESC_STR
"[20~", MCKEY_NOACTION
},
201 { KEY_F(10), ESC_STR
"[21~", MCKEY_NOACTION
},
202 { 0, 0, MCKEY_NOACTION
},
205 static key_define_t mc_default_keys
[] = {
206 { ESC_CHAR
, ESC_STR
, MCKEY_ESCAPE
},
207 { ESC_CHAR
, ESC_STR ESC_STR
, MCKEY_NOACTION
},
208 { 0, 0, MCKEY_NOACTION
},
212 define_sequences (key_define_t
*kd
)
216 for (i
= 0; kd
[i
].code
; i
++)
217 define_sequence(kd
[i
].code
, kd
[i
].seq
, kd
[i
].action
);
220 #ifdef HAVE_TEXTMODE_X11_SUPPORT
221 static Display
*x11_display
;
222 static Window x11_window
;
223 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
225 /* This has to be called before slang_init or whatever routine
226 calls any define_sequence */
229 char *term
= (char *) getenv ("TERM");
231 /* This has to be the first define_sequence */
232 /* So, we can assume that the first keys member has ESC */
233 define_sequences (mc_default_keys
);
235 /* Terminfo on irix does not have some keys */
236 if ((!strncmp (term
, "iris-ansi", 9)) || (!strncmp (term
, "xterm", 5)))
237 define_sequences (xterm_key_defines
);
239 define_sequences (mc_bindings
);
241 /* load some additional keys (e.g. direct Alt-? support) */
242 load_xtra_key_defines();
245 if (strncmp(term
, "qnx", 3) == 0){
246 /* Modify the default value of use_8th_bit_as_meta: we would
247 * like to provide a working mc for a newbie who knows nothing
248 * about [Options|Display bits|Full 8 bits input]...
250 * Don't use 'meta'-bit, when we are dealing with a
251 * 'qnx*'-type terminal: clear the default value!
252 * These terminal types use 0xFF as an escape character,
253 * so use_8th_bit_as_meta==1 must not be enabled!
255 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
256 * is not used now (doesn't even depend on use_8th_bit_as_meta
257 * as in mc-3.1.2)...GREAT!...no additional code is required!]
259 use_8th_bit_as_meta
= 0;
263 #ifdef HAVE_TEXTMODE_X11_SUPPORT
264 x11_display
= XOpenDisplay (0);
266 x11_window
= DefaultRootWindow (x11_display
);
267 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
270 /* This has to be called after SLang_init_tty/slint_init */
271 void init_key_input_fd (void)
274 input_fd
= SLang_TT_Read_FD
;
280 xmouse_get_event (Gpm_Event
*ev
)
283 static struct timeval tv1
= { 0, 0 }; /* Force first click as single */
284 static struct timeval tv2
;
286 static int last_btn
= 0;
288 /* Decode Xterm mouse information to a GPM style event */
290 /* Variable btn has following meaning: */
291 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
294 /* There seems to be no way of knowing which button was released */
295 /* So we assume all the buttons were released */
299 ev
->type
= GPM_UP
| (GPM_SINGLE
<< clicks
);
305 /* Bogus event, maybe mouse wheel */
311 if (tv1
.tv_sec
&& (DIF_TIME (tv1
,tv2
) < double_click_speed
)){
319 ev
->buttons
= GPM_B_LEFT
;
322 ev
->buttons
= GPM_B_MIDDLE
;
325 ev
->buttons
= GPM_B_RIGHT
;
328 ev
->buttons
= GPM_B_UP
;
331 ev
->buttons
= GPM_B_DOWN
;
339 last_btn
= ev
->buttons
;
341 /* Coordinates are 33-based */
342 /* Transform them to 1-based */
343 ev
->x
= getch () - 32;
344 ev
->y
= getch () - 32;
347 static key_def
*create_sequence (char *seq
, int code
, int action
)
349 key_def
*base
, *p
, *attach
;
351 for (base
= attach
= NULL
; *seq
; seq
++){
352 p
= g_new (key_def
, 1);
354 if (attach
) attach
->child
= p
;
358 p
->child
= p
->next
= NULL
;
362 p
->action
= MCKEY_NOACTION
;
368 /* The maximum sequence length (32 + null terminator) */
369 #define SEQ_BUFFER_LEN 33
370 static int seq_buffer
[SEQ_BUFFER_LEN
];
371 static int *seq_append
= 0;
373 static int push_char (int c
)
376 seq_append
= seq_buffer
;
378 if (seq_append
== &(seq_buffer
[SEQ_BUFFER_LEN
-2]))
386 * Return 1 on success, 0 on error.
387 * An error happens if SEQ is a beginning of an existing longer sequence.
389 int define_sequence (int code
, char *seq
, int action
)
393 if (strlen (seq
) > SEQ_BUFFER_LEN
-1)
396 for (base
= keys
; (base
!= 0) && *seq
; ){
397 if (*seq
== base
->ch
){
398 if (base
->child
== 0){
400 base
->child
= create_sequence (seq
+1, code
, action
);
403 /* The sequence matches an existing one. */
405 base
->action
= action
;
416 base
->next
= create_sequence (seq
, code
, action
);
423 /* Attempt to redefine a sequence with a shorter sequence. */
427 keys
= create_sequence (seq
, code
, action
);
431 static int *pending_keys
;
434 correct_key_code (int c
)
436 /* This is needed on some OS that do not support ncurses and */
437 /* do some magic after read()ing the data */
442 if (c
== KEY_SCANCEL
)
449 if (!alternate_plus_minus
)
451 case KEY_KP_ADD
: c
= '+'; break;
452 case KEY_KP_SUBTRACT
: c
= '-'; break;
453 case KEY_KP_MULTIPLY
: c
= '*'; break;
459 int get_key_code (int no_delay
)
462 static key_def
*this = NULL
, *parent
;
463 static struct timeval esctime
= { -1, -1 };
464 static int lastnodelay
= -1;
466 if (no_delay
!= lastnodelay
) {
468 lastnodelay
= no_delay
;
473 int d
= *pending_keys
++;
479 if (d
== ESC_CHAR
&& pending_keys
){
480 d
= ALT(*pending_keys
++);
483 if ((d
& 0x80) && use_8th_bit_as_meta
)
486 return correct_key_code (d
);
491 nodelay (stdscr
, TRUE
);
494 #if defined(USE_NCURSES) && defined(KEY_RESIZE)
496 goto nodelay_try_again
;
499 nodelay (stdscr
, FALSE
);
501 if (this != NULL
&& parent
!= NULL
&&
502 parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
) {
503 struct timeval current
, timeout
;
505 if (esctime
.tv_sec
== -1)
508 timeout
.tv_sec
= ESCMODE_TIMEOUT
/ 1000000 + esctime
.tv_sec
;
509 timeout
.tv_usec
= ESCMODE_TIMEOUT
% 1000000 + esctime
.tv_usec
;
510 if (timeout
.tv_usec
> 1000000) {
511 timeout
.tv_usec
-= 1000000;
514 if (current
.tv_sec
< timeout
.tv_sec
)
516 if (current
.tv_sec
== timeout
.tv_sec
&&
517 current
.tv_usec
< timeout
.tv_usec
)
520 pending_keys
= seq_append
= NULL
;
526 /* Maybe we got an incomplete match.
527 This we do only in delay mode, since otherwise
528 getch can return -1 at any time. */
530 pending_keys
= seq_buffer
;
537 /* Search the key on the root */
538 if (!no_delay
|| this == NULL
) {
542 if ((c
& 0x80) && use_8th_bit_as_meta
) {
545 /* The first sequence defined starts with esc */
554 pending_keys
= seq_buffer
;
559 if (parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
) {
563 /* Shouldn't happen */
564 fprintf (stderr
, "Internal error\n");
567 goto nodelay_try_again
;
570 c
= xgetch_second ();
572 pending_keys
= seq_append
= NULL
;
578 goto nodelay_try_again
;
582 /* We got a complete match, return and reset search */
585 pending_keys
= seq_append
= NULL
;
588 return correct_key_code (code
);
594 if (parent
!= NULL
&& parent
->action
== MCKEY_ESCAPE
) {
595 /* This is just to save a lot of define_sequences */
597 || (c
== '\n') || (c
== '\t') || (c
== XCTRL('h'))
598 || (c
== KEY_BACKSPACE
) || (c
== '!') || (c
== '\r')
599 || c
== 127 || c
== '+' || c
== '-' || c
== '\\'
606 pending_keys
= seq_append
= NULL
;
608 return correct_key_code (c
);
610 /* Did not find a match or {c} was changed in the if above,
611 so we have to return everything we had skipped
614 pending_keys
= seq_buffer
;
620 return correct_key_code (c
);
623 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
625 try_channels (int set_timeout
)
627 struct timeval timeout
;
628 static fd_set select_set
;
629 struct timeval
*timeptr
;
634 FD_ZERO (&select_set
);
635 FD_SET (input_fd
, &select_set
); /* Add stdin */
636 maxfdp
= max (add_selects (&select_set
), input_fd
);
640 timeout
.tv_usec
= 100000;
645 v
= select (maxfdp
+ 1, &select_set
, NULL
, NULL
, timeptr
);
647 check_selects (&select_set
);
648 if (FD_ISSET (input_fd
, &select_set
))
654 /* Workaround for System V Curses vt100 bug */
655 static int getch_with_delay (void)
659 /* This routine could be used on systems without mouse support,
660 so we need to do the select check :-( */
665 /* Try to get a character */
666 c
= get_key_code (0);
669 /* Failed -> wait 0.1 secs and try again */
672 /* Success -> return the character */
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 */
683 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 (mouse_enabled
&& !pending_keys
) {
718 FD_ZERO (&select_set
);
719 FD_SET (input_fd
, &select_set
);
720 maxfdp
= max (add_selects (&select_set
), input_fd
);
723 if (use_mouse_p
== MOUSE_GPM
) {
725 /* Connection to gpm broken, possibly gpm has died */
727 use_mouse_p
= MOUSE_NONE
;
730 FD_SET (gpm_fd
, &select_set
);
731 maxfdp
= max (maxfdp
, gpm_fd
);
736 timeout
.tv_usec
= mou_auto_repeat
* 1000;
739 time_addr
= &timeout
;
743 if ((seconds
= vfs_timeouts ())) {
744 /* the timeout could be improved and actually be
745 * the number of seconds until the next vfs entry
746 * timeouts in the stamp list.
749 timeout
.tv_sec
= seconds
;
751 time_addr
= &timeout
;
757 time_addr
= &timeout
;
761 enable_interrupt_key ();
762 flag
= select (maxfdp
+ 1, &select_set
, NULL
, NULL
, time_addr
);
763 disable_interrupt_key ();
765 /* select timed out: it could be for any of the following reasons:
766 * redo_event -> it was because of the MOU_REPEAT handler
767 * !block -> we did not block in the select call
768 * else -> 10 second timeout to check the vfs status.
775 vfs_timeout_handler ();
777 if (flag
== -1 && errno
== EINTR
)
780 check_selects (&select_set
);
782 if (FD_ISSET (input_fd
, &select_set
))
785 if (use_mouse_p
== MOUSE_GPM
&& FD_ISSET (gpm_fd
, &select_set
)) {
791 #endif /* !HAVE_LIBGPM */
794 flag
= is_wintouched (stdscr
);
796 #endif /* !HAVE_SLANG */
797 c
= block
? getch_with_delay () : get_key_code (1);
802 #endif /* !HAVE_SLANG */
807 #endif /* KEY_MOUSE */
810 xmouse_get_event (event
);
820 /* Returns a key press, mouse events are discarded */
827 while ((key
= get_event (&ev
, 0, 1)) == EV_NONE
)
832 static int xgetch_second (void)
836 struct timeval timeout
;
838 timeout
.tv_sec
= ESCMODE_TIMEOUT
/ 1000000;
839 timeout
.tv_usec
= ESCMODE_TIMEOUT
% 1000000;
840 nodelay (stdscr
, TRUE
);
841 FD_ZERO (&Read_FD_Set
);
842 FD_SET (input_fd
, &Read_FD_Set
);
843 select (input_fd
+ 1, &Read_FD_Set
, NULL
, NULL
, &timeout
);
845 nodelay (stdscr
, FALSE
);
850 learn_store_key (char *buffer
, char **p
, int c
)
852 if (*p
- buffer
> 253)
857 } else if (c
< ' ') {
859 *(*p
)++ = c
+ 'a' - 1;
860 } else if (c
== '^') {
867 char *learn_key (void)
869 /* LEARN_TIMEOUT in usec */
870 #define LEARN_TIMEOUT 200000
873 struct timeval endtime
;
874 struct timeval timeout
;
879 keypad(stdscr
, FALSE
); /* disable intepreting keys by ncurses */
882 c
= getch (); /* 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;
890 nodelay (stdscr
, TRUE
);
892 while ((c
= getch ()) == -1) {
894 timeout
.tv_usec
= endtime
.tv_usec
- timeout
.tv_usec
;
895 if (timeout
.tv_usec
< 0)
897 timeout
.tv_sec
= endtime
.tv_sec
- timeout
.tv_sec
;
898 if (timeout
.tv_sec
>= 0 && timeout
.tv_usec
> 0) {
899 FD_ZERO (&Read_FD_Set
);
900 FD_SET (input_fd
, &Read_FD_Set
);
901 select (input_fd
+ 1, &Read_FD_Set
, NULL
, NULL
, &timeout
);
907 learn_store_key (buffer
, &p
, c
);
909 keypad(stdscr
, TRUE
);
910 nodelay (stdscr
, FALSE
);
912 return g_strdup (buffer
);
915 /* xterm and linux console only: set keypad to numeric or application
916 mode. Only in application keypad mode it's possible to distinguish
917 the '+' key and the '+' on the keypad ('*' and '-' ditto)*/
919 numeric_keypad_mode (void)
921 if (console_flag
|| xterm_flag
) {
922 fprintf (stdout
, "\033>");
928 application_keypad_mode (void)
930 if (console_flag
|| xterm_flag
) {
931 fprintf (stdout
, "\033=");
937 /* A function to check if we're idle.
938 Currently checks only for key presses.
939 We could also check the mouse. */
942 /* Check for incoming key presses *
943 * If there are any we say we're busy */
946 struct timeval timeout
;
947 FD_ZERO (&select_set
);
948 FD_SET (0, &select_set
);
951 select (1, &select_set
, 0, 0, &timeout
);
952 return ! FD_ISSET (0, &select_set
);
959 #ifdef HAVE_TEXTMODE_X11_SUPPORT
968 b
= XQueryPointer(x11_display
, x11_window
, &root
, &child
,
973 if (mask
& ShiftMask
)
974 result
|= SHIFT_PRESSED
;
975 if (mask
& ControlMask
)
976 result
|= CONTROL_PRESSED
;
982 unsigned char modifiers
;
986 if (ioctl (0, TIOCLINUX
, &modifiers
) < 0)
989 return (int) modifiers
;
999 if (get_modifier () & CONTROL_PRESSED
)
1005 static void k_dispose (key_def
*k
)
1009 k_dispose (k
->child
);
1010 k_dispose (k
->next
);
1014 static void s_dispose (SelectList
*sel
)
1019 s_dispose (sel
->next
);
1026 s_dispose (select_list
);
1028 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1030 XCloseDisplay (x11_display
);
1031 #endif /* HAVE_TEXTMODE_X11_SUPPORT */