2 Keyboard support routines.
4 Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
5 2005, 2006, 2007, 2009, 2010, 2011
6 The Free Software Foundation, Inc.
9 Miguel de Icaza, 1994, 1995
10 Janne Kukonlehto, 1994, 1995
14 This file is part of the Midnight Commander.
16 The Midnight Commander is free software: you can redistribute it
17 and/or modify it under the terms of the GNU General Public License as
18 published by the Free Software Foundation, either version 3 of the License,
19 or (at your option) any later version.
21 The Midnight Commander is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program. If not, see <http://www.gnu.org/licenses/>.
31 * \brief Source: keyboard support routines
42 #include <sys/types.h>
45 #include "lib/global.h"
46 #include "lib/strutil.h" /* str_casecmp */
48 #include "lib/vfs/vfs.h"
51 #include "tty-internal.h" /* mouse_enabled */
55 #include "lib/widget.h" /* mc_refresh() */
57 #ifdef HAVE_TEXTMODE_X11_SUPPORT
62 #if defined(__GLIBC__) && (__GLIBC__ < 2)
63 #include <linux/termios.h> /* TIOCLINUX */
67 #include <sys/ioctl.h>
68 #endif /* __linux__ */
72 #include <sys/ioctl.h>
73 #endif /* __CYGWIN__ */
78 #include <sys/dcmd_chr.h>
79 #endif /* __QNXNTO__ */
81 /*** global variables ****************************************************************************/
83 int mou_auto_repeat
= 100;
84 int double_click_speed
= 250;
86 int use_8th_bit_as_meta
= 0;
88 /* This table is a mapping between names and the constants we use
89 * We use this to allow users to define alternate definitions for
90 * certain keys that may be missing from the terminal database
92 const key_code_name_t key_name_conv_tab
[] = {
93 /* KEY_F(0) is not here, since we are mapping it to f10, so there is no reason
94 to define f0 as well. Also, it makes Learn keys a bunch of problems :( */
95 {KEY_F (1), "f1", N_("Function key 1"), "F1"},
96 {KEY_F (2), "f2", N_("Function key 2"), "F2"},
97 {KEY_F (3), "f3", N_("Function key 3"), "F3"},
98 {KEY_F (4), "f4", N_("Function key 4"), "F4"},
99 {KEY_F (5), "f5", N_("Function key 5"), "F5"},
100 {KEY_F (6), "f6", N_("Function key 6"), "F6"},
101 {KEY_F (7), "f7", N_("Function key 7"), "F7"},
102 {KEY_F (8), "f8", N_("Function key 8"), "F8"},
103 {KEY_F (9), "f9", N_("Function key 9"), "F9"},
104 {KEY_F (10), "f10", N_("Function key 10"), "F10"},
105 {KEY_F (11), "f11", N_("Function key 11"), "F11"},
106 {KEY_F (12), "f12", N_("Function key 12"), "F12"},
107 {KEY_F (13), "f13", N_("Function key 13"), "F13"},
108 {KEY_F (14), "f14", N_("Function key 14"), "F14"},
109 {KEY_F (15), "f15", N_("Function key 15"), "F15"},
110 {KEY_F (16), "f16", N_("Function key 16"), "F16"},
111 {KEY_F (17), "f17", N_("Function key 17"), "F17"},
112 {KEY_F (18), "f18", N_("Function key 18"), "F18"},
113 {KEY_F (19), "f19", N_("Function key 19"), "F19"},
114 {KEY_F (20), "f20", N_("Function key 20"), "F20"},
115 {KEY_BACKSPACE
, "backspace", N_("Backspace key"), "Backspace"},
116 {KEY_END
, "end", N_("End key"), "End"},
117 {KEY_UP
, "up", N_("Up arrow key"), "Up"},
118 {KEY_DOWN
, "down", N_("Down arrow key"), "Down"},
119 {KEY_LEFT
, "left", N_("Left arrow key"), "Left"},
120 {KEY_RIGHT
, "right", N_("Right arrow key"), "Right"},
121 {KEY_HOME
, "home", N_("Home key"), "Home"},
122 {KEY_NPAGE
, "pgdn", N_("Page Down key"), "PgDn"},
123 {KEY_PPAGE
, "pgup", N_("Page Up key"), "PgUp"},
124 {KEY_IC
, "insert", N_("Insert key"), "Ins"},
125 {KEY_DC
, "delete", N_("Delete key"), "Del"},
126 {ALT ('\t'), "complete", N_("Completion/M-tab"), "Meta-Tab"},
127 {KEY_KP_ADD
, "kpplus", N_("+ on keypad"), "+"},
128 {KEY_KP_SUBTRACT
, "kpminus", N_("- on keypad"), "-"},
129 {(int) '/', "kpslash", N_("Slash on keypad"), "/"},
130 {KEY_KP_MULTIPLY
, "kpasterisk", N_("* on keypad"), "*"},
132 /* From here on, these won't be shown in Learn keys (no space) */
133 {ESC_CHAR
, "escape", N_("Escape key"), "Esc"},
134 {KEY_LEFT
, "kpleft", N_("Left arrow keypad"), "Left"},
135 {KEY_RIGHT
, "kpright", N_("Right arrow keypad"), "Right"},
136 {KEY_UP
, "kpup", N_("Up arrow keypad"), "Up"},
137 {KEY_DOWN
, "kpdown", N_("Down arrow keypad"), "Down"},
138 {KEY_HOME
, "kphome", N_("Home on keypad"), "Home"},
139 {KEY_END
, "kpend", N_("End on keypad"), "End"},
140 {KEY_NPAGE
, "kpnpage", N_("Page Down keypad"), "PgDn"},
141 {KEY_PPAGE
, "kpppage", N_("Page Up keypad"), "PgUp"},
142 {KEY_IC
, "kpinsert", N_("Insert on keypad"), "Ins"},
143 {KEY_DC
, "kpdelete", N_("Delete on keypad"), "Del"},
144 {(int) '\n', "kpenter", N_("Enter on keypad"), "Enter"},
145 {KEY_F (21), "f21", N_("Function key 21"), "F21"},
146 {KEY_F (22), "f22", N_("Function key 22"), "F22"},
147 {KEY_F (23), "f23", N_("Function key 23"), "F23"},
148 {KEY_F (24), "f24", N_("Function key 24"), "F24"},
149 {KEY_A1
, "a1", N_("A1 key"), "A1"},
150 {KEY_C1
, "c1", N_("C1 key"), "C1"},
152 /* Alternative label */
153 {ESC_CHAR
, "esc", N_("Escape key"), "Esc"},
154 {KEY_BACKSPACE
, "bs", N_("Backspace key"), "Bakspace"},
155 {KEY_IC
, "ins", N_("Insert key"), "Ins"},
156 {KEY_DC
, "del", N_("Delete key"), "Del"},
157 {(int) '+', "plus", N_("Plus"), "+"},
158 {(int) '-', "minus", N_("Minus"), "-"},
159 {(int) '*', "asterisk", N_("Asterisk"), "*"},
160 {(int) '.', "dot", N_("Dot"), "."},
161 {(int) '<', "lt", N_("Less than"), "<"},
162 {(int) '>', "gt", N_("Great than"), ">"},
163 {(int) '=', "equal", N_("Equal"), "="},
164 {(int) ',', "comma", N_("Comma"), ","},
165 {(int) '\'', "apostrophe", N_("Apostrophe"), "\'"},
166 {(int) ':', "colon", N_("Colon"), ":"},
167 {(int) '!', "exclamation", N_("Exclamation mark"), "!"},
168 {(int) '?', "question", N_("Question mark"), "?"},
169 {(int) '&', "ampersand", N_("Ampersand"), "&"},
170 {(int) '$', "dollar", N_("Dollar sign"), "$"},
171 {(int) '"', "quota", N_("Quotation mark"), "\""},
172 {(int) '%', "percent", N_("Percent sign"), "%"},
173 {(int) '^', "caret", N_("Caret"), "^"},
174 {(int) '~', "tilda", N_("Tilda"), "~"},
175 {(int) '`', "prime", N_("Prime"), "`"},
176 {(int) '_', "underline", N_("Underline"), "_"},
177 {(int) '_', "understrike", N_("Understrike"), "_"},
178 {(int) '|', "pipe", N_("Pipe"), "|"},
179 {(int) '(', "lparenthesis", N_("Left parenthesis"), "("},
180 {(int) ')', "rparenthesis", N_("Right parenthesis"), ")"},
181 {(int) '[', "lbracket", N_("Left bracket"), "["},
182 {(int) ']', "rbracket", N_("Right bracket"), "]"},
183 {(int) '{', "lbrace", N_("Left brace"), "{"},
184 {(int) '}', "rbrace", N_("Right brace"), "}"},
185 {(int) '\n', "enter", N_("Enter"), "Enter"},
186 {(int) '\t', "tab", N_("Tab key"), "Tab"},
187 {(int) ' ', "space", N_("Space key"), "Space"},
188 {(int) '/', "slash", N_("Slash key"), "/"},
189 {(int) '\\', "backslash", N_("Backslash key"), "\\"},
190 {(int) '#', "number", N_("Number sign #"), "#"},
191 {(int) '#', "hash", N_("Number sign #"), "#"},
192 /* TRANSLATORS: Please translate as in "at sign" (@). */
193 {(int) '@', "at", N_("At sign"), "@"},
196 {KEY_M_CTRL
, "control", N_("Ctrl"), "C"},
197 {KEY_M_CTRL
, "ctrl", N_("Ctrl"), "C"},
198 {KEY_M_ALT
, "meta", N_("Alt"), "M"},
199 {KEY_M_ALT
, "alt", N_("Alt"), "M"},
200 {KEY_M_ALT
, "ralt", N_("Alt"), "M"},
201 {KEY_M_SHIFT
, "shift", N_("Shift"), "S"},
203 {0, NULL
, NULL
, NULL
}
206 /*** file scope macro definitions ****************************************************************/
208 #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *) NULL))
209 #define DIF_TIME(t1, t2) ((t2.tv_sec - t1.tv_sec) * 1000 + (t2.tv_usec - t1.tv_usec)/1000)
211 /* The maximum sequence length (32 + null terminator) */
212 #define SEQ_BUFFER_LEN 33
214 /*** file scope type declarations ****************************************************************/
216 /* Linux console keyboard modifiers */
219 SHIFT_PRESSED
= (1 << 0),
220 ALTR_PRESSED
= (1 << 1),
221 CONTROL_PRESSED
= (1 << 2),
222 ALTL_PRESSED
= (1 << 3)
225 typedef struct key_def
227 char ch
; /* Holds the matching char code */
228 int code
; /* The code returned, valid if child == NULL */
229 struct key_def
*next
;
230 struct key_def
*child
; /* sequence continuation */
231 int action
; /* optional action to be done. Now used only
232 to mark that we are just after the first
243 /* File descriptor monitoring add/remove routines */
244 typedef struct SelectList
249 struct SelectList
*next
;
252 typedef enum KeySortType
260 typedef int (*ph_dv_f
) (void *, void *);
261 typedef int (*ph_ov_f
) (void *);
262 typedef int (*ph_pqc_f
) (unsigned short, PhCursorInfo_t
*);
265 /*** file scope variables ************************************************************************/
267 static key_define_t mc_default_keys
[] = {
268 {ESC_CHAR
, ESC_STR
, MCKEY_ESCAPE
},
269 {ESC_CHAR
, ESC_STR ESC_STR
, MCKEY_NOACTION
},
270 {0, NULL
, MCKEY_NOACTION
},
273 /* Broken terminfo and termcap databases on xterminals */
274 static key_define_t xterm_key_defines
[] = {
275 {KEY_F (1), ESC_STR
"OP", MCKEY_NOACTION
},
276 {KEY_F (2), ESC_STR
"OQ", MCKEY_NOACTION
},
277 {KEY_F (3), ESC_STR
"OR", MCKEY_NOACTION
},
278 {KEY_F (4), ESC_STR
"OS", MCKEY_NOACTION
},
279 {KEY_F (1), ESC_STR
"[11~", MCKEY_NOACTION
},
280 {KEY_F (2), ESC_STR
"[12~", MCKEY_NOACTION
},
281 {KEY_F (3), ESC_STR
"[13~", MCKEY_NOACTION
},
282 {KEY_F (4), ESC_STR
"[14~", MCKEY_NOACTION
},
283 {KEY_F (5), ESC_STR
"[15~", MCKEY_NOACTION
},
284 {KEY_F (6), ESC_STR
"[17~", MCKEY_NOACTION
},
285 {KEY_F (7), ESC_STR
"[18~", MCKEY_NOACTION
},
286 {KEY_F (8), ESC_STR
"[19~", MCKEY_NOACTION
},
287 {KEY_F (9), ESC_STR
"[20~", MCKEY_NOACTION
},
288 {KEY_F (10), ESC_STR
"[21~", MCKEY_NOACTION
},
290 /* old xterm Shift-arrows */
291 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"O2A", MCKEY_NOACTION
},
292 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"O2B", MCKEY_NOACTION
},
293 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"O2C", MCKEY_NOACTION
},
294 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"O2D", MCKEY_NOACTION
},
296 /* new xterm Shift-arrows */
297 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"[1;2A", MCKEY_NOACTION
},
298 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"[1;2B", MCKEY_NOACTION
},
299 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"[1;2C", MCKEY_NOACTION
},
300 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"[1;2D", MCKEY_NOACTION
},
302 /* more xterm keys with modifiers */
303 {KEY_M_CTRL
| KEY_PPAGE
, ESC_STR
"[5;5~", MCKEY_NOACTION
},
304 {KEY_M_CTRL
| KEY_NPAGE
, ESC_STR
"[6;5~", MCKEY_NOACTION
},
305 {KEY_M_CTRL
| KEY_IC
, ESC_STR
"[2;5~", MCKEY_NOACTION
},
306 {KEY_M_CTRL
| KEY_DC
, ESC_STR
"[3;5~", MCKEY_NOACTION
},
307 {KEY_M_CTRL
| KEY_HOME
, ESC_STR
"[1;5H", MCKEY_NOACTION
},
308 {KEY_M_CTRL
| KEY_END
, ESC_STR
"[1;5F", MCKEY_NOACTION
},
309 {KEY_M_SHIFT
| KEY_HOME
, ESC_STR
"[1;2H", MCKEY_NOACTION
},
310 {KEY_M_SHIFT
| KEY_END
, ESC_STR
"[1;2F", MCKEY_NOACTION
},
311 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"[1;5A", MCKEY_NOACTION
},
312 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[1;5B", MCKEY_NOACTION
},
313 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[1;5C", MCKEY_NOACTION
},
314 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[1;5D", MCKEY_NOACTION
},
315 {KEY_M_SHIFT
| KEY_IC
, ESC_STR
"[2;2~", MCKEY_NOACTION
},
316 {KEY_M_SHIFT
| KEY_DC
, ESC_STR
"[3;2~", MCKEY_NOACTION
},
317 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"[1;6A", MCKEY_NOACTION
},
318 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[1;6B", MCKEY_NOACTION
},
319 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[1;6C", MCKEY_NOACTION
},
320 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[1;6D", MCKEY_NOACTION
},
323 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"[[1;6A", MCKEY_NOACTION
},
324 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[[1;6B", MCKEY_NOACTION
},
325 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[[1;6C", MCKEY_NOACTION
},
326 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[[1;6D", MCKEY_NOACTION
},
328 /* putty alt-arrow keys */
329 /* removed as source esc esc esc trouble */
331 { KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "OA", MCKEY_NOACTION },
332 { KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "OB", MCKEY_NOACTION },
333 { KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "OC", MCKEY_NOACTION },
334 { KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "OD", MCKEY_NOACTION },
335 { KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[5~", MCKEY_NOACTION },
336 { KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[6~", MCKEY_NOACTION },
337 { KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1~", MCKEY_NOACTION },
338 { KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[4~", MCKEY_NOACTION },
340 { KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "[1;2A", MCKEY_NOACTION },
341 { KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "[1;2B", MCKEY_NOACTION },
342 { KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "[1;2C", MCKEY_NOACTION },
343 { KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "[1;2D", MCKEY_NOACTION },
345 { KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[[5;5~", MCKEY_NOACTION },
346 { KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[[6;5~", MCKEY_NOACTION },
347 { KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1;5H", MCKEY_NOACTION },
348 { KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[1;5F", MCKEY_NOACTION },
350 /* xterm alt-arrow keys */
351 {KEY_M_ALT
| KEY_UP
, ESC_STR
"[1;3A", MCKEY_NOACTION
},
352 {KEY_M_ALT
| KEY_DOWN
, ESC_STR
"[1;3B", MCKEY_NOACTION
},
353 {KEY_M_ALT
| KEY_RIGHT
, ESC_STR
"[1;3C", MCKEY_NOACTION
},
354 {KEY_M_ALT
| KEY_LEFT
, ESC_STR
"[1;3D", MCKEY_NOACTION
},
355 {KEY_M_ALT
| KEY_PPAGE
, ESC_STR
"[5;3~", MCKEY_NOACTION
},
356 {KEY_M_ALT
| KEY_NPAGE
, ESC_STR
"[6;3~", MCKEY_NOACTION
},
357 {KEY_M_ALT
| KEY_HOME
, ESC_STR
"[1~", MCKEY_NOACTION
},
358 {KEY_M_ALT
| KEY_END
, ESC_STR
"[4~", MCKEY_NOACTION
},
359 {KEY_M_CTRL
| KEY_M_ALT
| KEY_UP
, ESC_STR
"[1;7A", MCKEY_NOACTION
},
360 {KEY_M_CTRL
| KEY_M_ALT
| KEY_DOWN
, ESC_STR
"[1;7B", MCKEY_NOACTION
},
361 {KEY_M_CTRL
| KEY_M_ALT
| KEY_RIGHT
, ESC_STR
"[1;7C", MCKEY_NOACTION
},
362 {KEY_M_CTRL
| KEY_M_ALT
| KEY_LEFT
, ESC_STR
"[1;7D", MCKEY_NOACTION
},
363 {KEY_M_CTRL
| KEY_M_ALT
| KEY_PPAGE
, ESC_STR
"[5;7~", MCKEY_NOACTION
},
364 {KEY_M_CTRL
| KEY_M_ALT
| KEY_NPAGE
, ESC_STR
"[6;7~", MCKEY_NOACTION
},
365 {KEY_M_CTRL
| KEY_M_ALT
| KEY_HOME
, ESC_STR
"OH", MCKEY_NOACTION
},
366 {KEY_M_CTRL
| KEY_M_ALT
| KEY_END
, ESC_STR
"OF", MCKEY_NOACTION
},
368 /* rxvt keys with modifiers */
369 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"[a", MCKEY_NOACTION
},
370 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"[b", MCKEY_NOACTION
},
371 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"[c", MCKEY_NOACTION
},
372 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"[d", MCKEY_NOACTION
},
373 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"Oa", MCKEY_NOACTION
},
374 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"Ob", MCKEY_NOACTION
},
375 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"Oc", MCKEY_NOACTION
},
376 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"Od", MCKEY_NOACTION
},
377 {KEY_M_CTRL
| KEY_PPAGE
, ESC_STR
"[5^", MCKEY_NOACTION
},
378 {KEY_M_CTRL
| KEY_NPAGE
, ESC_STR
"[6^", MCKEY_NOACTION
},
379 {KEY_M_CTRL
| KEY_HOME
, ESC_STR
"[7^", MCKEY_NOACTION
},
380 {KEY_M_CTRL
| KEY_END
, ESC_STR
"[8^", MCKEY_NOACTION
},
381 {KEY_M_SHIFT
| KEY_HOME
, ESC_STR
"[7$", MCKEY_NOACTION
},
382 {KEY_M_SHIFT
| KEY_END
, ESC_STR
"[8$", MCKEY_NOACTION
},
383 {KEY_M_CTRL
| KEY_IC
, ESC_STR
"[2^", MCKEY_NOACTION
},
384 {KEY_M_CTRL
| KEY_DC
, ESC_STR
"[3^", MCKEY_NOACTION
},
385 {KEY_M_SHIFT
| KEY_DC
, ESC_STR
"[3$", MCKEY_NOACTION
},
387 /* konsole keys with modifiers */
388 {KEY_M_SHIFT
| KEY_HOME
, ESC_STR
"O2H", MCKEY_NOACTION
},
389 {KEY_M_SHIFT
| KEY_END
, ESC_STR
"O2F", MCKEY_NOACTION
},
392 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"[2A", MCKEY_NOACTION
},
393 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"[2B", MCKEY_NOACTION
},
394 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"[2C", MCKEY_NOACTION
},
395 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"[2D", MCKEY_NOACTION
},
396 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"[5A", MCKEY_NOACTION
},
397 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[5B", MCKEY_NOACTION
},
398 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[5C", MCKEY_NOACTION
},
399 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[5D", MCKEY_NOACTION
},
400 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"[6A", MCKEY_NOACTION
},
401 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[6B", MCKEY_NOACTION
},
402 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[6C", MCKEY_NOACTION
},
403 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[6D", MCKEY_NOACTION
},
405 /* gnome-terminal - application mode */
406 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"O5A", MCKEY_NOACTION
},
407 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"O5B", MCKEY_NOACTION
},
408 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"O5C", MCKEY_NOACTION
},
409 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"O5D", MCKEY_NOACTION
},
410 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"O6A", MCKEY_NOACTION
},
411 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"O6B", MCKEY_NOACTION
},
412 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"O6C", MCKEY_NOACTION
},
413 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"O6D", MCKEY_NOACTION
},
416 {KEY_M_SHIFT
| KEY_PPAGE
, ESC_STR
"[5;2~", MCKEY_NOACTION
},
417 {KEY_M_SHIFT
| KEY_NPAGE
, ESC_STR
"[6;2~", MCKEY_NOACTION
},
420 {KEY_M_SHIFT
| KEY_PPAGE
, ESC_STR
"[[5;53~", MCKEY_NOACTION
},
421 {KEY_M_SHIFT
| KEY_NPAGE
, ESC_STR
"[[6;53~", MCKEY_NOACTION
},
424 {KEY_IC
, ESC_STR
"Op", MCKEY_NOACTION
},
425 {KEY_DC
, ESC_STR
"On", MCKEY_NOACTION
},
426 {'/', ESC_STR
"Oo", MCKEY_NOACTION
},
427 {'\n', ESC_STR
"OM", MCKEY_NOACTION
},
429 {0, NULL
, MCKEY_NOACTION
},
432 /* qansi-m terminals have a much more key combinatios,
433 which are undefined in termcap/terminfo */
434 static key_define_t qansi_key_defines
[] = {
435 /* qansi-m terminal */
436 {KEY_M_CTRL
| KEY_NPAGE
, ESC_STR
"[u", MCKEY_NOACTION
}, /* Ctrl-PgDown */
437 {KEY_M_CTRL
| KEY_PPAGE
, ESC_STR
"[v", MCKEY_NOACTION
}, /* Ctrl-PgUp */
438 {KEY_M_CTRL
| KEY_HOME
, ESC_STR
"[h", MCKEY_NOACTION
}, /* Ctrl-Home */
439 {KEY_M_CTRL
| KEY_END
, ESC_STR
"[y", MCKEY_NOACTION
}, /* Ctrl-End */
440 {KEY_M_CTRL
| KEY_IC
, ESC_STR
"[`", MCKEY_NOACTION
}, /* Ctrl-Insert */
441 {KEY_M_CTRL
| KEY_DC
, ESC_STR
"[p", MCKEY_NOACTION
}, /* Ctrl-Delete */
442 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[d", MCKEY_NOACTION
}, /* Ctrl-Left */
443 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[c", MCKEY_NOACTION
}, /* Ctrl-Right */
444 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[b", MCKEY_NOACTION
}, /* Ctrl-Down */
445 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"[a", MCKEY_NOACTION
}, /* Ctrl-Up */
446 {KEY_M_CTRL
| KEY_KP_ADD
, ESC_STR
"[s", MCKEY_NOACTION
}, /* Ctrl-Gr-Plus */
447 {KEY_M_CTRL
| KEY_KP_SUBTRACT
, ESC_STR
"[t", MCKEY_NOACTION
}, /* Ctrl-Gr-Minus */
448 {KEY_M_CTRL
| '\t', ESC_STR
"[z", MCKEY_NOACTION
}, /* Ctrl-Tab */
449 {KEY_M_SHIFT
| '\t', ESC_STR
"[Z", MCKEY_NOACTION
}, /* Shift-Tab */
450 {KEY_M_CTRL
| KEY_F (1), ESC_STR
"[1~", MCKEY_NOACTION
}, /* Ctrl-F1 */
451 {KEY_M_CTRL
| KEY_F (2), ESC_STR
"[2~", MCKEY_NOACTION
}, /* Ctrl-F2 */
452 {KEY_M_CTRL
| KEY_F (3), ESC_STR
"[3~", MCKEY_NOACTION
}, /* Ctrl-F3 */
453 {KEY_M_CTRL
| KEY_F (4), ESC_STR
"[4~", MCKEY_NOACTION
}, /* Ctrl-F4 */
454 {KEY_M_CTRL
| KEY_F (5), ESC_STR
"[5~", MCKEY_NOACTION
}, /* Ctrl-F5 */
455 {KEY_M_CTRL
| KEY_F (6), ESC_STR
"[6~", MCKEY_NOACTION
}, /* Ctrl-F6 */
456 {KEY_M_CTRL
| KEY_F (7), ESC_STR
"[7~", MCKEY_NOACTION
}, /* Ctrl-F7 */
457 {KEY_M_CTRL
| KEY_F (8), ESC_STR
"[8~", MCKEY_NOACTION
}, /* Ctrl-F8 */
458 {KEY_M_CTRL
| KEY_F (9), ESC_STR
"[9~", MCKEY_NOACTION
}, /* Ctrl-F9 */
459 {KEY_M_CTRL
| KEY_F (10), ESC_STR
"[10~", MCKEY_NOACTION
}, /* Ctrl-F10 */
460 {KEY_M_CTRL
| KEY_F (11), ESC_STR
"[11~", MCKEY_NOACTION
}, /* Ctrl-F11 */
461 {KEY_M_CTRL
| KEY_F (12), ESC_STR
"[12~", MCKEY_NOACTION
}, /* Ctrl-F12 */
462 {KEY_M_ALT
| KEY_F (1), ESC_STR
"[17~", MCKEY_NOACTION
}, /* Alt-F1 */
463 {KEY_M_ALT
| KEY_F (2), ESC_STR
"[18~", MCKEY_NOACTION
}, /* Alt-F2 */
464 {KEY_M_ALT
| KEY_F (3), ESC_STR
"[19~", MCKEY_NOACTION
}, /* Alt-F3 */
465 {KEY_M_ALT
| KEY_F (4), ESC_STR
"[20~", MCKEY_NOACTION
}, /* Alt-F4 */
466 {KEY_M_ALT
| KEY_F (5), ESC_STR
"[21~", MCKEY_NOACTION
}, /* Alt-F5 */
467 {KEY_M_ALT
| KEY_F (6), ESC_STR
"[22~", MCKEY_NOACTION
}, /* Alt-F6 */
468 {KEY_M_ALT
| KEY_F (7), ESC_STR
"[23~", MCKEY_NOACTION
}, /* Alt-F7 */
469 {KEY_M_ALT
| KEY_F (8), ESC_STR
"[24~", MCKEY_NOACTION
}, /* Alt-F8 */
470 {KEY_M_ALT
| KEY_F (9), ESC_STR
"[25~", MCKEY_NOACTION
}, /* Alt-F9 */
471 {KEY_M_ALT
| KEY_F (10), ESC_STR
"[26~", MCKEY_NOACTION
}, /* Alt-F10 */
472 {KEY_M_ALT
| KEY_F (11), ESC_STR
"[27~", MCKEY_NOACTION
}, /* Alt-F11 */
473 {KEY_M_ALT
| KEY_F (12), ESC_STR
"[28~", MCKEY_NOACTION
}, /* Alt-F12 */
474 {KEY_M_ALT
| 'a', ESC_STR
"Na", MCKEY_NOACTION
}, /* Alt-a */
475 {KEY_M_ALT
| 'b', ESC_STR
"Nb", MCKEY_NOACTION
}, /* Alt-b */
476 {KEY_M_ALT
| 'c', ESC_STR
"Nc", MCKEY_NOACTION
}, /* Alt-c */
477 {KEY_M_ALT
| 'd', ESC_STR
"Nd", MCKEY_NOACTION
}, /* Alt-d */
478 {KEY_M_ALT
| 'e', ESC_STR
"Ne", MCKEY_NOACTION
}, /* Alt-e */
479 {KEY_M_ALT
| 'f', ESC_STR
"Nf", MCKEY_NOACTION
}, /* Alt-f */
480 {KEY_M_ALT
| 'g', ESC_STR
"Ng", MCKEY_NOACTION
}, /* Alt-g */
481 {KEY_M_ALT
| 'h', ESC_STR
"Nh", MCKEY_NOACTION
}, /* Alt-h */
482 {KEY_M_ALT
| 'i', ESC_STR
"Ni", MCKEY_NOACTION
}, /* Alt-i */
483 {KEY_M_ALT
| 'j', ESC_STR
"Nj", MCKEY_NOACTION
}, /* Alt-j */
484 {KEY_M_ALT
| 'k', ESC_STR
"Nk", MCKEY_NOACTION
}, /* Alt-k */
485 {KEY_M_ALT
| 'l', ESC_STR
"Nl", MCKEY_NOACTION
}, /* Alt-l */
486 {KEY_M_ALT
| 'm', ESC_STR
"Nm", MCKEY_NOACTION
}, /* Alt-m */
487 {KEY_M_ALT
| 'n', ESC_STR
"Nn", MCKEY_NOACTION
}, /* Alt-n */
488 {KEY_M_ALT
| 'o', ESC_STR
"No", MCKEY_NOACTION
}, /* Alt-o */
489 {KEY_M_ALT
| 'p', ESC_STR
"Np", MCKEY_NOACTION
}, /* Alt-p */
490 {KEY_M_ALT
| 'q', ESC_STR
"Nq", MCKEY_NOACTION
}, /* Alt-q */
491 {KEY_M_ALT
| 'r', ESC_STR
"Nr", MCKEY_NOACTION
}, /* Alt-r */
492 {KEY_M_ALT
| 's', ESC_STR
"Ns", MCKEY_NOACTION
}, /* Alt-s */
493 {KEY_M_ALT
| 't', ESC_STR
"Nt", MCKEY_NOACTION
}, /* Alt-t */
494 {KEY_M_ALT
| 'u', ESC_STR
"Nu", MCKEY_NOACTION
}, /* Alt-u */
495 {KEY_M_ALT
| 'v', ESC_STR
"Nv", MCKEY_NOACTION
}, /* Alt-v */
496 {KEY_M_ALT
| 'w', ESC_STR
"Nw", MCKEY_NOACTION
}, /* Alt-w */
497 {KEY_M_ALT
| 'x', ESC_STR
"Nx", MCKEY_NOACTION
}, /* Alt-x */
498 {KEY_M_ALT
| 'y', ESC_STR
"Ny", MCKEY_NOACTION
}, /* Alt-y */
499 {KEY_M_ALT
| 'z', ESC_STR
"Nz", MCKEY_NOACTION
}, /* Alt-z */
500 {KEY_KP_SUBTRACT
, ESC_STR
"[S", MCKEY_NOACTION
}, /* Gr-Minus */
501 {KEY_KP_ADD
, ESC_STR
"[T", MCKEY_NOACTION
}, /* Gr-Plus */
502 {0, NULL
, MCKEY_NOACTION
},
505 /* timeout for old_esc_mode in usec */
506 int old_esc_mode_timeout
= 1000000; /* settable via env */
508 /* This holds all the key definitions */
509 static key_def
*keys
= NULL
;
512 static int disabled_channels
= 0; /* Disable channels checking */
514 static SelectList
*select_list
= NULL
;
516 static int seq_buffer
[SEQ_BUFFER_LEN
];
517 static int *seq_append
= NULL
;
519 static int *pending_keys
= NULL
;
523 ph_ov_f ph_input_group
;
524 ph_pqc_f ph_query_cursor
;
527 #ifdef HAVE_TEXTMODE_X11_SUPPORT
528 static Display
*x11_display
;
529 static Window x11_window
;
530 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
532 static KeySortType has_been_sorted
= KEY_NOSORT
;
535 static const size_t key_conv_tab_size
= G_N_ELEMENTS (key_name_conv_tab
) - 1;
538 static const key_code_name_t
*key_conv_tab_sorted
[G_N_ELEMENTS (key_name_conv_tab
) - 1];
540 /*** file scope functions ************************************************************************/
541 /* --------------------------------------------------------------------------------------------- */
544 add_selects (fd_set
* select_set
)
548 if (disabled_channels
== 0)
552 for (p
= select_list
; p
!= NULL
; p
= p
->next
)
554 FD_SET (p
->fd
, select_set
);
563 /* --------------------------------------------------------------------------------------------- */
566 check_selects (fd_set
* select_set
)
568 if (disabled_channels
== 0)
577 for (p
= select_list
; p
; p
= p
->next
)
578 if (FD_ISSET (p
->fd
, select_set
))
580 FD_CLR (p
->fd
, select_set
);
581 (*p
->callback
) (p
->fd
, p
->info
);
590 /* --------------------------------------------------------------------------------------------- */
591 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
594 try_channels (int set_timeout
)
596 struct timeval time_out
;
597 static fd_set select_set
;
598 struct timeval
*timeptr
;
604 FD_ZERO (&select_set
);
605 FD_SET (input_fd
, &select_set
); /* Add stdin */
606 maxfdp
= max (add_selects (&select_set
), input_fd
);
612 time_out
.tv_usec
= 100000;
616 v
= select (maxfdp
+ 1, &select_set
, NULL
, NULL
, timeptr
);
619 check_selects (&select_set
);
620 if (FD_ISSET (input_fd
, &select_set
))
626 /* --------------------------------------------------------------------------------------------- */
629 create_sequence (const char *seq
, int code
, int action
)
631 key_def
*base
, *p
, *attach
;
633 for (base
= attach
= NULL
; *seq
; seq
++)
635 p
= g_new (key_def
, 1);
643 p
->child
= p
->next
= NULL
;
647 p
->action
= MCKEY_NOACTION
;
653 /* --------------------------------------------------------------------------------------------- */
656 define_sequences (const key_define_t
* kd
)
660 for (i
= 0; kd
[i
].code
!= 0; i
++)
661 define_sequence (kd
[i
].code
, kd
[i
].seq
, kd
[i
].action
);
664 /* --------------------------------------------------------------------------------------------- */
669 #ifdef HAVE_TEXTMODE_X11_SUPPORT
670 if (getenv ("DISPLAY") != NULL
)
672 x11_display
= mc_XOpenDisplay (0);
674 if (x11_display
!= NULL
)
675 x11_window
= DefaultRootWindow (x11_display
);
677 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
680 /* --------------------------------------------------------------------------------------------- */
681 /* Workaround for System V Curses vt100 bug */
684 getch_with_delay (void)
688 /* This routine could be used on systems without mouse support,
689 so we need to do the select check :-( */
692 if (pending_keys
== NULL
)
695 /* Try to get a character */
696 c
= get_key_code (0);
699 /* Failed -> wait 0.1 secs and try again */
702 /* Success -> return the character */
706 /* --------------------------------------------------------------------------------------------- */
709 xmouse_get_event (Gpm_Event
* ev
)
712 static struct timeval tv1
= { 0, 0 }; /* Force first click as single */
713 static struct timeval tv2
;
714 static int clicks
= 0;
715 static int last_btn
= 0;
717 /* Decode Xterm mouse information to a GPM style event */
719 /* Variable btn has following meaning: */
720 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
721 btn
= tty_lowlevel_getch () - 32;
723 /* There seems to be no way of knowing which button was released */
724 /* So we assume all the buttons were released */
730 if ((last_btn
& (GPM_B_UP
| GPM_B_DOWN
)) != 0)
732 /* FIXME: DIRTY HACK */
733 /* don't generate GPM_UP after mouse wheel */
734 /* need for menu event handling */
741 ev
->type
= GPM_UP
| (GPM_SINGLE
<< clicks
);
750 /* Bogus event, maybe mouse wheel */
756 if (btn
>= 32 && btn
<= 34)
765 if (tv1
.tv_sec
&& (DIF_TIME (tv1
, tv2
) < double_click_speed
))
776 ev
->buttons
= GPM_B_LEFT
;
779 ev
->buttons
= GPM_B_MIDDLE
;
782 ev
->buttons
= GPM_B_RIGHT
;
785 ev
->buttons
= GPM_B_UP
;
789 ev
->buttons
= GPM_B_DOWN
;
798 last_btn
= ev
->buttons
;
800 /* Coordinates are 33-based */
801 /* Transform them to 1-based */
802 ev
->x
= tty_lowlevel_getch () - 32;
803 ev
->y
= tty_lowlevel_getch () - 32;
806 /* --------------------------------------------------------------------------------------------- */
808 * Get modifier state (shift, alt, ctrl) for the last key pressed.
809 * We are assuming that the state didn't change since the key press.
810 * This is only correct if get_modifier() is called very fast after
811 * the input was received, so that the user didn't release the
820 int mod_status
, shift_ext_status
;
821 static int in_photon
= 0;
822 static int ph_ig
= 0;
823 PhCursorInfo_t cursor_info
;
824 #endif /* __QNXNTO__ */
826 #ifdef HAVE_TEXTMODE_X11_SUPPORT
834 mc_XQueryPointer (x11_display
, x11_window
, &root
, &child
, &root_x
,
835 &root_y
, &win_x
, &win_y
, &mask
);
837 if (mask
& ShiftMask
)
838 result
|= KEY_M_SHIFT
;
839 if (mask
& ControlMask
)
840 result
|= KEY_M_CTRL
;
843 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
848 /* First time here, let's load Photon library and attach
851 if (getenv ("PHOTON2_PATH") != NULL
)
853 /* QNX 6.x has no support for RTLD_LAZY */
854 void *ph_handle
= dlopen ("/usr/lib/libph.so", RTLD_NOW
);
855 if (ph_handle
!= NULL
)
857 ph_attach
= (ph_dv_f
) dlsym (ph_handle
, "PhAttach");
858 ph_input_group
= (ph_ov_f
) dlsym (ph_handle
, "PhInputGroup");
859 ph_query_cursor
= (ph_pqc_f
) dlsym (ph_handle
, "PhQueryCursor");
860 if ((ph_attach
!= NULL
) && (ph_input_group
!= NULL
) && (ph_query_cursor
!= NULL
))
862 if ((*ph_attach
) (0, 0))
864 ph_ig
= (*ph_input_group
) (0);
871 /* We do not have Photon running. Assume we are in text
875 if (devctl (fileno (stdin
), DCMD_CHR_LINESTATUS
, &mod_status
, sizeof (int), NULL
) == -1)
877 shift_ext_status
= mod_status
& 0xffffff00UL
;
879 if (mod_status
& _LINESTATUS_CON_ALT
)
881 if (mod_status
& _LINESTATUS_CON_CTRL
)
882 result
|= KEY_M_CTRL
;
883 if ((mod_status
& _LINESTATUS_CON_SHIFT
) || (shift_ext_status
& 0x00000800UL
))
884 result
|= KEY_M_SHIFT
;
888 (*ph_query_cursor
) (ph_ig
, &cursor_info
);
889 if (cursor_info
.key_mods
& 0x04)
891 if (cursor_info
.key_mods
& 0x02)
892 result
|= KEY_M_CTRL
;
893 if (cursor_info
.key_mods
& 0x01)
894 result
|= KEY_M_SHIFT
;
896 #endif /* __QNXNTO__ */
898 #if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX)
900 unsigned char modifiers
= 6;
902 if (ioctl (0, TIOCLINUX
, &modifiers
) < 0)
905 /* Translate Linux modifiers into mc modifiers */
906 if (modifiers
& SHIFT_PRESSED
)
907 result
|= KEY_M_SHIFT
;
908 if (modifiers
& (ALTL_PRESSED
| ALTR_PRESSED
))
910 if (modifiers
& CONTROL_PRESSED
)
911 result
|= KEY_M_CTRL
;
913 #endif /* !__linux__ */
917 /* --------------------------------------------------------------------------------------------- */
922 gboolean ret
= FALSE
;
924 if (seq_append
== NULL
)
925 seq_append
= seq_buffer
;
927 if (seq_append
!= &(seq_buffer
[SEQ_BUFFER_LEN
- 2]))
937 /* --------------------------------------------------------------------------------------------- */
938 /* Apply corrections for the keycode generated in get_key_code() */
941 correct_key_code (int code
)
943 unsigned int c
= code
& ~KEY_M_MASK
; /* code without modifier */
944 unsigned int mod
= code
& KEY_M_MASK
; /* modifier */
946 unsigned int qmod
; /* bunch of the QNX console
947 modifiers needs unchanged */
948 #endif /* __QNXNTO__ */
951 * Add key modifiers directly from X11 or OS.
952 * Ordinary characters only get modifiers from sequences.
954 if (c
< 32 || c
>= 256)
956 mod
|= get_modifier ();
959 /* This is needed if the newline is reported as carriage return */
963 /* This is reported to be useful on AIX */
964 if (c
== KEY_SCANCEL
)
967 /* Convert Shift+Tab and Ctrl+Tab to Back Tab */
968 if ((c
== '\t') && (mod
& (KEY_M_SHIFT
| KEY_M_CTRL
)))
974 /* F0 is the same as F10 for out purposes */
979 * We are not interested if Ctrl was pressed when entering control
980 * characters, so assume that it was. When checking for such keys,
981 * XCTRL macro should be used. In some cases, we are interested,
982 * e.g. to distinguish Ctrl-Enter from Enter.
986 /* Special case for backspase ('\b' < 32) */
990 else if (c
< 32 && c
!= ESC_CHAR
&& c
!= '\t' && c
!= '\n')
996 qmod
= get_modifier ();
998 if ((c
== 127) && (mod
== 0))
999 { /* Add Ctrl/Alt/Shift-BackSpace */
1000 mod
|= get_modifier ();
1004 if ((c
== '0') && (mod
== 0))
1005 { /* Add Shift-Insert on key pad */
1006 if ((qmod
& KEY_M_SHIFT
) == KEY_M_SHIFT
)
1013 if ((c
== '.') && (mod
== 0))
1014 { /* Add Shift-Del on key pad */
1015 if ((qmod
& KEY_M_SHIFT
) == KEY_M_SHIFT
)
1021 #endif /* __QNXNTO__ */
1023 /* Unrecognized 0177 is delete (preserve Ctrl) */
1030 /* Unrecognized Ctrl-d is delete */
1031 if (c
== (31 & 'd'))
1037 /* Unrecognized Ctrl-h is backspace */
1038 if (c
== (31 & 'h'))
1045 /* Shift+BackSpace is backspace */
1046 if (c
== KEY_BACKSPACE
&& (mod
& KEY_M_SHIFT
))
1048 mod
&= ~KEY_M_SHIFT
;
1051 /* Convert Shift+Fn to F(n+10) */
1052 if (c
>= KEY_F (1) && c
<= KEY_F (10) && (mod
& KEY_M_SHIFT
))
1057 /* Remove Shift information from function keys */
1058 if (c
>= KEY_F (1) && c
<= KEY_F (20))
1060 mod
&= ~KEY_M_SHIFT
;
1063 if (!mc_global
.tty
.alternate_plus_minus
)
1069 case KEY_KP_SUBTRACT
:
1072 case KEY_KP_MULTIPLY
:
1080 /* --------------------------------------------------------------------------------------------- */
1083 xgetch_second (void)
1087 struct timeval time_out
;
1089 time_out
.tv_sec
= old_esc_mode_timeout
/ 1000000;
1090 time_out
.tv_usec
= old_esc_mode_timeout
% 1000000;
1092 FD_ZERO (&Read_FD_Set
);
1093 FD_SET (input_fd
, &Read_FD_Set
);
1094 select (input_fd
+ 1, &Read_FD_Set
, NULL
, NULL
, &time_out
);
1095 c
= tty_lowlevel_getch ();
1096 tty_nodelay (FALSE
);
1100 /* --------------------------------------------------------------------------------------------- */
1103 learn_store_key (char *buffer
, char **p
, int c
)
1105 if (*p
- buffer
> 253)
1115 *(*p
)++ = c
+ 'a' - 1;
1126 /* --------------------------------------------------------------------------------------------- */
1129 k_dispose (key_def
* k
)
1133 k_dispose (k
->child
);
1134 k_dispose (k
->next
);
1139 /* --------------------------------------------------------------------------------------------- */
1142 s_dispose (SelectList
* sel
)
1146 s_dispose (sel
->next
);
1151 /* --------------------------------------------------------------------------------------------- */
1154 key_code_comparator_by_name (const void *p1
, const void *p2
)
1156 const key_code_name_t
*n1
= *(const key_code_name_t
**) p1
;
1157 const key_code_name_t
*n2
= *(const key_code_name_t
**) p2
;
1159 return str_casecmp (n1
->name
, n2
->name
);
1162 /* --------------------------------------------------------------------------------------------- */
1165 key_code_comparator_by_code (const void *p1
, const void *p2
)
1167 const key_code_name_t
*n1
= *(const key_code_name_t
**) p1
;
1168 const key_code_name_t
*n2
= *(const key_code_name_t
**) p2
;
1170 return n1
->code
- n2
->code
;
1173 /* --------------------------------------------------------------------------------------------- */
1176 sort_key_conv_tab (enum KeySortType type_sort
)
1178 if (has_been_sorted
!= type_sort
)
1181 for (i
= 0; i
< key_conv_tab_size
; i
++)
1182 key_conv_tab_sorted
[i
] = &key_name_conv_tab
[i
];
1184 if (type_sort
== KEY_SORTBYNAME
)
1186 qsort (key_conv_tab_sorted
, key_conv_tab_size
, sizeof (key_conv_tab_sorted
[0]),
1187 &key_code_comparator_by_name
);
1189 else if (type_sort
== KEY_SORTBYCODE
)
1191 qsort (key_conv_tab_sorted
, key_conv_tab_size
, sizeof (key_conv_tab_sorted
[0]),
1192 &key_code_comparator_by_code
);
1194 has_been_sorted
= type_sort
;
1198 /* --------------------------------------------------------------------------------------------- */
1201 lookup_keyname (const char *name
, int *idx
)
1203 if (name
[0] != '\0')
1205 const key_code_name_t key
= { 0, name
, NULL
, NULL
};
1206 const key_code_name_t
*keyp
= &key
;
1207 key_code_name_t
**res
;
1209 if (name
[1] == '\0')
1212 return (int) name
[0];
1215 sort_key_conv_tab (KEY_SORTBYNAME
);
1217 res
= bsearch (&keyp
, key_conv_tab_sorted
, key_conv_tab_size
,
1218 sizeof (key_conv_tab_sorted
[0]), key_code_comparator_by_name
);
1222 *idx
= (int) (res
- (key_code_name_t
**) key_conv_tab_sorted
);
1223 return (*res
)->code
;
1231 /* --------------------------------------------------------------------------------------------- */
1234 lookup_keycode (const long code
, int *idx
)
1238 const key_code_name_t key
= { code
, NULL
, NULL
, NULL
};
1239 const key_code_name_t
*keyp
= &key
;
1240 key_code_name_t
**res
;
1242 sort_key_conv_tab (KEY_SORTBYCODE
);
1244 res
= bsearch (&keyp
, key_conv_tab_sorted
, key_conv_tab_size
,
1245 sizeof (key_conv_tab_sorted
[0]), key_code_comparator_by_code
);
1249 *idx
= (int) (res
- (key_code_name_t
**) key_conv_tab_sorted
);
1258 /* --------------------------------------------------------------------------------------------- */
1259 /*** public functions ****************************************************************************/
1260 /* --------------------------------------------------------------------------------------------- */
1261 /* This has to be called before init_slang or whatever routine
1262 calls any define_sequence */
1267 const char *term
= getenv ("TERM");
1269 /* This has to be the first define_sequence */
1270 /* So, we can assume that the first keys member has ESC */
1271 define_sequences (mc_default_keys
);
1273 /* Terminfo on irix does not have some keys */
1274 if (mc_global
.tty
.xterm_flag
1276 && (strncmp (term
, "iris-ansi", 9) == 0
1277 || strncmp (term
, "xterm", 5) == 0
1278 || strncmp (term
, "rxvt", 4) == 0 || strcmp (term
, "screen") == 0)))
1279 define_sequences (xterm_key_defines
);
1281 /* load some additional keys (e.g. direct Alt-? support) */
1282 load_xtra_key_defines ();
1285 if ((term
!= NULL
) && (strncmp (term
, "qnx", 3) == 0))
1287 /* Modify the default value of use_8th_bit_as_meta: we would
1288 * like to provide a working mc for a newbie who knows nothing
1289 * about [Options|Display bits|Full 8 bits input]...
1291 * Don't use 'meta'-bit, when we are dealing with a
1292 * 'qnx*'-type terminal: clear the default value!
1293 * These terminal types use 0xFF as an escape character,
1294 * so use_8th_bit_as_meta==1 must not be enabled!
1296 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
1297 * is not used now (doesn't even depend on use_8th_bit_as_meta
1298 * as in mc-3.1.2)...GREAT!...no additional code is required!]
1300 use_8th_bit_as_meta
= 0;
1302 #endif /* __QNX__ */
1306 /* Load the qansi-m key definitions
1307 if we are running under the qansi-m terminal */
1308 if (term
!= NULL
&& (strncmp (term
, "qansi-m", 7) == 0))
1309 define_sequences (qansi_key_defines
);
1312 /* --------------------------------------------------------------------------------------------- */
1314 * This has to be called after SLang_init_tty/slint_init
1318 init_key_input_fd (void)
1321 input_fd
= SLang_TT_Read_FD
;
1325 /* --------------------------------------------------------------------------------------------- */
1331 s_dispose (select_list
);
1333 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1335 mc_XCloseDisplay (x11_display
);
1339 /* --------------------------------------------------------------------------------------------- */
1342 add_select_channel (int fd
, select_fn callback
, void *info
)
1346 new = g_new (SelectList
, 1);
1348 new->callback
= callback
;
1350 new->next
= select_list
;
1354 /* --------------------------------------------------------------------------------------------- */
1357 delete_select_channel (int fd
)
1359 SelectList
*p
= select_list
;
1360 SelectList
*p_prev
= NULL
;
1369 p_prev
->next
= p_next
;
1371 select_list
= p_next
;
1383 /* --------------------------------------------------------------------------------------------- */
1388 if (disabled_channels
== 0)
1389 fputs ("Error: channels_up called with disabled_channels = 0\n", stderr
);
1390 disabled_channels
--;
1393 /* --------------------------------------------------------------------------------------------- */
1396 channels_down (void)
1398 disabled_channels
++;
1401 /* --------------------------------------------------------------------------------------------- */
1403 * Return the code associated with the symbolic name keyname
1407 lookup_key (const char *name
, char **label
)
1409 char **lc_keys
, **p
;
1421 name
= g_strstrip (g_strdup (name
));
1422 p
= lc_keys
= g_strsplit_set (name
, "-+ ", -1);
1423 g_free ((char *) name
);
1425 while ((p
!= NULL
) && (*p
!= NULL
))
1427 if ((*p
)[0] != '\0')
1431 key
= lookup_keyname (g_strstrip (*p
), &idx
);
1433 if (key
== KEY_M_ALT
)
1435 else if (key
== KEY_M_CTRL
)
1437 else if (key
== KEY_M_SHIFT
)
1450 g_strfreev (lc_keys
);
1461 s
= g_string_new ("");
1465 g_string_append (s
, key_conv_tab_sorted
[use_meta
]->shortcut
);
1466 g_string_append_c (s
, '-');
1470 g_string_append (s
, key_conv_tab_sorted
[use_ctrl
]->shortcut
);
1471 g_string_append_c (s
, '-');
1473 if (use_shift
!= -1)
1476 g_string_append_c (s
, (gchar
) g_ascii_toupper ((gchar
) k
));
1479 g_string_append (s
, key_conv_tab_sorted
[use_shift
]->shortcut
);
1480 g_string_append_c (s
, '-');
1481 g_string_append (s
, key_conv_tab_sorted
[lc_index
]->shortcut
);
1486 if ((k
>= 'A') || (lc_index
< 0) || (key_conv_tab_sorted
[lc_index
]->shortcut
== NULL
))
1487 g_string_append_c (s
, (gchar
) g_ascii_tolower ((gchar
) k
));
1489 g_string_append (s
, key_conv_tab_sorted
[lc_index
]->shortcut
);
1491 else if ((lc_index
!= -1) && (key_conv_tab_sorted
[lc_index
]->shortcut
!= NULL
))
1492 g_string_append (s
, key_conv_tab_sorted
[lc_index
]->shortcut
);
1494 g_string_append_c (s
, (gchar
) g_ascii_tolower ((gchar
) key
));
1496 *label
= g_string_free (s
, FALSE
);
1499 if (use_shift
!= -1)
1501 if (k
< 127 && k
> 31)
1502 k
= g_ascii_toupper ((gchar
) k
);
1521 /* --------------------------------------------------------------------------------------------- */
1524 lookup_key_by_code (const int keycode
)
1526 /* code without modifier */
1527 unsigned int k
= keycode
& ~KEY_M_MASK
;
1529 unsigned int mod
= keycode
& KEY_M_MASK
;
1539 s
= g_string_sized_new (8);
1541 if (lookup_keycode (k
, &key_idx
) || (k
> 0 && k
< 256))
1543 if (mod
& KEY_M_ALT
)
1545 if (lookup_keycode (KEY_M_ALT
, &idx
))
1548 g_string_append (s
, key_conv_tab_sorted
[use_meta
]->name
);
1549 g_string_append_c (s
, '-');
1552 if (mod
& KEY_M_CTRL
)
1554 /* non printeble chars like a CTRL-[A..Z] */
1558 if (lookup_keycode (KEY_M_CTRL
, &idx
))
1561 g_string_append (s
, key_conv_tab_sorted
[use_ctrl
]->name
);
1562 g_string_append_c (s
, '-');
1565 if (mod
& KEY_M_SHIFT
)
1567 if (lookup_keycode (KEY_M_ALT
, &idx
))
1571 g_string_append_c (s
, (gchar
) g_ascii_toupper ((gchar
) k
));
1574 g_string_append (s
, key_conv_tab_sorted
[use_shift
]->name
);
1575 g_string_append_c (s
, '-');
1576 g_string_append (s
, key_conv_tab_sorted
[key_idx
]->name
);
1582 if ((k
>= 'A') || (key_idx
< 0) || (key_conv_tab_sorted
[key_idx
]->name
== NULL
))
1583 g_string_append_c (s
, (gchar
) k
);
1585 g_string_append (s
, key_conv_tab_sorted
[key_idx
]->name
);
1587 else if ((key_idx
!= -1) && (key_conv_tab_sorted
[key_idx
]->name
!= NULL
))
1588 g_string_append (s
, key_conv_tab_sorted
[key_idx
]->name
);
1590 g_string_append_c (s
, (gchar
) keycode
);
1593 return g_string_free (s
, s
->len
== 0);
1596 /* --------------------------------------------------------------------------------------------- */
1598 * Return TRUE on success, FALSE on error.
1599 * An error happens if SEQ is a beginning of an existing longer sequence.
1603 define_sequence (int code
, const char *seq
, int action
)
1607 if (strlen (seq
) > SEQ_BUFFER_LEN
- 1)
1610 for (base
= keys
; (base
!= NULL
) && (*seq
!= '\0');)
1611 if (*seq
== base
->ch
)
1613 if (base
->child
== 0)
1615 if (*(seq
+ 1) != '\0')
1616 base
->child
= create_sequence (seq
+ 1, code
, action
);
1619 /* The sequence matches an existing one. */
1621 base
->action
= action
;
1635 base
->next
= create_sequence (seq
, code
, action
);
1642 /* Attempt to redefine a sequence with a shorter sequence. */
1646 keys
= create_sequence (seq
, code
, action
);
1650 /* --------------------------------------------------------------------------------------------- */
1652 * Check if we are idle, i.e. there are no pending keyboard or mouse
1653 * events. Return 1 is idle, 0 is there are pending events.
1660 struct timeval time_out
;
1662 FD_ZERO (&select_set
);
1663 FD_SET (input_fd
, &select_set
);
1666 if (mouse_enabled
&& (use_mouse_p
== MOUSE_GPM
) && (gpm_fd
> 0))
1668 FD_SET (gpm_fd
, &select_set
);
1669 maxfdp
= max (maxfdp
, gpm_fd
);
1672 time_out
.tv_sec
= 0;
1673 time_out
.tv_usec
= 0;
1674 return (select (maxfdp
+ 1, &select_set
, 0, 0, &time_out
) <= 0);
1677 /* --------------------------------------------------------------------------------------------- */
1680 get_key_code (int no_delay
)
1683 static key_def
*this = NULL
, *parent
;
1684 static struct timeval esctime
= { -1, -1 };
1685 static int lastnodelay
= -1;
1687 if (no_delay
!= lastnodelay
)
1690 lastnodelay
= no_delay
;
1694 if (pending_keys
!= NULL
)
1696 int d
= *pending_keys
++;
1698 if (*pending_keys
== 0)
1700 pending_keys
= NULL
;
1703 if ((d
== ESC_CHAR
) && (pending_keys
!= NULL
))
1705 d
= ALT (*pending_keys
++);
1708 if ((d
> 127 && d
< 256) && use_8th_bit_as_meta
)
1711 return correct_key_code (d
);
1718 c
= tty_lowlevel_getch ();
1719 #if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE)
1720 if (c
== KEY_RESIZE
)
1721 goto nodelay_try_again
;
1725 tty_nodelay (FALSE
);
1728 if (this != NULL
&& parent
!= NULL
&& parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
)
1730 struct timeval current
, time_out
;
1732 if (esctime
.tv_sec
== -1)
1735 time_out
.tv_sec
= old_esc_mode_timeout
/ 1000000 + esctime
.tv_sec
;
1736 time_out
.tv_usec
= old_esc_mode_timeout
% 1000000 + esctime
.tv_usec
;
1737 if (time_out
.tv_usec
> 1000000)
1739 time_out
.tv_usec
-= 1000000;
1742 if (current
.tv_sec
< time_out
.tv_sec
)
1744 if (current
.tv_sec
== time_out
.tv_sec
&& current
.tv_usec
< time_out
.tv_usec
)
1747 pending_keys
= seq_append
= NULL
;
1755 /* Maybe we got an incomplete match.
1756 This we do only in delay mode, since otherwise
1757 tty_lowlevel_getch can return -1 at any time. */
1758 if (seq_append
!= NULL
)
1760 pending_keys
= seq_buffer
;
1767 /* Search the key on the root */
1768 if (!no_delay
|| this == NULL
)
1773 if ((c
> 127 && c
< 256) && use_8th_bit_as_meta
)
1777 /* The first sequence defined starts with esc */
1782 while (this != NULL
)
1790 pending_keys
= seq_buffer
;
1795 if (parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
)
1802 /* Shouldn't happen */
1803 fputs ("Internal error\n", stderr
);
1804 exit (EXIT_FAILURE
);
1806 goto nodelay_try_again
;
1808 esctime
.tv_sec
= -1;
1809 c
= xgetch_second ();
1812 pending_keys
= seq_append
= NULL
;
1820 goto nodelay_try_again
;
1821 c
= tty_lowlevel_getch ();
1826 /* We got a complete match, return and reset search */
1829 pending_keys
= seq_append
= NULL
;
1832 return correct_key_code (code
);
1837 if (this->next
!= NULL
)
1841 if ((parent
!= NULL
) && (parent
->action
== MCKEY_ESCAPE
))
1843 /* Convert escape-digits to F-keys */
1844 if (g_ascii_isdigit (c
))
1845 c
= KEY_F (c
- '0');
1851 pending_keys
= seq_append
= NULL
;
1853 return correct_key_code (c
);
1855 /* Did not find a match or {c} was changed in the if above,
1856 so we have to return everything we had skipped
1859 pending_keys
= seq_buffer
;
1865 return correct_key_code (c
);
1868 /* --------------------------------------------------------------------------------------------- */
1869 /* Returns a character read from stdin with appropriate interpretation */
1870 /* Also takes care of generated mouse events */
1871 /* Returns EV_MOUSE if it is a mouse event */
1872 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
1875 tty_get_event (struct Gpm_Event
*event
, gboolean redo_event
, gboolean block
)
1878 static int flag
= 0; /* Return value from select */
1880 static struct Gpm_Event ev
; /* Mouse event */
1882 struct timeval time_out
;
1883 struct timeval
*time_addr
= NULL
;
1884 static int dirty
= 3;
1886 if ((dirty
== 3) || is_idle ())
1894 vfs_timeout_handler ();
1896 /* Ok, we use (event->x < 0) to signal that the event does not contain
1897 a suitable position for the mouse, so we can't use show_mouse_pointer
1902 show_mouse_pointer (event
->x
, event
->y
);
1907 /* Repeat if using mouse */
1908 while (pending_keys
== NULL
)
1913 FD_ZERO (&select_set
);
1914 FD_SET (input_fd
, &select_set
);
1915 maxfdp
= max (add_selects (&select_set
), input_fd
);
1918 if (mouse_enabled
&& (use_mouse_p
== MOUSE_GPM
))
1922 /* Connection to gpm broken, possibly gpm has died */
1923 mouse_enabled
= FALSE
;
1924 use_mouse_p
= MOUSE_NONE
;
1928 FD_SET (gpm_fd
, &select_set
);
1929 maxfdp
= max (maxfdp
, gpm_fd
);
1935 time_out
.tv_usec
= mou_auto_repeat
* 1000;
1936 time_out
.tv_sec
= 0;
1938 time_addr
= &time_out
;
1944 seconds
= vfs_timeouts ();
1949 /* the timeout could be improved and actually be
1950 * the number of seconds until the next vfs entry
1951 * timeouts in the stamp list.
1954 time_out
.tv_sec
= seconds
;
1955 time_out
.tv_usec
= 0;
1956 time_addr
= &time_out
;
1960 if (!block
|| mc_global
.tty
.winch_flag
)
1962 time_addr
= &time_out
;
1963 time_out
.tv_sec
= 0;
1964 time_out
.tv_usec
= 0;
1967 tty_enable_interrupt_key ();
1968 flag
= select (maxfdp
+ 1, &select_set
, NULL
, NULL
, time_addr
);
1969 tty_disable_interrupt_key ();
1971 /* select timed out: it could be for any of the following reasons:
1972 * redo_event -> it was because of the MOU_REPEAT handler
1973 * !block -> we did not block in the select call
1974 * else -> 10 second timeout to check the vfs status.
1980 if (!block
|| mc_global
.tty
.winch_flag
)
1982 vfs_timeout_handler ();
1984 if (flag
== -1 && errno
== EINTR
)
1987 check_selects (&select_set
);
1989 if (FD_ISSET (input_fd
, &select_set
))
1992 if (mouse_enabled
&& use_mouse_p
== MOUSE_GPM
1993 && gpm_fd
> 0 && FD_ISSET (gpm_fd
, &select_set
))
2000 #endif /* !HAVE_LIBGPM */
2004 flag
= is_wintouched (stdscr
);
2005 untouchwin (stdscr
);
2006 #endif /* !HAVE_SLANG */
2007 c
= block
? getch_with_delay () : get_key_code (1);
2011 tty_touch_screen ();
2012 #endif /* !HAVE_SLANG */
2014 if (mouse_enabled
&& (c
== MCKEY_MOUSE
2017 #endif /* KEY_MOUSE */
2021 xmouse_get_event (event
);
2022 return (event
->type
!= 0) ? EV_MOUSE
: EV_NONE
;
2028 /* --------------------------------------------------------------------------------------------- */
2029 /* Returns a key press, mouse events are discarded */
2038 while ((key
= tty_get_event (&ev
, FALSE
, TRUE
)) == EV_NONE
);
2042 /* --------------------------------------------------------------------------------------------- */
2047 /* LEARN_TIMEOUT in usec */
2048 #define LEARN_TIMEOUT 200000
2051 struct timeval endtime
;
2052 struct timeval time_out
;
2057 tty_keypad (FALSE
); /* disable intepreting keys by ncurses */
2058 c
= tty_lowlevel_getch ();
2060 c
= tty_lowlevel_getch (); /* Sanity check, should be unnecessary */
2061 learn_store_key (buffer
, &p
, c
);
2063 endtime
.tv_usec
+= LEARN_TIMEOUT
;
2064 if (endtime
.tv_usec
> 1000000)
2066 endtime
.tv_usec
-= 1000000;
2072 while ((c
= tty_lowlevel_getch ()) == -1)
2074 GET_TIME (time_out
);
2075 time_out
.tv_usec
= endtime
.tv_usec
- time_out
.tv_usec
;
2076 if (time_out
.tv_usec
< 0)
2078 time_out
.tv_sec
= endtime
.tv_sec
- time_out
.tv_sec
;
2079 if (time_out
.tv_sec
>= 0 && time_out
.tv_usec
> 0)
2081 FD_ZERO (&Read_FD_Set
);
2082 FD_SET (input_fd
, &Read_FD_Set
);
2083 select (input_fd
+ 1, &Read_FD_Set
, NULL
, NULL
, &time_out
);
2090 learn_store_key (buffer
, &p
, c
);
2093 tty_nodelay (FALSE
);
2095 return g_strdup (buffer
);
2096 #undef LEARN_TIMEOUT
2099 /* --------------------------------------------------------------------------------------------- */
2100 /* xterm and linux console only: set keypad to numeric or application
2101 mode. Only in application keypad mode it's possible to distinguish
2102 the '+' key and the '+' on the keypad ('*' and '-' ditto) */
2105 numeric_keypad_mode (void)
2107 if (mc_global
.tty
.console_flag
!= '\0' || mc_global
.tty
.xterm_flag
)
2109 fputs (ESC_STR
">", stdout
);
2114 /* --------------------------------------------------------------------------------------------- */
2117 application_keypad_mode (void)
2119 if (mc_global
.tty
.console_flag
!= '\0' || mc_global
.tty
.xterm_flag
)
2121 fputs (ESC_STR
"=", stdout
);
2126 /* --------------------------------------------------------------------------------------------- */