Merge branch '2621_path_encoding_and_extfs'
[midnight-commander.git] / lib / tty / key.c
blob963c1f77e08d9c35129cba79c1935854bb7335c6
1 /* Keyboard support routines.
3 Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
6 Written by: 1994, 1995 Miguel de Icaza.
7 1994, 1995 Janne Kukonlehto.
8 1995 Jakub Jelinek.
9 1997 Norbert Warmuth
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
25 /** \file key.c
26 * \brief Source: keyboard support routines
29 #include <config.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/time.h>
37 #include <sys/types.h>
38 #include <unistd.h>
40 #include "lib/global.h"
41 #include "lib/strutil.h" /* str_casecmp */
43 #include "lib/vfs/vfs.h"
45 #include "tty.h"
46 #include "tty-internal.h" /* mouse_enabled */
47 #include "mouse.h"
48 #include "key.h"
50 #include "lib/widget.h" /* mc_refresh() */
52 #ifdef HAVE_TEXTMODE_X11_SUPPORT
53 #include "x11conn.h"
54 #endif
56 #ifdef __linux__
57 #if defined(__GLIBC__) && (__GLIBC__ < 2)
58 #include <linux/termios.h> /* TIOCLINUX */
59 #else
60 #include <termios.h>
61 #endif
62 #include <sys/ioctl.h>
63 #endif /* __linux__ */
65 #ifdef __CYGWIN__
66 #include <termios.h>
67 #include <sys/ioctl.h>
68 #endif /* __CYGWIN__ */
70 #ifdef __QNXNTO__
71 #include <dlfcn.h>
72 #include <Ph.h>
73 #include <sys/dcmd_chr.h>
74 #endif /* __QNXNTO__ */
76 /*** global variables ****************************************************************************/
78 /* If true, use + and \ keys normally and select/unselect do if M-+ / M-\.
79 and M-- and keypad + / - */
80 int alternate_plus_minus = 0;
82 int mou_auto_repeat = 100;
83 int double_click_speed = 250;
84 int old_esc_mode = 0;
85 int use_8th_bit_as_meta = 0;
87 /* This table is a mapping between names and the constants we use
88 * We use this to allow users to define alternate definitions for
89 * certain keys that may be missing from the terminal database
91 const key_code_name_t key_name_conv_tab[] = {
92 /* KEY_F(0) is not here, since we are mapping it to f10, so there is no reason
93 to define f0 as well. Also, it makes Learn keys a bunch of problems :( */
94 {KEY_F (1), "f1", N_("Function key 1"), "F1"},
95 {KEY_F (2), "f2", N_("Function key 2"), "F2"},
96 {KEY_F (3), "f3", N_("Function key 3"), "F3"},
97 {KEY_F (4), "f4", N_("Function key 4"), "F4"},
98 {KEY_F (5), "f5", N_("Function key 5"), "F5"},
99 {KEY_F (6), "f6", N_("Function key 6"), "F6"},
100 {KEY_F (7), "f7", N_("Function key 7"), "F7"},
101 {KEY_F (8), "f8", N_("Function key 8"), "F8"},
102 {KEY_F (9), "f9", N_("Function key 9"), "F9"},
103 {KEY_F (10), "f10", N_("Function key 10"), "F10"},
104 {KEY_F (11), "f11", N_("Function key 11"), "F11"},
105 {KEY_F (12), "f12", N_("Function key 12"), "F12"},
106 {KEY_F (13), "f13", N_("Function key 13"), "F13"},
107 {KEY_F (14), "f14", N_("Function key 14"), "F14"},
108 {KEY_F (15), "f15", N_("Function key 15"), "F15"},
109 {KEY_F (16), "f16", N_("Function key 16"), "F16"},
110 {KEY_F (17), "f17", N_("Function key 17"), "F17"},
111 {KEY_F (18), "f18", N_("Function key 18"), "F18"},
112 {KEY_F (19), "f19", N_("Function key 19"), "F19"},
113 {KEY_F (20), "f20", N_("Function key 20"), "F20"},
114 {KEY_BACKSPACE, "backspace", N_("Backspace key"), "Backspace"},
115 {KEY_END, "end", N_("End key"), "End"},
116 {KEY_UP, "up", N_("Up arrow key"), "Up"},
117 {KEY_DOWN, "down", N_("Down arrow key"), "Down"},
118 {KEY_LEFT, "left", N_("Left arrow key"), "Left"},
119 {KEY_RIGHT, "right", N_("Right arrow key"), "Right"},
120 {KEY_HOME, "home", N_("Home key"), "Home"},
121 {KEY_NPAGE, "pgdn", N_("Page Down key"), "PgDn"},
122 {KEY_PPAGE, "pgup", N_("Page Up key"), "PgUp"},
123 {KEY_IC, "insert", N_("Insert key"), "Ins"},
124 {KEY_DC, "delete", N_("Delete key"), "Del"},
125 {ALT ('\t'), "complete", N_("Completion/M-tab"), "Meta-Tab"},
126 {KEY_KP_ADD, "kpplus", N_("+ on keypad"), "+"},
127 {KEY_KP_SUBTRACT, "kpminus", N_("- on keypad"), "-"},
128 {(int) '/', "kpslash", N_("Slash on keypad"), "/"},
129 {KEY_KP_MULTIPLY, "kpasterisk", N_("* on keypad"), "*"},
131 /* From here on, these won't be shown in Learn keys (no space) */
132 {ESC_CHAR, "escape", N_("Escape key"), "Esc"},
133 {KEY_LEFT, "kpleft", N_("Left arrow keypad"), "Left"},
134 {KEY_RIGHT, "kpright", N_("Right arrow keypad"), "Right"},
135 {KEY_UP, "kpup", N_("Up arrow keypad"), "Up"},
136 {KEY_DOWN, "kpdown", N_("Down arrow keypad"), "Down"},
137 {KEY_HOME, "kphome", N_("Home on keypad"), "Home"},
138 {KEY_END, "kpend", N_("End on keypad"), "End"},
139 {KEY_NPAGE, "kpnpage", N_("Page Down keypad"), "PgDn"},
140 {KEY_PPAGE, "kpppage", N_("Page Up keypad"), "PgUp"},
141 {KEY_IC, "kpinsert", N_("Insert on keypad"), "Ins"},
142 {KEY_DC, "kpdelete", N_("Delete on keypad"), "Del"},
143 {(int) '\n', "kpenter", N_("Enter on keypad"), "Enter"},
144 {KEY_F (21), "f21", N_("Function key 21"), "F21"},
145 {KEY_F (22), "f22", N_("Function key 22"), "F22"},
146 {KEY_F (23), "f23", N_("Function key 23"), "F23"},
147 {KEY_F (24), "f24", N_("Function key 24"), "F24"},
148 {KEY_A1, "a1", N_("A1 key"), "A1"},
149 {KEY_C1, "c1", N_("C1 key"), "C1"},
151 /* Alternative label */
152 {ESC_CHAR, "esc", N_("Escape key"), "Esc"},
153 {KEY_BACKSPACE, "bs", N_("Backspace key"), "Bakspace"},
154 {KEY_IC, "ins", N_("Insert key"), "Ins"},
155 {KEY_DC, "del", N_("Delete key"), "Del"},
156 {(int) '+', "plus", N_("Plus"), "+"},
157 {(int) '-', "minus", N_("Minus"), "-"},
158 {(int) '*', "asterisk", N_("Asterisk"), "*"},
159 {(int) '.', "dot", N_("Dot"), "."},
160 {(int) '<', "lt", N_("Less than"), "<"},
161 {(int) '>', "gt", N_("Great than"), ">"},
162 {(int) '=', "equal", N_("Equal"), "="},
163 {(int) ',', "comma", N_("Comma"), ","},
164 {(int) '\'', "apostrophe", N_("Apostrophe"), "\'"},
165 {(int) ':', "colon", N_("Colon"), ":"},
166 {(int) '!', "exclamation", N_("Exclamation mark"), "!"},
167 {(int) '?', "question", N_("Question mark"), "?"},
168 {(int) '&', "ampersand", N_("Ampersand"), "&"},
169 {(int) '$', "dollar", N_("Dollar sign"), "$"},
170 {(int) '"', "quota", N_("Quotation mark"), "\""},
171 {(int) '^', "caret", N_("Caret"), "^"},
172 {(int) '~', "tilda", N_("Tilda"), "~"},
173 {(int) '`', "prime", N_("Prime"), "`"},
174 {(int) '_', "underline", N_("Underline"), "_"},
175 {(int) '_', "understrike", N_("Understrike"), "_"},
176 {(int) '|', "pipe", N_("Pipe"), "|"},
177 {(int) '(', "lparenthesis", N_("Left parenthesis"), "("},
178 {(int) ')', "rparenthesis", N_("Right parenthesis"), ")"},
179 {(int) '[', "lbracket", N_("Left bracket"), "["},
180 {(int) ']', "rbracket", N_("Right bracket"), "]"},
181 {(int) '{', "lbrace", N_("Left brace"), "{"},
182 {(int) '}', "rbrace", N_("Right brace"), "}"},
183 {(int) '\n', "enter", N_("Enter"), "Enter"},
184 {(int) '\t', "tab", N_("Tab key"), "Tab"},
185 {(int) ' ', "space", N_("Space key"), "Space"},
186 {(int) '/', "slash", N_("Slash key"), "/"},
187 {(int) '\\', "backslash", N_("Backslash key"), "\\"},
188 {(int) '#', "number", N_("Number sign #"), "#"},
189 {(int) '#', "hash", N_("Number sign #"), "#"},
190 /* TRANSLATORS: Please translate as in "at sign" (@). */
191 {(int) '@', "at", N_("At sign"), "@"},
193 /* meta keys */
194 {KEY_M_CTRL, "control", N_("Ctrl"), "C"},
195 {KEY_M_CTRL, "ctrl", N_("Ctrl"), "C"},
196 {KEY_M_ALT, "meta", N_("Alt"), "M"},
197 {KEY_M_ALT, "alt", N_("Alt"), "M"},
198 {KEY_M_ALT, "ralt", N_("Alt"), "M"},
199 {KEY_M_SHIFT, "shift", N_("Shift"), "S"},
201 {0, NULL, NULL, NULL}
204 /*** file scope macro definitions ****************************************************************/
206 #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *) NULL))
207 #define DIF_TIME(t1, t2) ((t2.tv_sec - t1.tv_sec) * 1000 + (t2.tv_usec - t1.tv_usec)/1000)
209 /* The maximum sequence length (32 + null terminator) */
210 #define SEQ_BUFFER_LEN 33
212 /*** file scope type declarations ****************************************************************/
214 /* Linux console keyboard modifiers */
215 typedef enum
217 SHIFT_PRESSED = (1 << 0),
218 ALTR_PRESSED = (1 << 1),
219 CONTROL_PRESSED = (1 << 2),
220 ALTL_PRESSED = (1 << 3)
221 } mod_pressed_t;
223 typedef struct key_def
225 char ch; /* Holds the matching char code */
226 int code; /* The code returned, valid if child == NULL */
227 struct key_def *next;
228 struct key_def *child; /* sequence continuation */
229 int action; /* optional action to be done. Now used only
230 to mark that we are just after the first
231 Escape */
232 } key_def;
234 typedef struct
236 int code;
237 const char *seq;
238 int action;
239 } key_define_t;
241 /* File descriptor monitoring add/remove routines */
242 typedef struct SelectList
244 int fd;
245 select_fn callback;
246 void *info;
247 struct SelectList *next;
248 } SelectList;
250 typedef enum KeySortType
252 KEY_NOSORT = 0,
253 KEY_SORTBYNAME,
254 KEY_SORTBYCODE
255 } KeySortType;
257 #ifdef __QNXNTO__
258 typedef int (*ph_dv_f) (void *, void *);
259 typedef int (*ph_ov_f) (void *);
260 typedef int (*ph_pqc_f) (unsigned short, PhCursorInfo_t *);
261 #endif
263 /*** file scope variables ************************************************************************/
265 static key_define_t mc_default_keys[] = {
266 {ESC_CHAR, ESC_STR, MCKEY_ESCAPE},
267 {ESC_CHAR, ESC_STR ESC_STR, MCKEY_NOACTION},
268 {0, NULL, MCKEY_NOACTION},
271 /* Broken terminfo and termcap databases on xterminals */
272 static key_define_t xterm_key_defines[] = {
273 {KEY_F (1), ESC_STR "OP", MCKEY_NOACTION},
274 {KEY_F (2), ESC_STR "OQ", MCKEY_NOACTION},
275 {KEY_F (3), ESC_STR "OR", MCKEY_NOACTION},
276 {KEY_F (4), ESC_STR "OS", MCKEY_NOACTION},
277 {KEY_F (1), ESC_STR "[11~", MCKEY_NOACTION},
278 {KEY_F (2), ESC_STR "[12~", MCKEY_NOACTION},
279 {KEY_F (3), ESC_STR "[13~", MCKEY_NOACTION},
280 {KEY_F (4), ESC_STR "[14~", MCKEY_NOACTION},
281 {KEY_F (5), ESC_STR "[15~", MCKEY_NOACTION},
282 {KEY_F (6), ESC_STR "[17~", MCKEY_NOACTION},
283 {KEY_F (7), ESC_STR "[18~", MCKEY_NOACTION},
284 {KEY_F (8), ESC_STR "[19~", MCKEY_NOACTION},
285 {KEY_F (9), ESC_STR "[20~", MCKEY_NOACTION},
286 {KEY_F (10), ESC_STR "[21~", MCKEY_NOACTION},
288 /* old xterm Shift-arrows */
289 {KEY_M_SHIFT | KEY_UP, ESC_STR "O2A", MCKEY_NOACTION},
290 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "O2B", MCKEY_NOACTION},
291 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "O2C", MCKEY_NOACTION},
292 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "O2D", MCKEY_NOACTION},
294 /* new xterm Shift-arrows */
295 {KEY_M_SHIFT | KEY_UP, ESC_STR "[1;2A", MCKEY_NOACTION},
296 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[1;2B", MCKEY_NOACTION},
297 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[1;2C", MCKEY_NOACTION},
298 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[1;2D", MCKEY_NOACTION},
300 /* more xterm keys with modifiers */
301 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5;5~", MCKEY_NOACTION},
302 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6;5~", MCKEY_NOACTION},
303 {KEY_M_CTRL | KEY_IC, ESC_STR "[2;5~", MCKEY_NOACTION},
304 {KEY_M_CTRL | KEY_DC, ESC_STR "[3;5~", MCKEY_NOACTION},
305 {KEY_M_CTRL | KEY_HOME, ESC_STR "[1;5H", MCKEY_NOACTION},
306 {KEY_M_CTRL | KEY_END, ESC_STR "[1;5F", MCKEY_NOACTION},
307 {KEY_M_SHIFT | KEY_HOME, ESC_STR "[1;2H", MCKEY_NOACTION},
308 {KEY_M_SHIFT | KEY_END, ESC_STR "[1;2F", MCKEY_NOACTION},
309 {KEY_M_CTRL | KEY_UP, ESC_STR "[1;5A", MCKEY_NOACTION},
310 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;5B", MCKEY_NOACTION},
311 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;5C", MCKEY_NOACTION},
312 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;5D", MCKEY_NOACTION},
313 {KEY_M_SHIFT | KEY_IC, ESC_STR "[2;2~", MCKEY_NOACTION},
314 {KEY_M_SHIFT | KEY_DC, ESC_STR "[3;2~", MCKEY_NOACTION},
315 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[1;6A", MCKEY_NOACTION},
316 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;6B", MCKEY_NOACTION},
317 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;6C", MCKEY_NOACTION},
318 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;6D", MCKEY_NOACTION},
320 /* putty */
321 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[[1;6A", MCKEY_NOACTION},
322 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[[1;6B", MCKEY_NOACTION},
323 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[[1;6C", MCKEY_NOACTION},
324 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[[1;6D", MCKEY_NOACTION},
326 /* putty alt-arrow keys */
327 /* removed as source esc esc esc trouble */
329 { KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "OA", MCKEY_NOACTION },
330 { KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "OB", MCKEY_NOACTION },
331 { KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "OC", MCKEY_NOACTION },
332 { KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "OD", MCKEY_NOACTION },
333 { KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[5~", MCKEY_NOACTION },
334 { KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[6~", MCKEY_NOACTION },
335 { KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1~", MCKEY_NOACTION },
336 { KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[4~", MCKEY_NOACTION },
338 { KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "[1;2A", MCKEY_NOACTION },
339 { KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "[1;2B", MCKEY_NOACTION },
340 { KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "[1;2C", MCKEY_NOACTION },
341 { KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "[1;2D", MCKEY_NOACTION },
343 { KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[[5;5~", MCKEY_NOACTION },
344 { KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[[6;5~", MCKEY_NOACTION },
345 { KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1;5H", MCKEY_NOACTION },
346 { KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[1;5F", MCKEY_NOACTION },
348 /* xterm alt-arrow keys */
349 {KEY_M_ALT | KEY_UP, ESC_STR "[1;3A", MCKEY_NOACTION},
350 {KEY_M_ALT | KEY_DOWN, ESC_STR "[1;3B", MCKEY_NOACTION},
351 {KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;3C", MCKEY_NOACTION},
352 {KEY_M_ALT | KEY_LEFT, ESC_STR "[1;3D", MCKEY_NOACTION},
353 {KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;3~", MCKEY_NOACTION},
354 {KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;3~", MCKEY_NOACTION},
355 {KEY_M_ALT | KEY_HOME, ESC_STR "[1~", MCKEY_NOACTION},
356 {KEY_M_ALT | KEY_END, ESC_STR "[4~", MCKEY_NOACTION},
357 {KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR "[1;7A", MCKEY_NOACTION},
358 {KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR "[1;7B", MCKEY_NOACTION},
359 {KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;7C", MCKEY_NOACTION},
360 {KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR "[1;7D", MCKEY_NOACTION},
361 {KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;7~", MCKEY_NOACTION},
362 {KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;7~", MCKEY_NOACTION},
363 {KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR "OH", MCKEY_NOACTION},
364 {KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR "OF", MCKEY_NOACTION},
366 /* rxvt keys with modifiers */
367 {KEY_M_SHIFT | KEY_UP, ESC_STR "[a", MCKEY_NOACTION},
368 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION},
369 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION},
370 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION},
371 {KEY_M_CTRL | KEY_UP, ESC_STR "Oa", MCKEY_NOACTION},
372 {KEY_M_CTRL | KEY_DOWN, ESC_STR "Ob", MCKEY_NOACTION},
373 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "Oc", MCKEY_NOACTION},
374 {KEY_M_CTRL | KEY_LEFT, ESC_STR "Od", MCKEY_NOACTION},
375 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5^", MCKEY_NOACTION},
376 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6^", MCKEY_NOACTION},
377 {KEY_M_CTRL | KEY_HOME, ESC_STR "[7^", MCKEY_NOACTION},
378 {KEY_M_CTRL | KEY_END, ESC_STR "[8^", MCKEY_NOACTION},
379 {KEY_M_SHIFT | KEY_HOME, ESC_STR "[7$", MCKEY_NOACTION},
380 {KEY_M_SHIFT | KEY_END, ESC_STR "[8$", MCKEY_NOACTION},
381 {KEY_M_CTRL | KEY_IC, ESC_STR "[2^", MCKEY_NOACTION},
382 {KEY_M_CTRL | KEY_DC, ESC_STR "[3^", MCKEY_NOACTION},
383 {KEY_M_SHIFT | KEY_DC, ESC_STR "[3$", MCKEY_NOACTION},
385 /* konsole keys with modifiers */
386 {KEY_M_SHIFT | KEY_HOME, ESC_STR "O2H", MCKEY_NOACTION},
387 {KEY_M_SHIFT | KEY_END, ESC_STR "O2F", MCKEY_NOACTION},
389 /* gnome-terminal */
390 {KEY_M_SHIFT | KEY_UP, ESC_STR "[2A", MCKEY_NOACTION},
391 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[2B", MCKEY_NOACTION},
392 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[2C", MCKEY_NOACTION},
393 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[2D", MCKEY_NOACTION},
394 {KEY_M_CTRL | KEY_UP, ESC_STR "[5A", MCKEY_NOACTION},
395 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[5B", MCKEY_NOACTION},
396 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[5C", MCKEY_NOACTION},
397 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[5D", MCKEY_NOACTION},
398 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[6A", MCKEY_NOACTION},
399 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[6B", MCKEY_NOACTION},
400 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[6C", MCKEY_NOACTION},
401 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[6D", MCKEY_NOACTION},
403 /* gnome-terminal - application mode */
404 {KEY_M_CTRL | KEY_UP, ESC_STR "O5A", MCKEY_NOACTION},
405 {KEY_M_CTRL | KEY_DOWN, ESC_STR "O5B", MCKEY_NOACTION},
406 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "O5C", MCKEY_NOACTION},
407 {KEY_M_CTRL | KEY_LEFT, ESC_STR "O5D", MCKEY_NOACTION},
408 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "O6A", MCKEY_NOACTION},
409 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "O6B", MCKEY_NOACTION},
410 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "O6C", MCKEY_NOACTION},
411 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "O6D", MCKEY_NOACTION},
413 /* iTerm */
414 {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[5;2~", MCKEY_NOACTION},
415 {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[6;2~", MCKEY_NOACTION},
417 /* putty */
418 {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[[5;53~", MCKEY_NOACTION},
419 {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[[6;53~", MCKEY_NOACTION},
421 /* keypad keys */
422 {KEY_IC, ESC_STR "Op", MCKEY_NOACTION},
423 {KEY_DC, ESC_STR "On", MCKEY_NOACTION},
424 {'/', ESC_STR "Oo", MCKEY_NOACTION},
425 {'\n', ESC_STR "OM", MCKEY_NOACTION},
427 {0, NULL, MCKEY_NOACTION},
430 /* qansi-m terminals have a much more key combinatios,
431 which are undefined in termcap/terminfo */
432 static key_define_t qansi_key_defines[] = {
433 /* qansi-m terminal */
434 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[u", MCKEY_NOACTION}, /* Ctrl-PgDown */
435 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[v", MCKEY_NOACTION}, /* Ctrl-PgUp */
436 {KEY_M_CTRL | KEY_HOME, ESC_STR "[h", MCKEY_NOACTION}, /* Ctrl-Home */
437 {KEY_M_CTRL | KEY_END, ESC_STR "[y", MCKEY_NOACTION}, /* Ctrl-End */
438 {KEY_M_CTRL | KEY_IC, ESC_STR "[`", MCKEY_NOACTION}, /* Ctrl-Insert */
439 {KEY_M_CTRL | KEY_DC, ESC_STR "[p", MCKEY_NOACTION}, /* Ctrl-Delete */
440 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION}, /* Ctrl-Left */
441 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION}, /* Ctrl-Right */
442 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION}, /* Ctrl-Down */
443 {KEY_M_CTRL | KEY_UP, ESC_STR "[a", MCKEY_NOACTION}, /* Ctrl-Up */
444 {KEY_M_CTRL | KEY_KP_ADD, ESC_STR "[s", MCKEY_NOACTION}, /* Ctrl-Gr-Plus */
445 {KEY_M_CTRL | KEY_KP_SUBTRACT, ESC_STR "[t", MCKEY_NOACTION}, /* Ctrl-Gr-Minus */
446 {KEY_M_CTRL | '\t', ESC_STR "[z", MCKEY_NOACTION}, /* Ctrl-Tab */
447 {KEY_M_SHIFT | '\t', ESC_STR "[Z", MCKEY_NOACTION}, /* Shift-Tab */
448 {KEY_M_CTRL | KEY_F (1), ESC_STR "[1~", MCKEY_NOACTION}, /* Ctrl-F1 */
449 {KEY_M_CTRL | KEY_F (2), ESC_STR "[2~", MCKEY_NOACTION}, /* Ctrl-F2 */
450 {KEY_M_CTRL | KEY_F (3), ESC_STR "[3~", MCKEY_NOACTION}, /* Ctrl-F3 */
451 {KEY_M_CTRL | KEY_F (4), ESC_STR "[4~", MCKEY_NOACTION}, /* Ctrl-F4 */
452 {KEY_M_CTRL | KEY_F (5), ESC_STR "[5~", MCKEY_NOACTION}, /* Ctrl-F5 */
453 {KEY_M_CTRL | KEY_F (6), ESC_STR "[6~", MCKEY_NOACTION}, /* Ctrl-F6 */
454 {KEY_M_CTRL | KEY_F (7), ESC_STR "[7~", MCKEY_NOACTION}, /* Ctrl-F7 */
455 {KEY_M_CTRL | KEY_F (8), ESC_STR "[8~", MCKEY_NOACTION}, /* Ctrl-F8 */
456 {KEY_M_CTRL | KEY_F (9), ESC_STR "[9~", MCKEY_NOACTION}, /* Ctrl-F9 */
457 {KEY_M_CTRL | KEY_F (10), ESC_STR "[10~", MCKEY_NOACTION}, /* Ctrl-F10 */
458 {KEY_M_CTRL | KEY_F (11), ESC_STR "[11~", MCKEY_NOACTION}, /* Ctrl-F11 */
459 {KEY_M_CTRL | KEY_F (12), ESC_STR "[12~", MCKEY_NOACTION}, /* Ctrl-F12 */
460 {KEY_M_ALT | KEY_F (1), ESC_STR "[17~", MCKEY_NOACTION}, /* Alt-F1 */
461 {KEY_M_ALT | KEY_F (2), ESC_STR "[18~", MCKEY_NOACTION}, /* Alt-F2 */
462 {KEY_M_ALT | KEY_F (3), ESC_STR "[19~", MCKEY_NOACTION}, /* Alt-F3 */
463 {KEY_M_ALT | KEY_F (4), ESC_STR "[20~", MCKEY_NOACTION}, /* Alt-F4 */
464 {KEY_M_ALT | KEY_F (5), ESC_STR "[21~", MCKEY_NOACTION}, /* Alt-F5 */
465 {KEY_M_ALT | KEY_F (6), ESC_STR "[22~", MCKEY_NOACTION}, /* Alt-F6 */
466 {KEY_M_ALT | KEY_F (7), ESC_STR "[23~", MCKEY_NOACTION}, /* Alt-F7 */
467 {KEY_M_ALT | KEY_F (8), ESC_STR "[24~", MCKEY_NOACTION}, /* Alt-F8 */
468 {KEY_M_ALT | KEY_F (9), ESC_STR "[25~", MCKEY_NOACTION}, /* Alt-F9 */
469 {KEY_M_ALT | KEY_F (10), ESC_STR "[26~", MCKEY_NOACTION}, /* Alt-F10 */
470 {KEY_M_ALT | KEY_F (11), ESC_STR "[27~", MCKEY_NOACTION}, /* Alt-F11 */
471 {KEY_M_ALT | KEY_F (12), ESC_STR "[28~", MCKEY_NOACTION}, /* Alt-F12 */
472 {KEY_M_ALT | 'a', ESC_STR "Na", MCKEY_NOACTION}, /* Alt-a */
473 {KEY_M_ALT | 'b', ESC_STR "Nb", MCKEY_NOACTION}, /* Alt-b */
474 {KEY_M_ALT | 'c', ESC_STR "Nc", MCKEY_NOACTION}, /* Alt-c */
475 {KEY_M_ALT | 'd', ESC_STR "Nd", MCKEY_NOACTION}, /* Alt-d */
476 {KEY_M_ALT | 'e', ESC_STR "Ne", MCKEY_NOACTION}, /* Alt-e */
477 {KEY_M_ALT | 'f', ESC_STR "Nf", MCKEY_NOACTION}, /* Alt-f */
478 {KEY_M_ALT | 'g', ESC_STR "Ng", MCKEY_NOACTION}, /* Alt-g */
479 {KEY_M_ALT | 'h', ESC_STR "Nh", MCKEY_NOACTION}, /* Alt-h */
480 {KEY_M_ALT | 'i', ESC_STR "Ni", MCKEY_NOACTION}, /* Alt-i */
481 {KEY_M_ALT | 'j', ESC_STR "Nj", MCKEY_NOACTION}, /* Alt-j */
482 {KEY_M_ALT | 'k', ESC_STR "Nk", MCKEY_NOACTION}, /* Alt-k */
483 {KEY_M_ALT | 'l', ESC_STR "Nl", MCKEY_NOACTION}, /* Alt-l */
484 {KEY_M_ALT | 'm', ESC_STR "Nm", MCKEY_NOACTION}, /* Alt-m */
485 {KEY_M_ALT | 'n', ESC_STR "Nn", MCKEY_NOACTION}, /* Alt-n */
486 {KEY_M_ALT | 'o', ESC_STR "No", MCKEY_NOACTION}, /* Alt-o */
487 {KEY_M_ALT | 'p', ESC_STR "Np", MCKEY_NOACTION}, /* Alt-p */
488 {KEY_M_ALT | 'q', ESC_STR "Nq", MCKEY_NOACTION}, /* Alt-q */
489 {KEY_M_ALT | 'r', ESC_STR "Nr", MCKEY_NOACTION}, /* Alt-r */
490 {KEY_M_ALT | 's', ESC_STR "Ns", MCKEY_NOACTION}, /* Alt-s */
491 {KEY_M_ALT | 't', ESC_STR "Nt", MCKEY_NOACTION}, /* Alt-t */
492 {KEY_M_ALT | 'u', ESC_STR "Nu", MCKEY_NOACTION}, /* Alt-u */
493 {KEY_M_ALT | 'v', ESC_STR "Nv", MCKEY_NOACTION}, /* Alt-v */
494 {KEY_M_ALT | 'w', ESC_STR "Nw", MCKEY_NOACTION}, /* Alt-w */
495 {KEY_M_ALT | 'x', ESC_STR "Nx", MCKEY_NOACTION}, /* Alt-x */
496 {KEY_M_ALT | 'y', ESC_STR "Ny", MCKEY_NOACTION}, /* Alt-y */
497 {KEY_M_ALT | 'z', ESC_STR "Nz", MCKEY_NOACTION}, /* Alt-z */
498 {KEY_KP_SUBTRACT, ESC_STR "[S", MCKEY_NOACTION}, /* Gr-Minus */
499 {KEY_KP_ADD, ESC_STR "[T", MCKEY_NOACTION}, /* Gr-Plus */
500 {0, NULL, MCKEY_NOACTION},
503 /* timeout for old_esc_mode in usec */
504 int old_esc_mode_timeout = 1000000; /* settable via env */
506 /* This holds all the key definitions */
507 static key_def *keys = NULL;
509 static int input_fd;
510 static int disabled_channels = 0; /* Disable channels checking */
512 static SelectList *select_list = NULL;
514 static int seq_buffer[SEQ_BUFFER_LEN];
515 static int *seq_append = NULL;
517 static int *pending_keys = NULL;
519 #ifdef __QNXNTO__
520 ph_dv_f ph_attach;
521 ph_ov_f ph_input_group;
522 ph_pqc_f ph_query_cursor;
523 #endif
525 #ifdef HAVE_TEXTMODE_X11_SUPPORT
526 static Display *x11_display;
527 static Window x11_window;
528 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
530 static KeySortType has_been_sorted = KEY_NOSORT;
532 /* *INDENT-OFF* */
533 static const size_t key_conv_tab_size = G_N_ELEMENTS (key_name_conv_tab) - 1;
534 /* *INDENT-ON* */
536 static const key_code_name_t *key_conv_tab_sorted[G_N_ELEMENTS (key_name_conv_tab) - 1];
538 /*** file scope functions ************************************************************************/
539 /* --------------------------------------------------------------------------------------------- */
541 static int
542 add_selects (fd_set * select_set)
544 int top_fd = 0;
546 if (disabled_channels == 0)
548 SelectList *p;
550 for (p = select_list; p != NULL; p = p->next)
552 FD_SET (p->fd, select_set);
553 if (p->fd > top_fd)
554 top_fd = p->fd;
558 return top_fd;
561 /* --------------------------------------------------------------------------------------------- */
563 static void
564 check_selects (fd_set * select_set)
566 if (disabled_channels == 0)
568 gboolean retry;
572 SelectList *p;
574 retry = FALSE;
575 for (p = select_list; p; p = p->next)
576 if (FD_ISSET (p->fd, select_set))
578 FD_CLR (p->fd, select_set);
579 (*p->callback) (p->fd, p->info);
580 retry = TRUE;
581 break;
584 while (retry);
588 /* --------------------------------------------------------------------------------------------- */
589 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
591 static void
592 try_channels (int set_timeout)
594 struct timeval time_out;
595 static fd_set select_set;
596 struct timeval *timeptr;
597 int v;
598 int maxfdp;
600 while (1)
602 FD_ZERO (&select_set);
603 FD_SET (input_fd, &select_set); /* Add stdin */
604 maxfdp = max (add_selects (&select_set), input_fd);
606 timeptr = NULL;
607 if (set_timeout)
609 time_out.tv_sec = 0;
610 time_out.tv_usec = 100000;
611 timeptr = &time_out;
614 v = select (maxfdp + 1, &select_set, NULL, NULL, timeptr);
615 if (v > 0)
617 check_selects (&select_set);
618 if (FD_ISSET (input_fd, &select_set))
619 break;
624 /* --------------------------------------------------------------------------------------------- */
626 static key_def *
627 create_sequence (const char *seq, int code, int action)
629 key_def *base, *p, *attach;
631 for (base = attach = NULL; *seq; seq++)
633 p = g_new (key_def, 1);
634 if (base == NULL)
635 base = p;
636 if (attach != NULL)
637 attach->child = p;
639 p->ch = *seq;
640 p->code = code;
641 p->child = p->next = NULL;
642 if (seq[1] == '\0')
643 p->action = action;
644 else
645 p->action = MCKEY_NOACTION;
646 attach = p;
648 return base;
651 /* --------------------------------------------------------------------------------------------- */
653 static void
654 define_sequences (const key_define_t * kd)
656 int i;
658 for (i = 0; kd[i].code != 0; i++)
659 define_sequence (kd[i].code, kd[i].seq, kd[i].action);
662 /* --------------------------------------------------------------------------------------------- */
664 static void
665 init_key_x11 (void)
667 #ifdef HAVE_TEXTMODE_X11_SUPPORT
668 if (getenv ("DISPLAY") != NULL)
670 x11_display = mc_XOpenDisplay (0);
672 if (x11_display != NULL)
673 x11_window = DefaultRootWindow (x11_display);
675 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
678 /* --------------------------------------------------------------------------------------------- */
679 /* Workaround for System V Curses vt100 bug */
681 static int
682 getch_with_delay (void)
684 int c;
686 /* This routine could be used on systems without mouse support,
687 so we need to do the select check :-( */
688 while (1)
690 if (pending_keys == NULL)
691 try_channels (0);
693 /* Try to get a character */
694 c = get_key_code (0);
695 if (c != -1)
696 break;
697 /* Failed -> wait 0.1 secs and try again */
698 try_channels (1);
700 /* Success -> return the character */
701 return c;
704 /* --------------------------------------------------------------------------------------------- */
706 static void
707 xmouse_get_event (Gpm_Event * ev)
709 int btn;
710 static struct timeval tv1 = { 0, 0 }; /* Force first click as single */
711 static struct timeval tv2;
712 static int clicks = 0;
713 static int last_btn = 0;
715 /* Decode Xterm mouse information to a GPM style event */
717 /* Variable btn has following meaning: */
718 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
719 btn = tty_lowlevel_getch () - 32;
721 /* There seems to be no way of knowing which button was released */
722 /* So we assume all the buttons were released */
724 if (btn == 3)
726 if (last_btn != 0)
728 if ((last_btn & (GPM_B_UP | GPM_B_DOWN)) != 0)
730 /* FIXME: DIRTY HACK */
731 /* don't generate GPM_UP after mouse wheel */
732 /* need for menu event handling */
733 ev->type = 0;
734 tv1.tv_sec = 0;
735 tv1.tv_usec = 0;
737 else
739 ev->type = GPM_UP | (GPM_SINGLE << clicks);
740 GET_TIME (tv1);
742 ev->buttons = 0;
743 last_btn = 0;
744 clicks = 0;
746 else
748 /* Bogus event, maybe mouse wheel */
749 ev->type = 0;
752 else
754 if (btn >= 32 && btn <= 34)
756 btn -= 32;
757 ev->type = GPM_DRAG;
759 else
760 ev->type = GPM_DOWN;
762 GET_TIME (tv2);
763 if (tv1.tv_sec && (DIF_TIME (tv1, tv2) < double_click_speed))
765 clicks++;
766 clicks %= 3;
768 else
769 clicks = 0;
771 switch (btn)
773 case 0:
774 ev->buttons = GPM_B_LEFT;
775 break;
776 case 1:
777 ev->buttons = GPM_B_MIDDLE;
778 break;
779 case 2:
780 ev->buttons = GPM_B_RIGHT;
781 break;
782 case 64:
783 ev->buttons = GPM_B_UP;
784 clicks = 0;
785 break;
786 case 65:
787 ev->buttons = GPM_B_DOWN;
788 clicks = 0;
789 break;
790 default:
791 /* Nothing */
792 ev->type = 0;
793 ev->buttons = 0;
794 break;
796 last_btn = ev->buttons;
798 /* Coordinates are 33-based */
799 /* Transform them to 1-based */
800 ev->x = tty_lowlevel_getch () - 32;
801 ev->y = tty_lowlevel_getch () - 32;
804 /* --------------------------------------------------------------------------------------------- */
806 * Get modifier state (shift, alt, ctrl) for the last key pressed.
807 * We are assuming that the state didn't change since the key press.
808 * This is only correct if get_modifier() is called very fast after
809 * the input was received, so that the user didn't release the
810 * modifier keys yet.
813 static int
814 get_modifier (void)
816 int result = 0;
817 #ifdef __QNXNTO__
818 int mod_status, shift_ext_status;
819 static int in_photon = 0;
820 static int ph_ig = 0;
821 PhCursorInfo_t cursor_info;
822 #endif /* __QNXNTO__ */
824 #ifdef HAVE_TEXTMODE_X11_SUPPORT
825 if (x11_window != 0)
827 Window root, child;
828 int root_x, root_y;
829 int win_x, win_y;
830 unsigned int mask;
832 mc_XQueryPointer (x11_display, x11_window, &root, &child, &root_x,
833 &root_y, &win_x, &win_y, &mask);
835 if (mask & ShiftMask)
836 result |= KEY_M_SHIFT;
837 if (mask & ControlMask)
838 result |= KEY_M_CTRL;
839 return result;
841 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
842 #ifdef __QNXNTO__
844 if (in_photon == 0)
846 /* First time here, let's load Photon library and attach
847 to Photon */
848 in_photon = -1;
849 if (getenv ("PHOTON2_PATH") != NULL)
851 /* QNX 6.x has no support for RTLD_LAZY */
852 void *ph_handle = dlopen ("/usr/lib/libph.so", RTLD_NOW);
853 if (ph_handle != NULL)
855 ph_attach = (ph_dv_f) dlsym (ph_handle, "PhAttach");
856 ph_input_group = (ph_ov_f) dlsym (ph_handle, "PhInputGroup");
857 ph_query_cursor = (ph_pqc_f) dlsym (ph_handle, "PhQueryCursor");
858 if ((ph_attach != NULL) && (ph_input_group != NULL) && (ph_query_cursor != NULL))
860 if ((*ph_attach) (0, 0))
861 { /* Attached */
862 ph_ig = (*ph_input_group) (0);
863 in_photon = 1;
869 /* We do not have Photon running. Assume we are in text
870 console or xterm */
871 if (in_photon == -1)
873 if (devctl (fileno (stdin), DCMD_CHR_LINESTATUS, &mod_status, sizeof (int), NULL) == -1)
874 return 0;
875 shift_ext_status = mod_status & 0xffffff00UL;
876 mod_status &= 0x7f;
877 if (mod_status & _LINESTATUS_CON_ALT)
878 result |= KEY_M_ALT;
879 if (mod_status & _LINESTATUS_CON_CTRL)
880 result |= KEY_M_CTRL;
881 if ((mod_status & _LINESTATUS_CON_SHIFT) || (shift_ext_status & 0x00000800UL))
882 result |= KEY_M_SHIFT;
884 else
886 (*ph_query_cursor) (ph_ig, &cursor_info);
887 if (cursor_info.key_mods & 0x04)
888 result |= KEY_M_ALT;
889 if (cursor_info.key_mods & 0x02)
890 result |= KEY_M_CTRL;
891 if (cursor_info.key_mods & 0x01)
892 result |= KEY_M_SHIFT;
894 #endif /* __QNXNTO__ */
896 #if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX)
898 unsigned char modifiers = 6;
900 if (ioctl (0, TIOCLINUX, &modifiers) < 0)
901 return 0;
903 /* Translate Linux modifiers into mc modifiers */
904 if (modifiers & SHIFT_PRESSED)
905 result |= KEY_M_SHIFT;
906 if (modifiers & (ALTL_PRESSED | ALTR_PRESSED))
907 result |= KEY_M_ALT;
908 if (modifiers & CONTROL_PRESSED)
909 result |= KEY_M_CTRL;
911 #endif /* !__linux__ */
912 return result;
915 /* --------------------------------------------------------------------------------------------- */
917 static gboolean
918 push_char (int c)
920 gboolean ret = FALSE;
922 if (seq_append == NULL)
923 seq_append = seq_buffer;
925 if (seq_append != &(seq_buffer[SEQ_BUFFER_LEN - 2]))
927 *(seq_append++) = c;
928 *seq_append = 0;
929 ret = TRUE;
932 return ret;
935 /* --------------------------------------------------------------------------------------------- */
936 /* Apply corrections for the keycode generated in get_key_code() */
938 static int
939 correct_key_code (int code)
941 unsigned int c = code & ~KEY_M_MASK; /* code without modifier */
942 unsigned int mod = code & KEY_M_MASK; /* modifier */
943 #ifdef __QNXNTO__
944 unsigned int qmod; /* bunch of the QNX console
945 modifiers needs unchanged */
946 #endif /* __QNXNTO__ */
949 * Add key modifiers directly from X11 or OS.
950 * Ordinary characters only get modifiers from sequences.
952 if (c < 32 || c >= 256)
954 mod |= get_modifier ();
957 /* This is needed if the newline is reported as carriage return */
958 if (c == '\r')
959 c = '\n';
961 /* This is reported to be useful on AIX */
962 if (c == KEY_SCANCEL)
963 c = '\t';
965 /* Convert Shift+Tab and Ctrl+Tab to Back Tab */
966 if ((c == '\t') && (mod & (KEY_M_SHIFT | KEY_M_CTRL)))
968 c = KEY_BTAB;
969 mod = 0;
972 /* F0 is the same as F10 for out purposes */
973 if (c == KEY_F (0))
974 c = KEY_F (10);
977 * We are not interested if Ctrl was pressed when entering control
978 * characters, so assume that it was. When checking for such keys,
979 * XCTRL macro should be used. In some cases, we are interested,
980 * e.g. to distinguish Ctrl-Enter from Enter.
982 if (c == '\b')
984 /* Special case for backspase ('\b' < 32) */
985 c = KEY_BACKSPACE;
986 mod &= ~KEY_M_CTRL;
988 else if (c < 32 && c != ESC_CHAR && c != '\t' && c != '\n')
990 mod |= KEY_M_CTRL;
993 #ifdef __QNXNTO__
994 qmod = get_modifier ();
996 if ((c == 127) && (mod == 0))
997 { /* Add Ctrl/Alt/Shift-BackSpace */
998 mod |= get_modifier ();
999 c = KEY_BACKSPACE;
1002 if ((c == '0') && (mod == 0))
1003 { /* Add Shift-Insert on key pad */
1004 if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1006 mod = KEY_M_SHIFT;
1007 c = KEY_IC;
1011 if ((c == '.') && (mod == 0))
1012 { /* Add Shift-Del on key pad */
1013 if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1015 mod = KEY_M_SHIFT;
1016 c = KEY_DC;
1019 #endif /* __QNXNTO__ */
1021 /* Unrecognized 0177 is delete (preserve Ctrl) */
1022 if (c == 0177)
1024 c = KEY_BACKSPACE;
1027 #if 0
1028 /* Unrecognized Ctrl-d is delete */
1029 if (c == (31 & 'd'))
1031 c = KEY_DC;
1032 mod &= ~KEY_M_CTRL;
1035 /* Unrecognized Ctrl-h is backspace */
1036 if (c == (31 & 'h'))
1038 c = KEY_BACKSPACE;
1039 mod &= ~KEY_M_CTRL;
1041 #endif
1043 /* Shift+BackSpace is backspace */
1044 if (c == KEY_BACKSPACE && (mod & KEY_M_SHIFT))
1046 mod &= ~KEY_M_SHIFT;
1049 /* Convert Shift+Fn to F(n+10) */
1050 if (c >= KEY_F (1) && c <= KEY_F (10) && (mod & KEY_M_SHIFT))
1052 c += 10;
1055 /* Remove Shift information from function keys */
1056 if (c >= KEY_F (1) && c <= KEY_F (20))
1058 mod &= ~KEY_M_SHIFT;
1061 if (!alternate_plus_minus)
1062 switch (c)
1064 case KEY_KP_ADD:
1065 c = '+';
1066 break;
1067 case KEY_KP_SUBTRACT:
1068 c = '-';
1069 break;
1070 case KEY_KP_MULTIPLY:
1071 c = '*';
1072 break;
1075 return (mod | c);
1078 /* --------------------------------------------------------------------------------------------- */
1080 static int
1081 xgetch_second (void)
1083 fd_set Read_FD_Set;
1084 int c;
1085 struct timeval time_out;
1087 time_out.tv_sec = old_esc_mode_timeout / 1000000;
1088 time_out.tv_usec = old_esc_mode_timeout % 1000000;
1089 tty_nodelay (TRUE);
1090 FD_ZERO (&Read_FD_Set);
1091 FD_SET (input_fd, &Read_FD_Set);
1092 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
1093 c = tty_lowlevel_getch ();
1094 tty_nodelay (FALSE);
1095 return c;
1098 /* --------------------------------------------------------------------------------------------- */
1100 static void
1101 learn_store_key (char *buffer, char **p, int c)
1103 if (*p - buffer > 253)
1104 return;
1105 if (c == ESC_CHAR)
1107 *(*p)++ = '\\';
1108 *(*p)++ = 'e';
1110 else if (c < ' ')
1112 *(*p)++ = '^';
1113 *(*p)++ = c + 'a' - 1;
1115 else if (c == '^')
1117 *(*p)++ = '^';
1118 *(*p)++ = '^';
1120 else
1121 *(*p)++ = (char) c;
1124 /* --------------------------------------------------------------------------------------------- */
1126 static void
1127 k_dispose (key_def * k)
1129 if (k != NULL)
1131 k_dispose (k->child);
1132 k_dispose (k->next);
1133 g_free (k);
1137 /* --------------------------------------------------------------------------------------------- */
1139 static void
1140 s_dispose (SelectList * sel)
1142 if (sel != NULL)
1144 s_dispose (sel->next);
1145 g_free (sel);
1149 /* --------------------------------------------------------------------------------------------- */
1151 static int
1152 key_code_comparator_by_name (const void *p1, const void *p2)
1154 const key_code_name_t *n1 = *(const key_code_name_t **) p1;
1155 const key_code_name_t *n2 = *(const key_code_name_t **) p2;
1157 return str_casecmp (n1->name, n2->name);
1160 /* --------------------------------------------------------------------------------------------- */
1162 static int
1163 key_code_comparator_by_code (const void *p1, const void *p2)
1165 const key_code_name_t *n1 = *(const key_code_name_t **) p1;
1166 const key_code_name_t *n2 = *(const key_code_name_t **) p2;
1168 return n1->code - n2->code;
1171 /* --------------------------------------------------------------------------------------------- */
1173 static inline void
1174 sort_key_conv_tab (enum KeySortType type_sort)
1176 if (has_been_sorted != type_sort)
1178 size_t i;
1179 for (i = 0; i < key_conv_tab_size; i++)
1180 key_conv_tab_sorted[i] = &key_name_conv_tab[i];
1182 if (type_sort == KEY_SORTBYNAME)
1184 qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1185 &key_code_comparator_by_name);
1187 else if (type_sort == KEY_SORTBYCODE)
1189 qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1190 &key_code_comparator_by_code);
1192 has_been_sorted = type_sort;
1196 /* --------------------------------------------------------------------------------------------- */
1198 static int
1199 lookup_keyname (const char *name, int *idx)
1201 if (name[0] != '\0')
1203 const key_code_name_t key = { 0, name, NULL, NULL };
1204 const key_code_name_t *keyp = &key;
1205 key_code_name_t **res;
1207 if (name[1] == '\0')
1209 *idx = -1;
1210 return (int) name[0];
1213 sort_key_conv_tab (KEY_SORTBYNAME);
1215 res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1216 sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_name);
1218 if (res != NULL)
1220 *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
1221 return (*res)->code;
1225 *idx = -1;
1226 return 0;
1229 /* --------------------------------------------------------------------------------------------- */
1231 static gboolean
1232 lookup_keycode (const long code, int *idx)
1234 if (code != 0)
1236 const key_code_name_t key = { code, NULL, NULL, NULL };
1237 const key_code_name_t *keyp = &key;
1238 key_code_name_t **res;
1240 sort_key_conv_tab (KEY_SORTBYCODE);
1242 res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1243 sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_code);
1245 if (res != NULL)
1247 *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
1248 return TRUE;
1252 *idx = -1;
1253 return FALSE;
1256 /* --------------------------------------------------------------------------------------------- */
1257 /*** public functions ****************************************************************************/
1258 /* --------------------------------------------------------------------------------------------- */
1259 /* This has to be called before init_slang or whatever routine
1260 calls any define_sequence */
1262 void
1263 init_key (void)
1265 const char *term = getenv ("TERM");
1267 /* This has to be the first define_sequence */
1268 /* So, we can assume that the first keys member has ESC */
1269 define_sequences (mc_default_keys);
1271 /* Terminfo on irix does not have some keys */
1272 if (mc_global.tty.xterm_flag
1273 || (term != NULL
1274 && (strncmp (term, "iris-ansi", 9) == 0
1275 || strncmp (term, "xterm", 5) == 0
1276 || strncmp (term, "rxvt", 4) == 0 || strcmp (term, "screen") == 0)))
1277 define_sequences (xterm_key_defines);
1279 /* load some additional keys (e.g. direct Alt-? support) */
1280 load_xtra_key_defines ();
1282 #ifdef __QNX__
1283 if ((term != NULL) && (strncmp (term, "qnx", 3) == 0))
1285 /* Modify the default value of use_8th_bit_as_meta: we would
1286 * like to provide a working mc for a newbie who knows nothing
1287 * about [Options|Display bits|Full 8 bits input]...
1289 * Don't use 'meta'-bit, when we are dealing with a
1290 * 'qnx*'-type terminal: clear the default value!
1291 * These terminal types use 0xFF as an escape character,
1292 * so use_8th_bit_as_meta==1 must not be enabled!
1294 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
1295 * is not used now (doesn't even depend on use_8th_bit_as_meta
1296 * as in mc-3.1.2)...GREAT!...no additional code is required!]
1298 use_8th_bit_as_meta = 0;
1300 #endif /* __QNX__ */
1302 init_key_x11 ();
1304 /* Load the qansi-m key definitions
1305 if we are running under the qansi-m terminal */
1306 if (term != NULL && (strncmp (term, "qansi-m", 7) == 0))
1307 define_sequences (qansi_key_defines);
1310 /* --------------------------------------------------------------------------------------------- */
1312 * This has to be called after SLang_init_tty/slint_init
1315 void
1316 init_key_input_fd (void)
1318 #ifdef HAVE_SLANG
1319 input_fd = SLang_TT_Read_FD;
1320 #endif
1323 /* --------------------------------------------------------------------------------------------- */
1325 void
1326 done_key (void)
1328 k_dispose (keys);
1329 s_dispose (select_list);
1331 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1332 if (x11_display)
1333 mc_XCloseDisplay (x11_display);
1334 #endif
1337 /* --------------------------------------------------------------------------------------------- */
1339 void
1340 add_select_channel (int fd, select_fn callback, void *info)
1342 SelectList *new;
1344 new = g_new (SelectList, 1);
1345 new->fd = fd;
1346 new->callback = callback;
1347 new->info = info;
1348 new->next = select_list;
1349 select_list = new;
1352 /* --------------------------------------------------------------------------------------------- */
1354 void
1355 delete_select_channel (int fd)
1357 SelectList *p = select_list;
1358 SelectList *p_prev = NULL;
1359 SelectList *p_next;
1361 while (p != NULL)
1362 if (p->fd == fd)
1364 p_next = p->next;
1366 if (p_prev != NULL)
1367 p_prev->next = p_next;
1368 else
1369 select_list = p_next;
1371 g_free (p);
1372 p = p_next;
1374 else
1376 p_prev = p;
1377 p = p->next;
1381 /* --------------------------------------------------------------------------------------------- */
1383 void
1384 channels_up (void)
1386 if (disabled_channels == 0)
1387 fputs ("Error: channels_up called with disabled_channels = 0\n", stderr);
1388 disabled_channels--;
1391 /* --------------------------------------------------------------------------------------------- */
1393 void
1394 channels_down (void)
1396 disabled_channels++;
1399 /* --------------------------------------------------------------------------------------------- */
1401 * Return the code associated with the symbolic name keyname
1404 long
1405 lookup_key (const char *name, char **label)
1407 char **lc_keys, **p;
1408 int k = -1;
1409 int key = 0;
1410 int lc_index = -1;
1412 int use_meta = -1;
1413 int use_ctrl = -1;
1414 int use_shift = -1;
1416 if (name == NULL)
1417 return 0;
1419 name = g_strstrip (g_strdup (name));
1420 p = lc_keys = g_strsplit_set (name, "-+ ", -1);
1421 g_free ((char *) name);
1423 while ((p != NULL) && (*p != NULL))
1425 if ((*p)[0] != '\0')
1427 int idx;
1429 key = lookup_keyname (g_strstrip (*p), &idx);
1431 if (key == KEY_M_ALT)
1432 use_meta = idx;
1433 else if (key == KEY_M_CTRL)
1434 use_ctrl = idx;
1435 else if (key == KEY_M_SHIFT)
1436 use_shift = idx;
1437 else
1439 k = key;
1440 lc_index = idx;
1441 break;
1445 p++;
1448 g_strfreev (lc_keys);
1450 /* output */
1451 if (k <= 0)
1452 return 0;
1455 if (label != NULL)
1457 GString *s;
1459 s = g_string_new ("");
1461 if (use_meta != -1)
1463 g_string_append (s, key_conv_tab_sorted[use_meta]->shortcut);
1464 g_string_append_c (s, '-');
1466 if (use_ctrl != -1)
1468 g_string_append (s, key_conv_tab_sorted[use_ctrl]->shortcut);
1469 g_string_append_c (s, '-');
1471 if (use_shift != -1)
1473 if (k < 127)
1474 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1475 else
1477 g_string_append (s, key_conv_tab_sorted[use_shift]->shortcut);
1478 g_string_append_c (s, '-');
1479 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1482 else if (k < 128)
1484 if ((k >= 'A') || (lc_index < 0) || (key_conv_tab_sorted[lc_index]->shortcut == NULL))
1485 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) k));
1486 else
1487 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1489 else if ((lc_index != -1) && (key_conv_tab_sorted[lc_index]->shortcut != NULL))
1490 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1491 else
1492 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) key));
1494 *label = g_string_free (s, FALSE);
1497 if (use_shift != -1)
1499 if (k < 127 && k > 31)
1500 k = g_ascii_toupper ((gchar) k);
1501 else
1502 k |= KEY_M_SHIFT;
1505 if (use_ctrl != -1)
1507 if (k < 256)
1508 k = XCTRL (k);
1509 else
1510 k |= KEY_M_CTRL;
1513 if (use_meta != -1)
1514 k = ALT (k);
1516 return (long) k;
1519 /* --------------------------------------------------------------------------------------------- */
1521 char *
1522 lookup_key_by_code (const int keycode)
1524 /* code without modifier */
1525 unsigned int k = keycode & ~KEY_M_MASK;
1526 /* modifier */
1527 unsigned int mod = keycode & KEY_M_MASK;
1529 int use_meta = -1;
1530 int use_ctrl = -1;
1531 int use_shift = -1;
1532 int key_idx = -1;
1534 GString *s;
1535 int idx;
1537 s = g_string_sized_new (8);
1539 if (lookup_keycode (k, &key_idx) || (k > 0 && k < 256))
1541 if (mod & KEY_M_ALT)
1543 if (lookup_keycode (KEY_M_ALT, &idx))
1545 use_meta = idx;
1546 g_string_append (s, key_conv_tab_sorted[use_meta]->name);
1547 g_string_append_c (s, '-');
1550 if (mod & KEY_M_CTRL)
1552 /* non printeble chars like a CTRL-[A..Z] */
1553 if (k < 32)
1554 k += 64;
1556 if (lookup_keycode (KEY_M_CTRL, &idx))
1558 use_ctrl = idx;
1559 g_string_append (s, key_conv_tab_sorted[use_ctrl]->name);
1560 g_string_append_c (s, '-');
1563 if (mod & KEY_M_SHIFT)
1565 if (lookup_keycode (KEY_M_ALT, &idx))
1567 use_shift = idx;
1568 if (k < 127)
1569 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1570 else
1572 g_string_append (s, key_conv_tab_sorted[use_shift]->name);
1573 g_string_append_c (s, '-');
1574 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1578 else if (k < 128)
1580 if ((k >= 'A') || (key_idx < 0) || (key_conv_tab_sorted[key_idx]->name == NULL))
1581 g_string_append_c (s, (gchar) k);
1582 else
1583 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1585 else if ((key_idx != -1) && (key_conv_tab_sorted[key_idx]->name != NULL))
1586 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1587 else
1588 g_string_append_c (s, (gchar) keycode);
1591 return g_string_free (s, s->len == 0);
1594 /* --------------------------------------------------------------------------------------------- */
1596 * Return TRUE on success, FALSE on error.
1597 * An error happens if SEQ is a beginning of an existing longer sequence.
1600 gboolean
1601 define_sequence (int code, const char *seq, int action)
1603 key_def *base;
1605 if (strlen (seq) > SEQ_BUFFER_LEN - 1)
1606 return FALSE;
1608 for (base = keys; (base != NULL) && (*seq != '\0');)
1609 if (*seq == base->ch)
1611 if (base->child == 0)
1613 if (*(seq + 1) != '\0')
1614 base->child = create_sequence (seq + 1, code, action);
1615 else
1617 /* The sequence matches an existing one. */
1618 base->code = code;
1619 base->action = action;
1621 return TRUE;
1624 base = base->child;
1625 seq++;
1627 else
1629 if (base->next)
1630 base = base->next;
1631 else
1633 base->next = create_sequence (seq, code, action);
1634 return TRUE;
1638 if (*seq == '\0')
1640 /* Attempt to redefine a sequence with a shorter sequence. */
1641 return FALSE;
1644 keys = create_sequence (seq, code, action);
1645 return TRUE;
1648 /* --------------------------------------------------------------------------------------------- */
1650 * Check if we are idle, i.e. there are no pending keyboard or mouse
1651 * events. Return 1 is idle, 0 is there are pending events.
1653 gboolean
1654 is_idle (void)
1656 int maxfdp;
1657 fd_set select_set;
1658 struct timeval time_out;
1660 FD_ZERO (&select_set);
1661 FD_SET (input_fd, &select_set);
1662 maxfdp = input_fd;
1663 #ifdef HAVE_LIBGPM
1664 if (mouse_enabled && (use_mouse_p == MOUSE_GPM) && (gpm_fd > 0))
1666 FD_SET (gpm_fd, &select_set);
1667 maxfdp = max (maxfdp, gpm_fd);
1669 #endif
1670 time_out.tv_sec = 0;
1671 time_out.tv_usec = 0;
1672 return (select (maxfdp + 1, &select_set, 0, 0, &time_out) <= 0);
1675 /* --------------------------------------------------------------------------------------------- */
1678 get_key_code (int no_delay)
1680 int c;
1681 static key_def *this = NULL, *parent;
1682 static struct timeval esctime = { -1, -1 };
1683 static int lastnodelay = -1;
1685 if (no_delay != lastnodelay)
1687 this = NULL;
1688 lastnodelay = no_delay;
1691 pend_send:
1692 if (pending_keys != NULL)
1694 int d = *pending_keys++;
1695 check_pend:
1696 if (*pending_keys == 0)
1698 pending_keys = NULL;
1699 seq_append = NULL;
1701 if ((d == ESC_CHAR) && (pending_keys != NULL))
1703 d = ALT (*pending_keys++);
1704 goto check_pend;
1706 if ((d > 127 && d < 256) && use_8th_bit_as_meta)
1707 d = ALT (d & 0x7f);
1708 this = NULL;
1709 return correct_key_code (d);
1712 nodelay_try_again:
1713 if (no_delay)
1714 tty_nodelay (TRUE);
1716 c = tty_lowlevel_getch ();
1717 #if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE)
1718 if (c == KEY_RESIZE)
1719 goto nodelay_try_again;
1720 #endif
1721 if (no_delay)
1723 tty_nodelay (FALSE);
1724 if (c == -1)
1726 if (this != NULL && parent != NULL && parent->action == MCKEY_ESCAPE && old_esc_mode)
1728 struct timeval current, time_out;
1730 if (esctime.tv_sec == -1)
1731 return -1;
1732 GET_TIME (current);
1733 time_out.tv_sec = old_esc_mode_timeout / 1000000 + esctime.tv_sec;
1734 time_out.tv_usec = old_esc_mode_timeout % 1000000 + esctime.tv_usec;
1735 if (time_out.tv_usec > 1000000)
1737 time_out.tv_usec -= 1000000;
1738 time_out.tv_sec++;
1740 if (current.tv_sec < time_out.tv_sec)
1741 return -1;
1742 if (current.tv_sec == time_out.tv_sec && current.tv_usec < time_out.tv_usec)
1743 return -1;
1744 this = NULL;
1745 pending_keys = seq_append = NULL;
1746 return ESC_CHAR;
1748 return -1;
1751 else if (c == -1)
1753 /* Maybe we got an incomplete match.
1754 This we do only in delay mode, since otherwise
1755 tty_lowlevel_getch can return -1 at any time. */
1756 if (seq_append != NULL)
1758 pending_keys = seq_buffer;
1759 goto pend_send;
1761 this = NULL;
1762 return -1;
1765 /* Search the key on the root */
1766 if (!no_delay || this == NULL)
1768 this = keys;
1769 parent = NULL;
1771 if ((c > 127 && c < 256) && use_8th_bit_as_meta)
1773 c &= 0x7f;
1775 /* The first sequence defined starts with esc */
1776 parent = keys;
1777 this = keys->child;
1780 while (this != NULL)
1782 if (c == this->ch)
1784 if (this->child)
1786 if (!push_char (c))
1788 pending_keys = seq_buffer;
1789 goto pend_send;
1791 parent = this;
1792 this = this->child;
1793 if (parent->action == MCKEY_ESCAPE && old_esc_mode)
1795 if (no_delay)
1797 GET_TIME (esctime);
1798 if (this == NULL)
1800 /* Shouldn't happen */
1801 fputs ("Internal error\n", stderr);
1802 exit (EXIT_FAILURE);
1804 goto nodelay_try_again;
1806 esctime.tv_sec = -1;
1807 c = xgetch_second ();
1808 if (c == -1)
1810 pending_keys = seq_append = NULL;
1811 this = NULL;
1812 return ESC_CHAR;
1815 else
1817 if (no_delay)
1818 goto nodelay_try_again;
1819 c = tty_lowlevel_getch ();
1822 else
1824 /* We got a complete match, return and reset search */
1825 int code;
1827 pending_keys = seq_append = NULL;
1828 code = this->code;
1829 this = NULL;
1830 return correct_key_code (code);
1833 else
1835 if (this->next != NULL)
1836 this = this->next;
1837 else
1839 if ((parent != NULL) && (parent->action == MCKEY_ESCAPE))
1841 /* Convert escape-digits to F-keys */
1842 if (g_ascii_isdigit (c))
1843 c = KEY_F (c - '0');
1844 else if (c == ' ')
1845 c = ESC_CHAR;
1846 else
1847 c = ALT (c);
1849 pending_keys = seq_append = NULL;
1850 this = NULL;
1851 return correct_key_code (c);
1853 /* Did not find a match or {c} was changed in the if above,
1854 so we have to return everything we had skipped
1856 push_char (c);
1857 pending_keys = seq_buffer;
1858 goto pend_send;
1862 this = NULL;
1863 return correct_key_code (c);
1866 /* --------------------------------------------------------------------------------------------- */
1867 /* Returns a character read from stdin with appropriate interpretation */
1868 /* Also takes care of generated mouse events */
1869 /* Returns EV_MOUSE if it is a mouse event */
1870 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
1873 tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block)
1875 int c;
1876 static int flag = 0; /* Return value from select */
1877 #ifdef HAVE_LIBGPM
1878 static struct Gpm_Event ev; /* Mouse event */
1879 #endif
1880 struct timeval time_out;
1881 struct timeval *time_addr = NULL;
1882 static int dirty = 3;
1884 if ((dirty == 3) || is_idle ())
1886 mc_refresh ();
1887 dirty = 1;
1889 else
1890 dirty++;
1892 vfs_timeout_handler ();
1894 /* Ok, we use (event->x < 0) to signal that the event does not contain
1895 a suitable position for the mouse, so we can't use show_mouse_pointer
1896 on it.
1898 if (event->x > 0)
1900 show_mouse_pointer (event->x, event->y);
1901 if (!redo_event)
1902 event->x = -1;
1905 /* Repeat if using mouse */
1906 while (pending_keys == NULL)
1908 int maxfdp;
1909 fd_set select_set;
1911 FD_ZERO (&select_set);
1912 FD_SET (input_fd, &select_set);
1913 maxfdp = max (add_selects (&select_set), input_fd);
1915 #ifdef HAVE_LIBGPM
1916 if (mouse_enabled && (use_mouse_p == MOUSE_GPM))
1918 if (gpm_fd < 0)
1920 /* Connection to gpm broken, possibly gpm has died */
1921 mouse_enabled = FALSE;
1922 use_mouse_p = MOUSE_NONE;
1923 break;
1926 FD_SET (gpm_fd, &select_set);
1927 maxfdp = max (maxfdp, gpm_fd);
1929 #endif
1931 if (redo_event)
1933 time_out.tv_usec = mou_auto_repeat * 1000;
1934 time_out.tv_sec = 0;
1936 time_addr = &time_out;
1938 else
1940 int seconds;
1942 seconds = vfs_timeouts ();
1943 time_addr = NULL;
1945 if (seconds != 0)
1947 /* the timeout could be improved and actually be
1948 * the number of seconds until the next vfs entry
1949 * timeouts in the stamp list.
1952 time_out.tv_sec = seconds;
1953 time_out.tv_usec = 0;
1954 time_addr = &time_out;
1958 if (!block || mc_global.tty.winch_flag)
1960 time_addr = &time_out;
1961 time_out.tv_sec = 0;
1962 time_out.tv_usec = 0;
1965 tty_enable_interrupt_key ();
1966 flag = select (maxfdp + 1, &select_set, NULL, NULL, time_addr);
1967 tty_disable_interrupt_key ();
1969 /* select timed out: it could be for any of the following reasons:
1970 * redo_event -> it was because of the MOU_REPEAT handler
1971 * !block -> we did not block in the select call
1972 * else -> 10 second timeout to check the vfs status.
1974 if (flag == 0)
1976 if (redo_event)
1977 return EV_MOUSE;
1978 if (!block || mc_global.tty.winch_flag)
1979 return EV_NONE;
1980 vfs_timeout_handler ();
1982 if (flag == -1 && errno == EINTR)
1983 return EV_NONE;
1985 check_selects (&select_set);
1987 if (FD_ISSET (input_fd, &select_set))
1988 break;
1989 #ifdef HAVE_LIBGPM
1990 if (mouse_enabled && use_mouse_p == MOUSE_GPM
1991 && gpm_fd > 0 && FD_ISSET (gpm_fd, &select_set))
1993 Gpm_GetEvent (&ev);
1994 Gpm_FitEvent (&ev);
1995 *event = ev;
1996 return EV_MOUSE;
1998 #endif /* !HAVE_LIBGPM */
2001 #ifndef HAVE_SLANG
2002 flag = is_wintouched (stdscr);
2003 untouchwin (stdscr);
2004 #endif /* !HAVE_SLANG */
2005 c = block ? getch_with_delay () : get_key_code (1);
2007 #ifndef HAVE_SLANG
2008 if (flag > 0)
2009 tty_touch_screen ();
2010 #endif /* !HAVE_SLANG */
2012 if (mouse_enabled && (c == MCKEY_MOUSE
2013 #ifdef KEY_MOUSE
2014 || c == KEY_MOUSE
2015 #endif /* KEY_MOUSE */
2018 /* Mouse event */
2019 xmouse_get_event (event);
2020 return (event->type != 0) ? EV_MOUSE : EV_NONE;
2023 return c;
2026 /* --------------------------------------------------------------------------------------------- */
2027 /* Returns a key press, mouse events are discarded */
2030 tty_getch (void)
2032 Gpm_Event ev;
2033 int key;
2035 ev.x = -1;
2036 while ((key = tty_get_event (&ev, FALSE, TRUE)) == EV_NONE);
2037 return key;
2040 /* --------------------------------------------------------------------------------------------- */
2042 char *
2043 learn_key (void)
2045 /* LEARN_TIMEOUT in usec */
2046 #define LEARN_TIMEOUT 200000
2048 fd_set Read_FD_Set;
2049 struct timeval endtime;
2050 struct timeval time_out;
2051 int c;
2052 char buffer[256];
2053 char *p = buffer;
2055 tty_keypad (FALSE); /* disable intepreting keys by ncurses */
2056 c = tty_lowlevel_getch ();
2057 while (c == -1)
2058 c = tty_lowlevel_getch (); /* Sanity check, should be unnecessary */
2059 learn_store_key (buffer, &p, c);
2060 GET_TIME (endtime);
2061 endtime.tv_usec += LEARN_TIMEOUT;
2062 if (endtime.tv_usec > 1000000)
2064 endtime.tv_usec -= 1000000;
2065 endtime.tv_sec++;
2067 tty_nodelay (TRUE);
2068 for (;;)
2070 while ((c = tty_lowlevel_getch ()) == -1)
2072 GET_TIME (time_out);
2073 time_out.tv_usec = endtime.tv_usec - time_out.tv_usec;
2074 if (time_out.tv_usec < 0)
2075 time_out.tv_sec++;
2076 time_out.tv_sec = endtime.tv_sec - time_out.tv_sec;
2077 if (time_out.tv_sec >= 0 && time_out.tv_usec > 0)
2079 FD_ZERO (&Read_FD_Set);
2080 FD_SET (input_fd, &Read_FD_Set);
2081 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
2083 else
2084 break;
2086 if (c == -1)
2087 break;
2088 learn_store_key (buffer, &p, c);
2090 tty_keypad (TRUE);
2091 tty_nodelay (FALSE);
2092 *p = '\0';
2093 return g_strdup (buffer);
2094 #undef LEARN_TIMEOUT
2097 /* --------------------------------------------------------------------------------------------- */
2098 /* xterm and linux console only: set keypad to numeric or application
2099 mode. Only in application keypad mode it's possible to distinguish
2100 the '+' key and the '+' on the keypad ('*' and '-' ditto) */
2102 void
2103 numeric_keypad_mode (void)
2105 if (mc_global.tty.console_flag || mc_global.tty.xterm_flag)
2107 fputs (ESC_STR ">", stdout);
2108 fflush (stdout);
2112 /* --------------------------------------------------------------------------------------------- */
2114 void
2115 application_keypad_mode (void)
2117 if (mc_global.tty.console_flag || mc_global.tty.xterm_flag)
2119 fputs (ESC_STR "=", stdout);
2120 fflush (stdout);
2124 /* --------------------------------------------------------------------------------------------- */