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 fd_set select_set
;
84 static int disabled_channels
= 0; /* Disable channels checking */
85 static int xgetch_second (void);
87 /* File descriptor monitoring add/remove routines */
88 typedef struct SelectList
{
92 struct SelectList
*next
;
95 static SelectList
*select_list
= 0;
97 void add_select_channel (int fd
, select_fn callback
, void *info
)
101 new = g_new (SelectList
, 1);
103 new->callback
= callback
;
105 new->next
= select_list
;
109 void delete_select_channel (int fd
)
111 SelectList
*p
= select_list
;
112 SelectList
*p_prev
= 0;
120 p_prev
->next
= p_next
;
122 select_list
= p_next
;
134 inline static int add_selects (fd_set
*select_set
)
139 if (disabled_channels
)
142 for (p
= select_list
; p
; p
= p
->next
){
143 FD_SET (p
->fd
, select_set
);
150 static void check_selects (fd_set
*select_set
)
154 if (disabled_channels
)
157 for (p
= select_list
; p
; p
= p
->next
)
158 if (FD_ISSET (p
->fd
, select_set
))
159 (*p
->callback
)(p
->fd
, p
->info
);
162 void channels_down (void)
164 disabled_channels
++;
167 void channels_up (void)
169 if (!disabled_channels
)
171 "Error: channels_up called with disabled_channels = 0\n");
175 typedef const struct {
181 static key_define_t mc_bindings
[] = {
182 { KEY_END
, ESC_STR
">", MCKEY_NOACTION
},
183 { KEY_HOME
, ESC_STR
"<", MCKEY_NOACTION
},
184 { 0, 0, MCKEY_NOACTION
},
187 /* Broken terminfo and termcap databases on xterminals */
188 static key_define_t xterm_key_defines
[] = {
189 { KEY_F(1), ESC_STR
"OP", MCKEY_NOACTION
},
190 { KEY_F(2), ESC_STR
"OQ", MCKEY_NOACTION
},
191 { KEY_F(3), ESC_STR
"OR", MCKEY_NOACTION
},
192 { KEY_F(4), ESC_STR
"OS", MCKEY_NOACTION
},
193 { KEY_F(1), ESC_STR
"[11~", MCKEY_NOACTION
},
194 { KEY_F(2), ESC_STR
"[12~", MCKEY_NOACTION
},
195 { KEY_F(3), ESC_STR
"[13~", MCKEY_NOACTION
},
196 { KEY_F(4), ESC_STR
"[14~", MCKEY_NOACTION
},
197 { KEY_F(5), ESC_STR
"[15~", MCKEY_NOACTION
},
198 { KEY_F(6), ESC_STR
"[17~", MCKEY_NOACTION
},
199 { KEY_F(7), ESC_STR
"[18~", MCKEY_NOACTION
},
200 { KEY_F(8), ESC_STR
"[19~", MCKEY_NOACTION
},
201 { KEY_F(9), ESC_STR
"[20~", MCKEY_NOACTION
},
202 { KEY_F(10), ESC_STR
"[21~", MCKEY_NOACTION
},
203 { 0, 0, MCKEY_NOACTION
},
206 static key_define_t mc_default_keys
[] = {
207 { ESC_CHAR
, ESC_STR
, MCKEY_ESCAPE
},
208 { ESC_CHAR
, ESC_STR ESC_STR
, MCKEY_NOACTION
},
209 { 0, 0, MCKEY_NOACTION
},
213 define_sequences (key_define_t
*kd
)
217 for (i
= 0; kd
[i
].code
; i
++)
218 define_sequence(kd
[i
].code
, kd
[i
].seq
, kd
[i
].action
);
221 #ifdef HAVE_TEXTMODE_X11_SUPPORT
222 static Display
*x11_display
;
223 static Window x11_window
;
224 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
226 /* This has to be called before slang_init or whatever routine
227 calls any define_sequence */
230 char *term
= (char *) getenv ("TERM");
232 /* This has to be the first define_sequence */
233 /* So, we can assume that the first keys member has ESC */
234 define_sequences (mc_default_keys
);
236 /* Terminfo on irix does not have some keys */
237 if ((!strncmp (term
, "iris-ansi", 9)) || (!strncmp (term
, "xterm", 5)))
238 define_sequences (xterm_key_defines
);
240 define_sequences (mc_bindings
);
242 /* load some additional keys (e.g. direct Alt-? support) */
243 load_xtra_key_defines();
246 if (strncmp(term
, "qnx", 3) == 0){
247 /* Modify the default value of use_8th_bit_as_meta: we would
248 * like to provide a working mc for a newbie who knows nothing
249 * about [Options|Display bits|Full 8 bits input]...
251 * Don't use 'meta'-bit, when we are dealing with a
252 * 'qnx*'-type terminal: clear the default value!
253 * These terminal types use 0xFF as an escape character,
254 * so use_8th_bit_as_meta==1 must not be enabled!
256 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
257 * is not used now (doesn't even depend on use_8th_bit_as_meta
258 * as in mc-3.1.2)...GREAT!...no additional code is required!]
260 use_8th_bit_as_meta
= 0;
264 #ifdef HAVE_TEXTMODE_X11_SUPPORT
265 x11_display
= XOpenDisplay (0);
267 x11_window
= DefaultRootWindow (x11_display
);
268 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
271 /* This has to be called after SLang_init_tty/slint_init */
272 void init_key_input_fd (void)
275 input_fd
= SLang_TT_Read_FD
;
281 xmouse_get_event (Gpm_Event
*ev
)
284 static struct timeval tv1
= { 0, 0 }; /* Force first click as single */
285 static struct timeval tv2
;
287 static int last_btn
= 0;
289 /* Decode Xterm mouse information to a GPM style event */
291 /* Variable btn has following meaning: */
292 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
293 btn
= xgetch () - 32;
295 /* There seems to be no way of knowing which button was released */
296 /* So we assume all the buttons were released */
300 ev
->type
= GPM_UP
| (GPM_SINGLE
<< clicks
);
306 /* Bogus event, maybe mouse wheel */
312 if (tv1
.tv_sec
&& (DIF_TIME (tv1
,tv2
) < double_click_speed
)){
320 ev
->buttons
= GPM_B_LEFT
;
323 ev
->buttons
= GPM_B_MIDDLE
;
326 ev
->buttons
= GPM_B_RIGHT
;
334 last_btn
= ev
->buttons
;
336 /* Coordinates are 33-based */
337 /* Transform them to 1-based */
338 ev
->x
= xgetch () - 32;
339 ev
->y
= xgetch () - 32;
342 static key_def
*create_sequence (char *seq
, int code
, int action
)
344 key_def
*base
, *p
, *attach
;
346 for (base
= attach
= NULL
; *seq
; seq
++){
347 p
= g_new (key_def
, 1);
349 if (attach
) attach
->child
= p
;
353 p
->child
= p
->next
= NULL
;
357 p
->action
= MCKEY_NOACTION
;
363 /* The maximum sequence length (32 + null terminator) */
364 #define SEQ_BUFFER_LEN 33
365 static int seq_buffer
[SEQ_BUFFER_LEN
];
366 static int *seq_append
= 0;
368 static int push_char (int c
)
371 seq_append
= seq_buffer
;
373 if (seq_append
== &(seq_buffer
[SEQ_BUFFER_LEN
-2]))
381 * Return 1 on success, 0 on error.
382 * An error happens if SEQ is a beginning of an existing longer sequence.
384 int define_sequence (int code
, char *seq
, int action
)
388 if (strlen (seq
) > SEQ_BUFFER_LEN
-1)
391 for (base
= keys
; (base
!= 0) && *seq
; ){
392 if (*seq
== base
->ch
){
393 if (base
->child
== 0){
395 base
->child
= create_sequence (seq
+1, code
, action
);
398 /* The sequence matches an existing one. */
400 base
->action
= action
;
411 base
->next
= create_sequence (seq
, code
, action
);
418 /* Attempt to redefine a sequence with a shorter sequence. */
422 keys
= create_sequence (seq
, code
, action
);
426 static int *pending_keys
;
429 correct_key_code (int c
)
431 /* This is needed on some OS that do not support ncurses and */
432 /* do some magic after read()ing the data */
437 if (c
== KEY_SCANCEL
)
444 if (!alternate_plus_minus
)
446 case KEY_KP_ADD
: c
= '+'; break;
447 case KEY_KP_SUBTRACT
: c
= '-'; break;
448 case KEY_KP_MULTIPLY
: c
= '*'; break;
454 int get_key_code (int no_delay
)
457 static key_def
*this = NULL
, *parent
;
458 static struct timeval esctime
= { -1, -1 };
459 static int lastnodelay
= -1;
461 if (no_delay
!= lastnodelay
) {
463 lastnodelay
= no_delay
;
468 int d
= *pending_keys
++;
474 if (d
== ESC_CHAR
&& pending_keys
){
475 d
= ALT(*pending_keys
++);
478 if ((d
& 0x80) && use_8th_bit_as_meta
)
481 return correct_key_code (d
);
486 nodelay (stdscr
, TRUE
);
489 #if defined(USE_NCURSES) && defined(KEY_RESIZE)
491 goto nodelay_try_again
;
494 nodelay (stdscr
, FALSE
);
496 if (this != NULL
&& parent
!= NULL
&&
497 parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
) {
498 struct timeval current
, timeout
;
500 if (esctime
.tv_sec
== -1)
503 timeout
.tv_sec
= ESCMODE_TIMEOUT
/ 1000000 + esctime
.tv_sec
;
504 timeout
.tv_usec
= ESCMODE_TIMEOUT
% 1000000 + esctime
.tv_usec
;
505 if (timeout
.tv_usec
> 1000000) {
506 timeout
.tv_usec
-= 1000000;
509 if (current
.tv_sec
< timeout
.tv_sec
)
511 if (current
.tv_sec
== timeout
.tv_sec
&&
512 current
.tv_usec
< timeout
.tv_usec
)
515 pending_keys
= seq_append
= NULL
;
520 } else if (c
== ERR
){
521 /* Maybe we got an incomplete match.
522 This we do only in delay mode, since otherwise
523 xgetch can return ERR at any time. */
525 pending_keys
= seq_buffer
;
532 /* Search the key on the root */
533 if (!no_delay
|| this == NULL
) {
537 if ((c
& 0x80) && use_8th_bit_as_meta
) {
540 /* The first sequence defined starts with esc */
549 pending_keys
= seq_buffer
;
554 if (parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
) {
558 /* Shouldn't happen */
559 fprintf (stderr
, "Internal error\n");
562 goto nodelay_try_again
;
565 c
= xgetch_second ();
567 pending_keys
= seq_append
= NULL
;
573 goto nodelay_try_again
;
577 /* We got a complete match, return and reset search */
580 pending_keys
= seq_append
= NULL
;
583 return correct_key_code (code
);
589 if (parent
!= NULL
&& parent
->action
== MCKEY_ESCAPE
) {
590 /* This is just to save a lot of define_sequences */
592 || (c
== '\n') || (c
== '\t') || (c
== XCTRL('h'))
593 || (c
== KEY_BACKSPACE
) || (c
== '!') || (c
== '\r')
594 || c
== 127 || c
== '+' || c
== '-' || c
== '\\'
601 pending_keys
= seq_append
= NULL
;
603 return correct_key_code (c
);
605 /* Did not find a match or {c} was changed in the if above,
606 so we have to return everything we had skipped
609 pending_keys
= seq_buffer
;
615 return correct_key_code (c
);
618 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
620 try_channels (int set_timeout
)
622 struct timeval timeout
;
623 static fd_set select_set
;
624 struct timeval
*timeptr
;
629 FD_ZERO (&select_set
);
630 FD_SET (input_fd
, &select_set
); /* Add stdin */
631 maxfdp
= max (add_selects (&select_set
), input_fd
);
635 timeout
.tv_usec
= 100000;
640 v
= select (maxfdp
+ 1, &select_set
, NULL
, NULL
, timeptr
);
642 check_selects (&select_set
);
643 if (FD_ISSET (input_fd
, &select_set
))
649 /* Workaround for System V Curses vt100 bug */
650 static int getch_with_delay (void)
654 /* This routine could be used on systems without mouse support,
655 so we need to do the select check :-( */
660 /* Try to get a character */
661 c
= get_key_code (0);
664 /* Failed -> wait 0.1 secs and try again */
667 /* Success -> return the character */
671 extern int max_dirt_limit
;
673 /* Returns a character read from stdin with appropriate interpretation */
674 /* Also takes care of generated mouse events */
675 /* Returns EV_MOUSE if it is a mouse event */
676 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
677 int 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
) {
711 FD_ZERO (&select_set
);
712 FD_SET (input_fd
, &select_set
);
713 maxfdp
= max (add_selects (&select_set
), input_fd
);
717 /* Connection to gpm broken, possibly gpm has died */
719 use_mouse_p
= MOUSE_NONE
;
721 if (mouse_enabled
&& use_mouse_p
== MOUSE_GPM
) {
722 FD_SET (gpm_fd
, &select_set
);
723 maxfdp
= max (maxfdp
, gpm_fd
);
728 timeout
.tv_usec
= mou_auto_repeat
* 1000;
731 time_addr
= &timeout
;
735 if ((seconds
= vfs_timeouts ())){
736 /* the timeout could be improved and actually be
737 * the number of seconds until the next vfs entry
738 * timeouts in the stamp list.
741 timeout
.tv_sec
= seconds
;
743 time_addr
= &timeout
;
749 time_addr
= &timeout
;
753 enable_interrupt_key ();
754 flag
= select (maxfdp
+ 1, &select_set
, NULL
, NULL
, time_addr
);
755 disable_interrupt_key ();
757 /* select timed out: it could be for any of the following reasons:
758 * redo_event -> it was because of the MOU_REPEAT handler
759 * !block -> we did not block in the select call
760 * else -> 10 second timeout to check the vfs status.
767 vfs_timeout_handler ();
769 if (flag
== -1 && errno
== EINTR
)
772 check_selects (&select_set
);
774 if (FD_ISSET (input_fd
, &select_set
))
778 if (mouse_enabled
&& use_mouse_p
== MOUSE_GPM
779 && 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
= xgetch (); /* 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
= xgetch ()) == 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 */