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
;
333 last_btn
= ev
->buttons
;
335 /* Coordinates are 33-based */
336 /* Transform them to 1-based */
337 ev
->x
= getch () - 32;
338 ev
->y
= getch () - 32;
341 static key_def
*create_sequence (char *seq
, int code
, int action
)
343 key_def
*base
, *p
, *attach
;
345 for (base
= attach
= NULL
; *seq
; seq
++){
346 p
= g_new (key_def
, 1);
348 if (attach
) attach
->child
= p
;
352 p
->child
= p
->next
= NULL
;
356 p
->action
= MCKEY_NOACTION
;
362 /* The maximum sequence length (32 + null terminator) */
363 #define SEQ_BUFFER_LEN 33
364 static int seq_buffer
[SEQ_BUFFER_LEN
];
365 static int *seq_append
= 0;
367 static int push_char (int c
)
370 seq_append
= seq_buffer
;
372 if (seq_append
== &(seq_buffer
[SEQ_BUFFER_LEN
-2]))
380 * Return 1 on success, 0 on error.
381 * An error happens if SEQ is a beginning of an existing longer sequence.
383 int define_sequence (int code
, char *seq
, int action
)
387 if (strlen (seq
) > SEQ_BUFFER_LEN
-1)
390 for (base
= keys
; (base
!= 0) && *seq
; ){
391 if (*seq
== base
->ch
){
392 if (base
->child
== 0){
394 base
->child
= create_sequence (seq
+1, code
, action
);
397 /* The sequence matches an existing one. */
399 base
->action
= action
;
410 base
->next
= create_sequence (seq
, code
, action
);
417 /* Attempt to redefine a sequence with a shorter sequence. */
421 keys
= create_sequence (seq
, code
, action
);
425 static int *pending_keys
;
428 correct_key_code (int c
)
430 /* This is needed on some OS that do not support ncurses and */
431 /* do some magic after read()ing the data */
436 if (c
== KEY_SCANCEL
)
443 if (!alternate_plus_minus
)
445 case KEY_KP_ADD
: c
= '+'; break;
446 case KEY_KP_SUBTRACT
: c
= '-'; break;
447 case KEY_KP_MULTIPLY
: c
= '*'; break;
453 int get_key_code (int no_delay
)
456 static key_def
*this = NULL
, *parent
;
457 static struct timeval esctime
= { -1, -1 };
458 static int lastnodelay
= -1;
460 if (no_delay
!= lastnodelay
) {
462 lastnodelay
= no_delay
;
467 int d
= *pending_keys
++;
473 if (d
== ESC_CHAR
&& pending_keys
){
474 d
= ALT(*pending_keys
++);
477 if ((d
& 0x80) && use_8th_bit_as_meta
)
480 return correct_key_code (d
);
485 nodelay (stdscr
, TRUE
);
488 #if defined(USE_NCURSES) && defined(KEY_RESIZE)
490 goto nodelay_try_again
;
493 nodelay (stdscr
, FALSE
);
495 if (this != NULL
&& parent
!= NULL
&&
496 parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
) {
497 struct timeval current
, timeout
;
499 if (esctime
.tv_sec
== -1)
502 timeout
.tv_sec
= ESCMODE_TIMEOUT
/ 1000000 + esctime
.tv_sec
;
503 timeout
.tv_usec
= ESCMODE_TIMEOUT
% 1000000 + esctime
.tv_usec
;
504 if (timeout
.tv_usec
> 1000000) {
505 timeout
.tv_usec
-= 1000000;
508 if (current
.tv_sec
< timeout
.tv_sec
)
510 if (current
.tv_sec
== timeout
.tv_sec
&&
511 current
.tv_usec
< timeout
.tv_usec
)
514 pending_keys
= seq_append
= NULL
;
519 } else if (c
== ERR
){
520 /* Maybe we got an incomplete match.
521 This we do only in delay mode, since otherwise
522 getch can return ERR at any time. */
524 pending_keys
= seq_buffer
;
531 /* Search the key on the root */
532 if (!no_delay
|| this == NULL
) {
536 if ((c
& 0x80) && use_8th_bit_as_meta
) {
539 /* The first sequence defined starts with esc */
548 pending_keys
= seq_buffer
;
553 if (parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
) {
557 /* Shouldn't happen */
558 fprintf (stderr
, "Internal error\n");
561 goto nodelay_try_again
;
564 c
= xgetch_second ();
566 pending_keys
= seq_append
= NULL
;
572 goto nodelay_try_again
;
576 /* We got a complete match, return and reset search */
579 pending_keys
= seq_append
= NULL
;
582 return correct_key_code (code
);
588 if (parent
!= NULL
&& parent
->action
== MCKEY_ESCAPE
) {
589 /* This is just to save a lot of define_sequences */
591 || (c
== '\n') || (c
== '\t') || (c
== XCTRL('h'))
592 || (c
== KEY_BACKSPACE
) || (c
== '!') || (c
== '\r')
593 || c
== 127 || c
== '+' || c
== '-' || c
== '\\'
600 pending_keys
= seq_append
= NULL
;
602 return correct_key_code (c
);
604 /* Did not find a match or {c} was changed in the if above,
605 so we have to return everything we had skipped
608 pending_keys
= seq_buffer
;
614 return correct_key_code (c
);
617 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
619 try_channels (int set_timeout
)
621 struct timeval timeout
;
622 static fd_set select_set
;
623 struct timeval
*timeptr
;
628 FD_ZERO (&select_set
);
629 FD_SET (input_fd
, &select_set
); /* Add stdin */
630 maxfdp
= max (add_selects (&select_set
), input_fd
);
634 timeout
.tv_usec
= 100000;
639 v
= select (maxfdp
+ 1, &select_set
, NULL
, NULL
, timeptr
);
641 check_selects (&select_set
);
642 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 */
670 extern int max_dirt_limit
;
672 /* Returns a character read from stdin with appropriate interpretation */
673 /* Also takes care of generated mouse events */
674 /* Returns EV_MOUSE if it is a mouse event */
675 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
677 get_event (Gpm_Event
* event
, int redo_event
, int block
)
680 static int flag
; /* Return value from select */
682 static Gpm_Event ev
; /* Mouse event */
684 struct timeval timeout
;
685 struct timeval
*time_addr
= NULL
;
686 static int dirty
= 3;
688 if ((dirty
== 3) || is_idle ()) {
695 vfs_timeout_handler ();
697 /* Ok, we use (event->x < 0) to signal that the event does not contain
698 a suitable position for the mouse, so we can't use show_mouse_pointer
702 show_mouse_pointer (event
->x
, event
->y
);
707 /* Repeat if using mouse */
708 while (mouse_enabled
&& !pending_keys
) {
712 FD_ZERO (&select_set
);
713 FD_SET (input_fd
, &select_set
);
714 maxfdp
= max (add_selects (&select_set
), input_fd
);
717 if (use_mouse_p
== MOUSE_GPM
) {
719 /* Connection to gpm broken, possibly gpm has died */
721 use_mouse_p
= MOUSE_NONE
;
724 FD_SET (gpm_fd
, &select_set
);
725 maxfdp
= max (maxfdp
, gpm_fd
);
730 timeout
.tv_usec
= mou_auto_repeat
* 1000;
733 time_addr
= &timeout
;
737 if ((seconds
= vfs_timeouts ())) {
738 /* the timeout could be improved and actually be
739 * the number of seconds until the next vfs entry
740 * timeouts in the stamp list.
743 timeout
.tv_sec
= seconds
;
745 time_addr
= &timeout
;
751 time_addr
= &timeout
;
755 enable_interrupt_key ();
756 flag
= select (maxfdp
+ 1, &select_set
, NULL
, NULL
, time_addr
);
757 disable_interrupt_key ();
759 /* select timed out: it could be for any of the following reasons:
760 * redo_event -> it was because of the MOU_REPEAT handler
761 * !block -> we did not block in the select call
762 * else -> 10 second timeout to check the vfs status.
769 vfs_timeout_handler ();
771 if (flag
== -1 && errno
== EINTR
)
774 check_selects (&select_set
);
776 if (FD_ISSET (input_fd
, &select_set
))
779 if (use_mouse_p
== MOUSE_GPM
&& FD_ISSET (gpm_fd
, &select_set
)) {
785 #endif /* !HAVE_LIBGPM */
788 flag
= is_wintouched (stdscr
);
790 #endif /* !HAVE_SLANG */
791 c
= block
? getch_with_delay () : get_key_code (1);
796 #endif /* !HAVE_SLANG */
801 #endif /* KEY_MOUSE */
804 xmouse_get_event (event
);
814 /* Returns a key press, mouse events are discarded */
821 while ((key
= get_event (&ev
, 0, 1)) == EV_NONE
)
826 static int xgetch_second (void)
830 struct timeval timeout
;
832 timeout
.tv_sec
= ESCMODE_TIMEOUT
/ 1000000;
833 timeout
.tv_usec
= ESCMODE_TIMEOUT
% 1000000;
834 nodelay (stdscr
, TRUE
);
835 FD_ZERO (&Read_FD_Set
);
836 FD_SET (input_fd
, &Read_FD_Set
);
837 select (input_fd
+ 1, &Read_FD_Set
, NULL
, NULL
, &timeout
);
839 nodelay (stdscr
, FALSE
);
844 learn_store_key (char *buffer
, char **p
, int c
)
846 if (*p
- buffer
> 253)
851 } else if (c
< ' ') {
853 *(*p
)++ = c
+ 'a' - 1;
854 } else if (c
== '^') {
861 char *learn_key (void)
863 /* LEARN_TIMEOUT in usec */
864 #define LEARN_TIMEOUT 200000
867 struct timeval endtime
;
868 struct timeval timeout
;
873 keypad(stdscr
, FALSE
); /* disable intepreting keys by ncurses */
876 c
= getch (); /* Sanity check, should be unnecessary */
877 learn_store_key (buffer
, &p
, c
);
879 endtime
.tv_usec
+= LEARN_TIMEOUT
;
880 if (endtime
.tv_usec
> 1000000) {
881 endtime
.tv_usec
-= 1000000;
884 nodelay (stdscr
, TRUE
);
886 while ((c
= getch ()) == ERR
) {
888 timeout
.tv_usec
= endtime
.tv_usec
- timeout
.tv_usec
;
889 if (timeout
.tv_usec
< 0)
891 timeout
.tv_sec
= endtime
.tv_sec
- timeout
.tv_sec
;
892 if (timeout
.tv_sec
>= 0 && timeout
.tv_usec
> 0) {
893 FD_ZERO (&Read_FD_Set
);
894 FD_SET (input_fd
, &Read_FD_Set
);
895 select (input_fd
+ 1, &Read_FD_Set
, NULL
, NULL
, &timeout
);
901 learn_store_key (buffer
, &p
, c
);
903 keypad(stdscr
, TRUE
);
904 nodelay (stdscr
, FALSE
);
906 return g_strdup (buffer
);
909 /* xterm and linux console only: set keypad to numeric or application
910 mode. Only in application keypad mode it's possible to distinguish
911 the '+' key and the '+' on the keypad ('*' and '-' ditto)*/
913 numeric_keypad_mode (void)
915 if (console_flag
|| xterm_flag
) {
916 fprintf (stdout
, "\033>");
922 application_keypad_mode (void)
924 if (console_flag
|| xterm_flag
) {
925 fprintf (stdout
, "\033=");
931 /* A function to check if we're idle.
932 Currently checks only for key presses.
933 We could also check the mouse. */
936 /* Check for incoming key presses *
937 * If there are any we say we're busy */
940 struct timeval timeout
;
941 FD_ZERO (&select_set
);
942 FD_SET (0, &select_set
);
945 select (1, &select_set
, 0, 0, &timeout
);
946 return ! FD_ISSET (0, &select_set
);
953 #ifdef HAVE_TEXTMODE_X11_SUPPORT
962 b
= XQueryPointer(x11_display
, x11_window
, &root
, &child
,
967 if (mask
& ShiftMask
)
968 result
|= SHIFT_PRESSED
;
969 if (mask
& ControlMask
)
970 result
|= CONTROL_PRESSED
;
976 unsigned char modifiers
;
980 if (ioctl (0, TIOCLINUX
, &modifiers
) < 0)
983 return (int) modifiers
;
993 if (get_modifier () & CONTROL_PRESSED
)
999 static void k_dispose (key_def
*k
)
1003 k_dispose (k
->child
);
1004 k_dispose (k
->next
);
1008 static void s_dispose (SelectList
*sel
)
1013 s_dispose (sel
->next
);
1020 s_dispose (select_list
);
1022 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1024 XCloseDisplay (x11_display
);
1025 #endif /* HAVE_TEXTMODE_X11_SUPPORT */