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"
47 #include "lib/vfs/vfs.h"
50 #include "tty-internal.h" /* mouse_enabled */
54 #include "lib/widget.h" /* mc_refresh() */
56 #ifdef HAVE_TEXTMODE_X11_SUPPORT
61 #if defined(__GLIBC__) && (__GLIBC__ < 2)
62 #include <linux/termios.h> /* TIOCLINUX */
66 #include <sys/ioctl.h>
67 #endif /* __linux__ */
71 #include <sys/ioctl.h>
72 #endif /* __CYGWIN__ */
77 #include <sys/dcmd_chr.h>
78 #endif /* __QNXNTO__ */
80 /*** global variables ****************************************************************************/
82 int mou_auto_repeat
= 100;
83 int double_click_speed
= 250;
85 /* timeout for old_esc_mode in usec */
86 int old_esc_mode_timeout
= 1000000; /* settable via env */
87 int use_8th_bit_as_meta
= 0;
89 /* This table is a mapping between names and the constants we use
90 * We use this to allow users to define alternate definitions for
91 * certain keys that may be missing from the terminal database
93 const key_code_name_t key_name_conv_tab
[] = {
94 /* KEY_F(0) is not here, since we are mapping it to f10, so there is no reason
95 to define f0 as well. Also, it makes Learn keys a bunch of problems :( */
96 {KEY_F (1), "f1", N_("Function key 1"), "F1"},
97 {KEY_F (2), "f2", N_("Function key 2"), "F2"},
98 {KEY_F (3), "f3", N_("Function key 3"), "F3"},
99 {KEY_F (4), "f4", N_("Function key 4"), "F4"},
100 {KEY_F (5), "f5", N_("Function key 5"), "F5"},
101 {KEY_F (6), "f6", N_("Function key 6"), "F6"},
102 {KEY_F (7), "f7", N_("Function key 7"), "F7"},
103 {KEY_F (8), "f8", N_("Function key 8"), "F8"},
104 {KEY_F (9), "f9", N_("Function key 9"), "F9"},
105 {KEY_F (10), "f10", N_("Function key 10"), "F10"},
106 {KEY_F (11), "f11", N_("Function key 11"), "F11"},
107 {KEY_F (12), "f12", N_("Function key 12"), "F12"},
108 {KEY_F (13), "f13", N_("Function key 13"), "F13"},
109 {KEY_F (14), "f14", N_("Function key 14"), "F14"},
110 {KEY_F (15), "f15", N_("Function key 15"), "F15"},
111 {KEY_F (16), "f16", N_("Function key 16"), "F16"},
112 {KEY_F (17), "f17", N_("Function key 17"), "F17"},
113 {KEY_F (18), "f18", N_("Function key 18"), "F18"},
114 {KEY_F (19), "f19", N_("Function key 19"), "F19"},
115 {KEY_F (20), "f20", N_("Function key 20"), "F20"},
116 {KEY_BACKSPACE
, "backspace", N_("Backspace key"), "Backspace"},
117 {KEY_END
, "end", N_("End key"), "End"},
118 {KEY_UP
, "up", N_("Up arrow key"), "Up"},
119 {KEY_DOWN
, "down", N_("Down arrow key"), "Down"},
120 {KEY_LEFT
, "left", N_("Left arrow key"), "Left"},
121 {KEY_RIGHT
, "right", N_("Right arrow key"), "Right"},
122 {KEY_HOME
, "home", N_("Home key"), "Home"},
123 {KEY_NPAGE
, "pgdn", N_("Page Down key"), "PgDn"},
124 {KEY_PPAGE
, "pgup", N_("Page Up key"), "PgUp"},
125 {KEY_IC
, "insert", N_("Insert key"), "Ins"},
126 {KEY_DC
, "delete", N_("Delete key"), "Del"},
127 {ALT ('\t'), "complete", N_("Completion/M-tab"), "Meta-Tab"},
128 {KEY_KP_ADD
, "kpplus", N_("+ on keypad"), "+"},
129 {KEY_KP_SUBTRACT
, "kpminus", N_("- on keypad"), "-"},
130 {(int) '/', "kpslash", N_("Slash on keypad"), "/"},
131 {KEY_KP_MULTIPLY
, "kpasterisk", N_("* on keypad"), "*"},
133 /* From here on, these won't be shown in Learn keys (no space) */
134 {ESC_CHAR
, "escape", N_("Escape key"), "Esc"},
135 {KEY_LEFT
, "kpleft", N_("Left arrow keypad"), "Left"},
136 {KEY_RIGHT
, "kpright", N_("Right arrow keypad"), "Right"},
137 {KEY_UP
, "kpup", N_("Up arrow keypad"), "Up"},
138 {KEY_DOWN
, "kpdown", N_("Down arrow keypad"), "Down"},
139 {KEY_HOME
, "kphome", N_("Home on keypad"), "Home"},
140 {KEY_END
, "kpend", N_("End on keypad"), "End"},
141 {KEY_NPAGE
, "kpnpage", N_("Page Down keypad"), "PgDn"},
142 {KEY_PPAGE
, "kpppage", N_("Page Up keypad"), "PgUp"},
143 {KEY_IC
, "kpinsert", N_("Insert on keypad"), "Ins"},
144 {KEY_DC
, "kpdelete", N_("Delete on keypad"), "Del"},
145 {(int) '\n', "kpenter", N_("Enter on keypad"), "Enter"},
146 {KEY_F (21), "f21", N_("Function key 21"), "F21"},
147 {KEY_F (22), "f22", N_("Function key 22"), "F22"},
148 {KEY_F (23), "f23", N_("Function key 23"), "F23"},
149 {KEY_F (24), "f24", N_("Function key 24"), "F24"},
150 {KEY_A1
, "a1", N_("A1 key"), "A1"},
151 {KEY_C1
, "c1", N_("C1 key"), "C1"},
153 /* Alternative label */
154 {ESC_CHAR
, "esc", N_("Escape key"), "Esc"},
155 {KEY_BACKSPACE
, "bs", N_("Backspace key"), "Bakspace"},
156 {KEY_IC
, "ins", N_("Insert key"), "Ins"},
157 {KEY_DC
, "del", N_("Delete key"), "Del"},
158 {(int) '+', "plus", N_("Plus"), "+"},
159 {(int) '-', "minus", N_("Minus"), "-"},
160 {(int) '*', "asterisk", N_("Asterisk"), "*"},
161 {(int) '.', "dot", N_("Dot"), "."},
162 {(int) '<', "lt", N_("Less than"), "<"},
163 {(int) '>', "gt", N_("Great than"), ">"},
164 {(int) '=', "equal", N_("Equal"), "="},
165 {(int) ',', "comma", N_("Comma"), ","},
166 {(int) '\'', "apostrophe", N_("Apostrophe"), "\'"},
167 {(int) ':', "colon", N_("Colon"), ":"},
168 {(int) '!', "exclamation", N_("Exclamation mark"), "!"},
169 {(int) '?', "question", N_("Question mark"), "?"},
170 {(int) '&', "ampersand", N_("Ampersand"), "&"},
171 {(int) '$', "dollar", N_("Dollar sign"), "$"},
172 {(int) '"', "quota", N_("Quotation mark"), "\""},
173 {(int) '%', "percent", N_("Percent sign"), "%"},
174 {(int) '^', "caret", N_("Caret"), "^"},
175 {(int) '~', "tilda", N_("Tilda"), "~"},
176 {(int) '`', "prime", N_("Prime"), "`"},
177 {(int) '_', "underline", N_("Underline"), "_"},
178 {(int) '_', "understrike", N_("Understrike"), "_"},
179 {(int) '|', "pipe", N_("Pipe"), "|"},
180 {(int) '(', "lparenthesis", N_("Left parenthesis"), "("},
181 {(int) ')', "rparenthesis", N_("Right parenthesis"), ")"},
182 {(int) '[', "lbracket", N_("Left bracket"), "["},
183 {(int) ']', "rbracket", N_("Right bracket"), "]"},
184 {(int) '{', "lbrace", N_("Left brace"), "{"},
185 {(int) '}', "rbrace", N_("Right brace"), "}"},
186 {(int) '\n', "enter", N_("Enter"), "Enter"},
187 {(int) '\t', "tab", N_("Tab key"), "Tab"},
188 {(int) ' ', "space", N_("Space key"), "Space"},
189 {(int) '/', "slash", N_("Slash key"), "/"},
190 {(int) '\\', "backslash", N_("Backslash key"), "\\"},
191 {(int) '#', "number", N_("Number sign #"), "#"},
192 {(int) '#', "hash", N_("Number sign #"), "#"},
193 /* TRANSLATORS: Please translate as in "at sign" (@). */
194 {(int) '@', "at", N_("At sign"), "@"},
197 {KEY_M_CTRL
, "control", N_("Ctrl"), "C"},
198 {KEY_M_CTRL
, "ctrl", N_("Ctrl"), "C"},
199 {KEY_M_ALT
, "meta", N_("Alt"), "M"},
200 {KEY_M_ALT
, "alt", N_("Alt"), "M"},
201 {KEY_M_ALT
, "ralt", N_("Alt"), "M"},
202 {KEY_M_SHIFT
, "shift", N_("Shift"), "S"},
204 {0, NULL
, NULL
, NULL
}
207 /*** file scope macro definitions ****************************************************************/
209 #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *) NULL))
210 #define DIF_TIME(t1, t2) ((t2.tv_sec - t1.tv_sec) * 1000 + (t2.tv_usec - t1.tv_usec)/1000)
212 /* The maximum sequence length (32 + null terminator) */
213 #define SEQ_BUFFER_LEN 33
215 /*** file scope type declarations ****************************************************************/
217 /* Linux console keyboard modifiers */
220 SHIFT_PRESSED
= (1 << 0),
221 ALTR_PRESSED
= (1 << 1),
222 CONTROL_PRESSED
= (1 << 2),
223 ALTL_PRESSED
= (1 << 3)
226 typedef struct key_def
228 char ch
; /* Holds the matching char code */
229 int code
; /* The code returned, valid if child == NULL */
230 struct key_def
*next
;
231 struct key_def
*child
; /* sequence continuation */
232 int action
; /* optional action to be done. Now used only
233 to mark that we are just after the first
244 /* File descriptor monitoring add/remove routines */
245 typedef struct SelectList
250 struct SelectList
*next
;
253 typedef enum KeySortType
261 typedef int (*ph_dv_f
) (void *, void *);
262 typedef int (*ph_ov_f
) (void *);
263 typedef int (*ph_pqc_f
) (unsigned short, PhCursorInfo_t
*);
266 /*** file scope variables ************************************************************************/
268 static key_define_t mc_default_keys
[] = {
269 {ESC_CHAR
, ESC_STR
, MCKEY_ESCAPE
},
270 {ESC_CHAR
, ESC_STR ESC_STR
, MCKEY_NOACTION
},
271 {0, NULL
, MCKEY_NOACTION
},
274 /* Broken terminfo and termcap databases on xterminals */
275 static key_define_t xterm_key_defines
[] = {
276 {KEY_F (1), ESC_STR
"OP", MCKEY_NOACTION
},
277 {KEY_F (2), ESC_STR
"OQ", MCKEY_NOACTION
},
278 {KEY_F (3), ESC_STR
"OR", MCKEY_NOACTION
},
279 {KEY_F (4), ESC_STR
"OS", MCKEY_NOACTION
},
280 {KEY_F (1), ESC_STR
"[11~", MCKEY_NOACTION
},
281 {KEY_F (2), ESC_STR
"[12~", MCKEY_NOACTION
},
282 {KEY_F (3), ESC_STR
"[13~", MCKEY_NOACTION
},
283 {KEY_F (4), ESC_STR
"[14~", MCKEY_NOACTION
},
284 {KEY_F (5), ESC_STR
"[15~", MCKEY_NOACTION
},
285 {KEY_F (6), ESC_STR
"[17~", MCKEY_NOACTION
},
286 {KEY_F (7), ESC_STR
"[18~", MCKEY_NOACTION
},
287 {KEY_F (8), ESC_STR
"[19~", MCKEY_NOACTION
},
288 {KEY_F (9), ESC_STR
"[20~", MCKEY_NOACTION
},
289 {KEY_F (10), ESC_STR
"[21~", MCKEY_NOACTION
},
291 /* old xterm Shift-arrows */
292 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"O2A", MCKEY_NOACTION
},
293 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"O2B", MCKEY_NOACTION
},
294 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"O2C", MCKEY_NOACTION
},
295 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"O2D", MCKEY_NOACTION
},
297 /* new xterm Shift-arrows */
298 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"[1;2A", MCKEY_NOACTION
},
299 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"[1;2B", MCKEY_NOACTION
},
300 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"[1;2C", MCKEY_NOACTION
},
301 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"[1;2D", MCKEY_NOACTION
},
303 /* more xterm keys with modifiers */
304 {KEY_M_CTRL
| KEY_PPAGE
, ESC_STR
"[5;5~", MCKEY_NOACTION
},
305 {KEY_M_CTRL
| KEY_NPAGE
, ESC_STR
"[6;5~", MCKEY_NOACTION
},
306 {KEY_M_CTRL
| KEY_IC
, ESC_STR
"[2;5~", MCKEY_NOACTION
},
307 {KEY_M_CTRL
| KEY_DC
, ESC_STR
"[3;5~", MCKEY_NOACTION
},
308 {KEY_M_CTRL
| KEY_HOME
, ESC_STR
"[1;5H", MCKEY_NOACTION
},
309 {KEY_M_CTRL
| KEY_END
, ESC_STR
"[1;5F", MCKEY_NOACTION
},
310 {KEY_M_SHIFT
| KEY_HOME
, ESC_STR
"[1;2H", MCKEY_NOACTION
},
311 {KEY_M_SHIFT
| KEY_END
, ESC_STR
"[1;2F", MCKEY_NOACTION
},
312 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"[1;5A", MCKEY_NOACTION
},
313 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[1;5B", MCKEY_NOACTION
},
314 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[1;5C", MCKEY_NOACTION
},
315 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[1;5D", MCKEY_NOACTION
},
316 {KEY_M_SHIFT
| KEY_IC
, ESC_STR
"[2;2~", MCKEY_NOACTION
},
317 {KEY_M_SHIFT
| KEY_DC
, ESC_STR
"[3;2~", MCKEY_NOACTION
},
318 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"[1;6A", MCKEY_NOACTION
},
319 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[1;6B", MCKEY_NOACTION
},
320 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[1;6C", MCKEY_NOACTION
},
321 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[1;6D", MCKEY_NOACTION
},
324 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"[[1;6A", MCKEY_NOACTION
},
325 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[[1;6B", MCKEY_NOACTION
},
326 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[[1;6C", MCKEY_NOACTION
},
327 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[[1;6D", MCKEY_NOACTION
},
329 /* putty alt-arrow keys */
330 /* removed as source esc esc esc trouble */
332 { KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "OA", MCKEY_NOACTION },
333 { KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "OB", MCKEY_NOACTION },
334 { KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "OC", MCKEY_NOACTION },
335 { KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "OD", MCKEY_NOACTION },
336 { KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[5~", MCKEY_NOACTION },
337 { KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[6~", MCKEY_NOACTION },
338 { KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1~", MCKEY_NOACTION },
339 { KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[4~", MCKEY_NOACTION },
341 { KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "[1;2A", MCKEY_NOACTION },
342 { KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "[1;2B", MCKEY_NOACTION },
343 { KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "[1;2C", MCKEY_NOACTION },
344 { KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "[1;2D", MCKEY_NOACTION },
346 { KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[[5;5~", MCKEY_NOACTION },
347 { KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[[6;5~", MCKEY_NOACTION },
348 { KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1;5H", MCKEY_NOACTION },
349 { KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[1;5F", MCKEY_NOACTION },
351 /* xterm alt-arrow keys */
352 {KEY_M_ALT
| KEY_UP
, ESC_STR
"[1;3A", MCKEY_NOACTION
},
353 {KEY_M_ALT
| KEY_DOWN
, ESC_STR
"[1;3B", MCKEY_NOACTION
},
354 {KEY_M_ALT
| KEY_RIGHT
, ESC_STR
"[1;3C", MCKEY_NOACTION
},
355 {KEY_M_ALT
| KEY_LEFT
, ESC_STR
"[1;3D", MCKEY_NOACTION
},
356 {KEY_M_ALT
| KEY_PPAGE
, ESC_STR
"[5;3~", MCKEY_NOACTION
},
357 {KEY_M_ALT
| KEY_NPAGE
, ESC_STR
"[6;3~", MCKEY_NOACTION
},
358 {KEY_M_ALT
| KEY_HOME
, ESC_STR
"[1~", MCKEY_NOACTION
},
359 {KEY_M_ALT
| KEY_END
, ESC_STR
"[4~", MCKEY_NOACTION
},
360 {KEY_M_CTRL
| KEY_M_ALT
| KEY_UP
, ESC_STR
"[1;7A", MCKEY_NOACTION
},
361 {KEY_M_CTRL
| KEY_M_ALT
| KEY_DOWN
, ESC_STR
"[1;7B", MCKEY_NOACTION
},
362 {KEY_M_CTRL
| KEY_M_ALT
| KEY_RIGHT
, ESC_STR
"[1;7C", MCKEY_NOACTION
},
363 {KEY_M_CTRL
| KEY_M_ALT
| KEY_LEFT
, ESC_STR
"[1;7D", MCKEY_NOACTION
},
364 {KEY_M_CTRL
| KEY_M_ALT
| KEY_PPAGE
, ESC_STR
"[5;7~", MCKEY_NOACTION
},
365 {KEY_M_CTRL
| KEY_M_ALT
| KEY_NPAGE
, ESC_STR
"[6;7~", MCKEY_NOACTION
},
366 {KEY_M_CTRL
| KEY_M_ALT
| KEY_HOME
, ESC_STR
"OH", MCKEY_NOACTION
},
367 {KEY_M_CTRL
| KEY_M_ALT
| KEY_END
, ESC_STR
"OF", MCKEY_NOACTION
},
369 /* rxvt keys with modifiers */
370 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"[a", MCKEY_NOACTION
},
371 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"[b", MCKEY_NOACTION
},
372 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"[c", MCKEY_NOACTION
},
373 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"[d", MCKEY_NOACTION
},
374 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"Oa", MCKEY_NOACTION
},
375 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"Ob", MCKEY_NOACTION
},
376 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"Oc", MCKEY_NOACTION
},
377 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"Od", MCKEY_NOACTION
},
378 {KEY_M_CTRL
| KEY_PPAGE
, ESC_STR
"[5^", MCKEY_NOACTION
},
379 {KEY_M_CTRL
| KEY_NPAGE
, ESC_STR
"[6^", MCKEY_NOACTION
},
380 {KEY_M_CTRL
| KEY_HOME
, ESC_STR
"[7^", MCKEY_NOACTION
},
381 {KEY_M_CTRL
| KEY_END
, ESC_STR
"[8^", MCKEY_NOACTION
},
382 {KEY_M_SHIFT
| KEY_HOME
, ESC_STR
"[7$", MCKEY_NOACTION
},
383 {KEY_M_SHIFT
| KEY_END
, ESC_STR
"[8$", MCKEY_NOACTION
},
384 {KEY_M_CTRL
| KEY_IC
, ESC_STR
"[2^", MCKEY_NOACTION
},
385 {KEY_M_CTRL
| KEY_DC
, ESC_STR
"[3^", MCKEY_NOACTION
},
386 {KEY_M_SHIFT
| KEY_DC
, ESC_STR
"[3$", MCKEY_NOACTION
},
388 /* konsole keys with modifiers */
389 {KEY_M_SHIFT
| KEY_HOME
, ESC_STR
"O2H", MCKEY_NOACTION
},
390 {KEY_M_SHIFT
| KEY_END
, ESC_STR
"O2F", MCKEY_NOACTION
},
393 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"[2A", MCKEY_NOACTION
},
394 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"[2B", MCKEY_NOACTION
},
395 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"[2C", MCKEY_NOACTION
},
396 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"[2D", MCKEY_NOACTION
},
397 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"[5A", MCKEY_NOACTION
},
398 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[5B", MCKEY_NOACTION
},
399 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[5C", MCKEY_NOACTION
},
400 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[5D", MCKEY_NOACTION
},
401 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"[6A", MCKEY_NOACTION
},
402 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[6B", MCKEY_NOACTION
},
403 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[6C", MCKEY_NOACTION
},
404 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[6D", MCKEY_NOACTION
},
406 /* gnome-terminal - application mode */
407 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"O5A", MCKEY_NOACTION
},
408 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"O5B", MCKEY_NOACTION
},
409 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"O5C", MCKEY_NOACTION
},
410 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"O5D", MCKEY_NOACTION
},
411 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"O6A", MCKEY_NOACTION
},
412 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"O6B", MCKEY_NOACTION
},
413 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"O6C", MCKEY_NOACTION
},
414 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"O6D", MCKEY_NOACTION
},
417 {KEY_M_SHIFT
| KEY_PPAGE
, ESC_STR
"[5;2~", MCKEY_NOACTION
},
418 {KEY_M_SHIFT
| KEY_NPAGE
, ESC_STR
"[6;2~", MCKEY_NOACTION
},
421 {KEY_M_SHIFT
| KEY_PPAGE
, ESC_STR
"[[5;53~", MCKEY_NOACTION
},
422 {KEY_M_SHIFT
| KEY_NPAGE
, ESC_STR
"[[6;53~", MCKEY_NOACTION
},
425 {KEY_IC
, ESC_STR
"Op", MCKEY_NOACTION
},
426 {KEY_DC
, ESC_STR
"On", MCKEY_NOACTION
},
427 {'/', ESC_STR
"Oo", MCKEY_NOACTION
},
428 {'\n', ESC_STR
"OM", MCKEY_NOACTION
},
430 {0, NULL
, MCKEY_NOACTION
},
433 /* qansi-m terminals have a much more key combinatios,
434 which are undefined in termcap/terminfo */
435 static key_define_t qansi_key_defines
[] = {
436 /* qansi-m terminal */
437 {KEY_M_CTRL
| KEY_NPAGE
, ESC_STR
"[u", MCKEY_NOACTION
}, /* Ctrl-PgDown */
438 {KEY_M_CTRL
| KEY_PPAGE
, ESC_STR
"[v", MCKEY_NOACTION
}, /* Ctrl-PgUp */
439 {KEY_M_CTRL
| KEY_HOME
, ESC_STR
"[h", MCKEY_NOACTION
}, /* Ctrl-Home */
440 {KEY_M_CTRL
| KEY_END
, ESC_STR
"[y", MCKEY_NOACTION
}, /* Ctrl-End */
441 {KEY_M_CTRL
| KEY_IC
, ESC_STR
"[`", MCKEY_NOACTION
}, /* Ctrl-Insert */
442 {KEY_M_CTRL
| KEY_DC
, ESC_STR
"[p", MCKEY_NOACTION
}, /* Ctrl-Delete */
443 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[d", MCKEY_NOACTION
}, /* Ctrl-Left */
444 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[c", MCKEY_NOACTION
}, /* Ctrl-Right */
445 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[b", MCKEY_NOACTION
}, /* Ctrl-Down */
446 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"[a", MCKEY_NOACTION
}, /* Ctrl-Up */
447 {KEY_M_CTRL
| KEY_KP_ADD
, ESC_STR
"[s", MCKEY_NOACTION
}, /* Ctrl-Gr-Plus */
448 {KEY_M_CTRL
| KEY_KP_SUBTRACT
, ESC_STR
"[t", MCKEY_NOACTION
}, /* Ctrl-Gr-Minus */
449 {KEY_M_CTRL
| '\t', ESC_STR
"[z", MCKEY_NOACTION
}, /* Ctrl-Tab */
450 {KEY_M_SHIFT
| '\t', ESC_STR
"[Z", MCKEY_NOACTION
}, /* Shift-Tab */
451 {KEY_M_CTRL
| KEY_F (1), ESC_STR
"[1~", MCKEY_NOACTION
}, /* Ctrl-F1 */
452 {KEY_M_CTRL
| KEY_F (2), ESC_STR
"[2~", MCKEY_NOACTION
}, /* Ctrl-F2 */
453 {KEY_M_CTRL
| KEY_F (3), ESC_STR
"[3~", MCKEY_NOACTION
}, /* Ctrl-F3 */
454 {KEY_M_CTRL
| KEY_F (4), ESC_STR
"[4~", MCKEY_NOACTION
}, /* Ctrl-F4 */
455 {KEY_M_CTRL
| KEY_F (5), ESC_STR
"[5~", MCKEY_NOACTION
}, /* Ctrl-F5 */
456 {KEY_M_CTRL
| KEY_F (6), ESC_STR
"[6~", MCKEY_NOACTION
}, /* Ctrl-F6 */
457 {KEY_M_CTRL
| KEY_F (7), ESC_STR
"[7~", MCKEY_NOACTION
}, /* Ctrl-F7 */
458 {KEY_M_CTRL
| KEY_F (8), ESC_STR
"[8~", MCKEY_NOACTION
}, /* Ctrl-F8 */
459 {KEY_M_CTRL
| KEY_F (9), ESC_STR
"[9~", MCKEY_NOACTION
}, /* Ctrl-F9 */
460 {KEY_M_CTRL
| KEY_F (10), ESC_STR
"[10~", MCKEY_NOACTION
}, /* Ctrl-F10 */
461 {KEY_M_CTRL
| KEY_F (11), ESC_STR
"[11~", MCKEY_NOACTION
}, /* Ctrl-F11 */
462 {KEY_M_CTRL
| KEY_F (12), ESC_STR
"[12~", MCKEY_NOACTION
}, /* Ctrl-F12 */
463 {KEY_M_ALT
| KEY_F (1), ESC_STR
"[17~", MCKEY_NOACTION
}, /* Alt-F1 */
464 {KEY_M_ALT
| KEY_F (2), ESC_STR
"[18~", MCKEY_NOACTION
}, /* Alt-F2 */
465 {KEY_M_ALT
| KEY_F (3), ESC_STR
"[19~", MCKEY_NOACTION
}, /* Alt-F3 */
466 {KEY_M_ALT
| KEY_F (4), ESC_STR
"[20~", MCKEY_NOACTION
}, /* Alt-F4 */
467 {KEY_M_ALT
| KEY_F (5), ESC_STR
"[21~", MCKEY_NOACTION
}, /* Alt-F5 */
468 {KEY_M_ALT
| KEY_F (6), ESC_STR
"[22~", MCKEY_NOACTION
}, /* Alt-F6 */
469 {KEY_M_ALT
| KEY_F (7), ESC_STR
"[23~", MCKEY_NOACTION
}, /* Alt-F7 */
470 {KEY_M_ALT
| KEY_F (8), ESC_STR
"[24~", MCKEY_NOACTION
}, /* Alt-F8 */
471 {KEY_M_ALT
| KEY_F (9), ESC_STR
"[25~", MCKEY_NOACTION
}, /* Alt-F9 */
472 {KEY_M_ALT
| KEY_F (10), ESC_STR
"[26~", MCKEY_NOACTION
}, /* Alt-F10 */
473 {KEY_M_ALT
| KEY_F (11), ESC_STR
"[27~", MCKEY_NOACTION
}, /* Alt-F11 */
474 {KEY_M_ALT
| KEY_F (12), ESC_STR
"[28~", MCKEY_NOACTION
}, /* Alt-F12 */
475 {KEY_M_ALT
| 'a', ESC_STR
"Na", MCKEY_NOACTION
}, /* Alt-a */
476 {KEY_M_ALT
| 'b', ESC_STR
"Nb", MCKEY_NOACTION
}, /* Alt-b */
477 {KEY_M_ALT
| 'c', ESC_STR
"Nc", MCKEY_NOACTION
}, /* Alt-c */
478 {KEY_M_ALT
| 'd', ESC_STR
"Nd", MCKEY_NOACTION
}, /* Alt-d */
479 {KEY_M_ALT
| 'e', ESC_STR
"Ne", MCKEY_NOACTION
}, /* Alt-e */
480 {KEY_M_ALT
| 'f', ESC_STR
"Nf", MCKEY_NOACTION
}, /* Alt-f */
481 {KEY_M_ALT
| 'g', ESC_STR
"Ng", MCKEY_NOACTION
}, /* Alt-g */
482 {KEY_M_ALT
| 'h', ESC_STR
"Nh", MCKEY_NOACTION
}, /* Alt-h */
483 {KEY_M_ALT
| 'i', ESC_STR
"Ni", MCKEY_NOACTION
}, /* Alt-i */
484 {KEY_M_ALT
| 'j', ESC_STR
"Nj", MCKEY_NOACTION
}, /* Alt-j */
485 {KEY_M_ALT
| 'k', ESC_STR
"Nk", MCKEY_NOACTION
}, /* Alt-k */
486 {KEY_M_ALT
| 'l', ESC_STR
"Nl", MCKEY_NOACTION
}, /* Alt-l */
487 {KEY_M_ALT
| 'm', ESC_STR
"Nm", MCKEY_NOACTION
}, /* Alt-m */
488 {KEY_M_ALT
| 'n', ESC_STR
"Nn", MCKEY_NOACTION
}, /* Alt-n */
489 {KEY_M_ALT
| 'o', ESC_STR
"No", MCKEY_NOACTION
}, /* Alt-o */
490 {KEY_M_ALT
| 'p', ESC_STR
"Np", MCKEY_NOACTION
}, /* Alt-p */
491 {KEY_M_ALT
| 'q', ESC_STR
"Nq", MCKEY_NOACTION
}, /* Alt-q */
492 {KEY_M_ALT
| 'r', ESC_STR
"Nr", MCKEY_NOACTION
}, /* Alt-r */
493 {KEY_M_ALT
| 's', ESC_STR
"Ns", MCKEY_NOACTION
}, /* Alt-s */
494 {KEY_M_ALT
| 't', ESC_STR
"Nt", MCKEY_NOACTION
}, /* Alt-t */
495 {KEY_M_ALT
| 'u', ESC_STR
"Nu", MCKEY_NOACTION
}, /* Alt-u */
496 {KEY_M_ALT
| 'v', ESC_STR
"Nv", MCKEY_NOACTION
}, /* Alt-v */
497 {KEY_M_ALT
| 'w', ESC_STR
"Nw", MCKEY_NOACTION
}, /* Alt-w */
498 {KEY_M_ALT
| 'x', ESC_STR
"Nx", MCKEY_NOACTION
}, /* Alt-x */
499 {KEY_M_ALT
| 'y', ESC_STR
"Ny", MCKEY_NOACTION
}, /* Alt-y */
500 {KEY_M_ALT
| 'z', ESC_STR
"Nz", MCKEY_NOACTION
}, /* Alt-z */
501 {KEY_KP_SUBTRACT
, ESC_STR
"[S", MCKEY_NOACTION
}, /* Gr-Minus */
502 {KEY_KP_ADD
, ESC_STR
"[T", MCKEY_NOACTION
}, /* Gr-Plus */
503 {0, NULL
, MCKEY_NOACTION
},
506 /* This holds all the key definitions */
507 static key_def
*keys
= NULL
;
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 static int mouse_btn
, mouse_x
, mouse_y
;
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
)
711 static struct timeval tv1
= { 0, 0 }; /* Force first click as single */
712 static struct timeval tv2
;
713 static int clicks
= 0;
714 static int last_btn
= 0;
717 /* Decode Xterm mouse information to a GPM style event */
719 /* There seems to be no way of knowing which button was released */
720 /* So we assume all the buttons were released */
726 if ((last_btn
& (GPM_B_UP
| GPM_B_DOWN
)) != 0)
728 /* FIXME: DIRTY HACK */
729 /* don't generate GPM_UP after mouse wheel */
730 /* need for menu event handling */
737 ev
->type
= GPM_UP
| (GPM_SINGLE
<< clicks
);
746 /* Bogus event, maybe mouse wheel */
752 if (btn
>= 32 && btn
<= 34)
761 if (tv1
.tv_sec
&& (DIF_TIME (tv1
, tv2
) < double_click_speed
))
772 ev
->buttons
= GPM_B_LEFT
;
775 ev
->buttons
= GPM_B_MIDDLE
;
778 ev
->buttons
= GPM_B_RIGHT
;
781 ev
->buttons
= GPM_B_UP
;
785 ev
->buttons
= GPM_B_DOWN
;
794 last_btn
= ev
->buttons
;
800 /* --------------------------------------------------------------------------------------------- */
802 * Get modifier state (shift, alt, ctrl) for the last key pressed.
803 * We are assuming that the state didn't change since the key press.
804 * This is only correct if get_modifier() is called very fast after
805 * the input was received, so that the user didn't release the
814 int mod_status
, shift_ext_status
;
815 static int in_photon
= 0;
816 static int ph_ig
= 0;
817 PhCursorInfo_t cursor_info
;
818 #endif /* __QNXNTO__ */
820 #ifdef HAVE_TEXTMODE_X11_SUPPORT
828 mc_XQueryPointer (x11_display
, x11_window
, &root
, &child
, &root_x
,
829 &root_y
, &win_x
, &win_y
, &mask
);
831 if (mask
& ShiftMask
)
832 result
|= KEY_M_SHIFT
;
833 if (mask
& ControlMask
)
834 result
|= KEY_M_CTRL
;
837 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
842 /* First time here, let's load Photon library and attach
845 if (getenv ("PHOTON2_PATH") != NULL
)
847 /* QNX 6.x has no support for RTLD_LAZY */
848 void *ph_handle
= dlopen ("/usr/lib/libph.so", RTLD_NOW
);
849 if (ph_handle
!= NULL
)
851 ph_attach
= (ph_dv_f
) dlsym (ph_handle
, "PhAttach");
852 ph_input_group
= (ph_ov_f
) dlsym (ph_handle
, "PhInputGroup");
853 ph_query_cursor
= (ph_pqc_f
) dlsym (ph_handle
, "PhQueryCursor");
854 if ((ph_attach
!= NULL
) && (ph_input_group
!= NULL
) && (ph_query_cursor
!= NULL
))
856 if ((*ph_attach
) (0, 0))
858 ph_ig
= (*ph_input_group
) (0);
865 /* We do not have Photon running. Assume we are in text
869 if (devctl (fileno (stdin
), DCMD_CHR_LINESTATUS
, &mod_status
, sizeof (int), NULL
) == -1)
871 shift_ext_status
= mod_status
& 0xffffff00UL
;
873 if (mod_status
& _LINESTATUS_CON_ALT
)
875 if (mod_status
& _LINESTATUS_CON_CTRL
)
876 result
|= KEY_M_CTRL
;
877 if ((mod_status
& _LINESTATUS_CON_SHIFT
) || (shift_ext_status
& 0x00000800UL
))
878 result
|= KEY_M_SHIFT
;
882 (*ph_query_cursor
) (ph_ig
, &cursor_info
);
883 if (cursor_info
.key_mods
& 0x04)
885 if (cursor_info
.key_mods
& 0x02)
886 result
|= KEY_M_CTRL
;
887 if (cursor_info
.key_mods
& 0x01)
888 result
|= KEY_M_SHIFT
;
890 #endif /* __QNXNTO__ */
892 #if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX)
894 unsigned char modifiers
= 6;
896 if (ioctl (0, TIOCLINUX
, &modifiers
) < 0)
899 /* Translate Linux modifiers into mc modifiers */
900 if (modifiers
& SHIFT_PRESSED
)
901 result
|= KEY_M_SHIFT
;
902 if (modifiers
& (ALTL_PRESSED
| ALTR_PRESSED
))
904 if (modifiers
& CONTROL_PRESSED
)
905 result
|= KEY_M_CTRL
;
907 #endif /* !__linux__ */
911 /* --------------------------------------------------------------------------------------------- */
916 gboolean ret
= FALSE
;
918 if (seq_append
== NULL
)
919 seq_append
= seq_buffer
;
921 if (seq_append
!= &(seq_buffer
[SEQ_BUFFER_LEN
- 2]))
931 /* --------------------------------------------------------------------------------------------- */
932 /* Parse extended mouse coordinates.
933 Returns -1 if pending_keys (up to seq_append) cannot be a prefix of extended mouse coordinates.
934 Returns 0 if pending_keys (up to seq_append) is a valid (but still incomplete) prefix for
935 extended mouse coordinates, e.g. "^[[32;4".
936 Returns 1 and fills the mouse_btn, mouse_x, mouse_y values if pending_keys (up to seq_append) is
937 a complete extended mouse sequence, e.g. "^[[32;42;5M"
940 /* Technical info (Egmont Koblinger <egmont@gmail.com>):
942 The ancient way of reporting mouse coordinates only supports coordinates up to 223,
943 so if your terminal is wider (or taller, but that's unlikely), you cannot use your mouse
944 in the rightmost columns.
946 * The old way of reporting mouse coordinates is the following:
947 + Output DECSET 1000 to enable mouse
948 + Expect escape sequences in the format \e[M<action+32><x+32><y+32> whereas <action+32>,
949 <x+32> and <y+32> are single bytes. (Action is 0 for left click, 1 for middle click,
950 2 for right click, 3 for release, or something like this.)
951 + Disadvantages of this format:
952 + x and y can only go up to 223.
953 + Coordinates above 95 are not ascii-compatible, so any character set converting
954 layer (e.g. luit) messes them up.
955 + The stream is not valid UTF-8, even if everything else is.
957 * The first new extension, introduced by xterm-262, is the following:
958 + Output DECSET 1000 to enable mouse, followed by DECSET 1005 to activate extended mode.
959 + Expect escape sequences in the format \e[M<action+32><<x+32>><<y+32>> whereas <<x+32>>
960 and <<y+32>> each can be up to two bytes long: coordinate+32 is encoded in UTF-8.
961 + Disadvantates of this format:
962 + There's still a limit of 2015 rows/columns (okay, it's not a real life problem).
963 + Doesn't solve the luit issue.
964 + It is "horribly broken" (quoting urxvt's changelog) in terms of compatibility
965 with the previous standard. There is no way for an application to tell whether
966 the underlying terminal supports this new mode (whether DECSET 1005 did actually change
967 the behavior or not), but depending on this a completely different user action might
968 generate the same input. Example:
969 + If the terminal doesn't support this extension, then clicking at (162, 129)
970 generates \e[M<32><194><161>.
971 + If the terminal supports this extension, then clicking at (129, 1) [bit of math:
972 129+32 = 161, U+0161 in UTF-8 is 194 161] generates \e[M<32><194><161><33>.
973 + so there's no way to tell whether the terminal ignored the 1005 escape sequence,
974 the user clicked on (162, 129) and then typed an exclamation mark; or whether
975 the terminal recognized the escape, and the user clicked on (129, 1).
976 + Due to this horrible brokenness, there's no way to implement support it without
977 explicitly asking the user (via a setting) if the terminal can speak this extension.
979 * The second new extension, introduced by rxvt-unicode-9.10, is the following:
980 + Output DECSET 1000 to enable mouse, followed by DECSET 1015 to activate this extended mode.
981 + Expect escape sequences in the format \e[{action+32};{x};{y}M where this time I used
982 the braces to denote spelling out the numbers in decimal, rather than using raw bytes.
983 + The only thing I don't understand is why they kept the offset of 32 at action, but other
984 than that, this format is totally okay, and solves all the weaknesses of the previous ones.
986 Currently, at least the following terminal emulators have support for these:
987 * xterm supports the xterm extension
988 * rxvt-unicode >= 9.10 supports both extensions
989 * iterm2 supports both extensions
990 * vte >= 0.31 supports the urxvt extension
994 parse_extended_mouse_coordinates (void)
996 int c
, btn
= 0, x
= 0, y
= 0;
997 const int *p
= pending_keys
;
998 const int *endp
= seq_append
;
1019 if (c
< '0' || c
> '9')
1021 btn
= 10 * btn
+ c
- '0';
1034 if (c
< '0' || c
> '9')
1036 x
= 10 * x
+ c
- '0';
1048 if (c
< '0' || c
> '9')
1050 y
= 10 * y
+ c
- '0';
1061 /* --------------------------------------------------------------------------------------------- */
1062 /* Apply corrections for the keycode generated in get_key_code() */
1065 correct_key_code (int code
)
1067 unsigned int c
= code
& ~KEY_M_MASK
; /* code without modifier */
1068 unsigned int mod
= code
& KEY_M_MASK
; /* modifier */
1070 unsigned int qmod
; /* bunch of the QNX console
1071 modifiers needs unchanged */
1072 #endif /* __QNXNTO__ */
1075 * Add key modifiers directly from X11 or OS.
1076 * Ordinary characters only get modifiers from sequences.
1078 if (c
< 32 || c
>= 256)
1080 mod
|= get_modifier ();
1083 /* This is needed if the newline is reported as carriage return */
1087 /* This is reported to be useful on AIX */
1088 if (c
== KEY_SCANCEL
)
1091 /* Convert Shift+Tab and Ctrl+Tab to Back Tab */
1092 if ((c
== '\t') && (mod
& (KEY_M_SHIFT
| KEY_M_CTRL
)))
1098 /* F0 is the same as F10 for out purposes */
1103 * We are not interested if Ctrl was pressed when entering control
1104 * characters, so assume that it was. When checking for such keys,
1105 * XCTRL macro should be used. In some cases, we are interested,
1106 * e.g. to distinguish Ctrl-Enter from Enter.
1110 /* Special case for backspase ('\b' < 32) */
1114 else if (c
< 32 && c
!= ESC_CHAR
&& c
!= '\t' && c
!= '\n')
1120 qmod
= get_modifier ();
1122 if ((c
== 127) && (mod
== 0))
1123 { /* Add Ctrl/Alt/Shift-BackSpace */
1124 mod
|= get_modifier ();
1128 if ((c
== '0') && (mod
== 0))
1129 { /* Add Shift-Insert on key pad */
1130 if ((qmod
& KEY_M_SHIFT
) == KEY_M_SHIFT
)
1137 if ((c
== '.') && (mod
== 0))
1138 { /* Add Shift-Del on key pad */
1139 if ((qmod
& KEY_M_SHIFT
) == KEY_M_SHIFT
)
1145 #endif /* __QNXNTO__ */
1147 /* Unrecognized 0177 is delete (preserve Ctrl) */
1154 /* Unrecognized Ctrl-d is delete */
1155 if (c
== (31 & 'd'))
1161 /* Unrecognized Ctrl-h is backspace */
1162 if (c
== (31 & 'h'))
1169 /* Shift+BackSpace is backspace */
1170 if (c
== KEY_BACKSPACE
&& (mod
& KEY_M_SHIFT
))
1172 mod
&= ~KEY_M_SHIFT
;
1175 /* Convert Shift+Fn to F(n+10) */
1176 if (c
>= KEY_F (1) && c
<= KEY_F (10) && (mod
& KEY_M_SHIFT
))
1181 /* Remove Shift information from function keys */
1182 if (c
>= KEY_F (1) && c
<= KEY_F (20))
1184 mod
&= ~KEY_M_SHIFT
;
1187 if (!mc_global
.tty
.alternate_plus_minus
)
1193 case KEY_KP_SUBTRACT
:
1196 case KEY_KP_MULTIPLY
:
1204 /* --------------------------------------------------------------------------------------------- */
1207 xgetch_second (void)
1211 struct timeval time_out
;
1213 time_out
.tv_sec
= old_esc_mode_timeout
/ 1000000;
1214 time_out
.tv_usec
= old_esc_mode_timeout
% 1000000;
1216 FD_ZERO (&Read_FD_Set
);
1217 FD_SET (input_fd
, &Read_FD_Set
);
1218 select (input_fd
+ 1, &Read_FD_Set
, NULL
, NULL
, &time_out
);
1219 c
= tty_lowlevel_getch ();
1220 tty_nodelay (FALSE
);
1224 /* --------------------------------------------------------------------------------------------- */
1227 learn_store_key (char *buffer
, char **p
, int c
)
1229 if (*p
- buffer
> 253)
1239 *(*p
)++ = c
+ 'a' - 1;
1250 /* --------------------------------------------------------------------------------------------- */
1253 k_dispose (key_def
* k
)
1257 k_dispose (k
->child
);
1258 k_dispose (k
->next
);
1263 /* --------------------------------------------------------------------------------------------- */
1266 s_dispose (SelectList
* sel
)
1270 s_dispose (sel
->next
);
1275 /* --------------------------------------------------------------------------------------------- */
1278 key_code_comparator_by_name (const void *p1
, const void *p2
)
1280 const key_code_name_t
*n1
= *(const key_code_name_t
**) p1
;
1281 const key_code_name_t
*n2
= *(const key_code_name_t
**) p2
;
1283 return g_ascii_strcasecmp (n1
->name
, n2
->name
);
1286 /* --------------------------------------------------------------------------------------------- */
1289 key_code_comparator_by_code (const void *p1
, const void *p2
)
1291 const key_code_name_t
*n1
= *(const key_code_name_t
**) p1
;
1292 const key_code_name_t
*n2
= *(const key_code_name_t
**) p2
;
1294 return n1
->code
- n2
->code
;
1297 /* --------------------------------------------------------------------------------------------- */
1300 sort_key_conv_tab (enum KeySortType type_sort
)
1302 if (has_been_sorted
!= type_sort
)
1305 for (i
= 0; i
< key_conv_tab_size
; i
++)
1306 key_conv_tab_sorted
[i
] = &key_name_conv_tab
[i
];
1308 if (type_sort
== KEY_SORTBYNAME
)
1310 qsort (key_conv_tab_sorted
, key_conv_tab_size
, sizeof (key_conv_tab_sorted
[0]),
1311 &key_code_comparator_by_name
);
1313 else if (type_sort
== KEY_SORTBYCODE
)
1315 qsort (key_conv_tab_sorted
, key_conv_tab_size
, sizeof (key_conv_tab_sorted
[0]),
1316 &key_code_comparator_by_code
);
1318 has_been_sorted
= type_sort
;
1322 /* --------------------------------------------------------------------------------------------- */
1325 lookup_keyname (const char *name
, int *idx
)
1327 if (name
[0] != '\0')
1329 const key_code_name_t key
= { 0, name
, NULL
, NULL
};
1330 const key_code_name_t
*keyp
= &key
;
1331 key_code_name_t
**res
;
1333 if (name
[1] == '\0')
1336 return (int) name
[0];
1339 sort_key_conv_tab (KEY_SORTBYNAME
);
1341 res
= bsearch (&keyp
, key_conv_tab_sorted
, key_conv_tab_size
,
1342 sizeof (key_conv_tab_sorted
[0]), key_code_comparator_by_name
);
1346 *idx
= (int) (res
- (key_code_name_t
**) key_conv_tab_sorted
);
1347 return (*res
)->code
;
1355 /* --------------------------------------------------------------------------------------------- */
1358 lookup_keycode (const long code
, int *idx
)
1362 const key_code_name_t key
= { code
, NULL
, NULL
, NULL
};
1363 const key_code_name_t
*keyp
= &key
;
1364 key_code_name_t
**res
;
1366 sort_key_conv_tab (KEY_SORTBYCODE
);
1368 res
= bsearch (&keyp
, key_conv_tab_sorted
, key_conv_tab_size
,
1369 sizeof (key_conv_tab_sorted
[0]), key_code_comparator_by_code
);
1373 *idx
= (int) (res
- (key_code_name_t
**) key_conv_tab_sorted
);
1382 /* --------------------------------------------------------------------------------------------- */
1383 /*** public functions ****************************************************************************/
1384 /* --------------------------------------------------------------------------------------------- */
1385 /* This has to be called before init_slang or whatever routine
1386 calls any define_sequence */
1391 const char *term
= getenv ("TERM");
1393 /* This has to be the first define_sequence */
1394 /* So, we can assume that the first keys member has ESC */
1395 define_sequences (mc_default_keys
);
1397 /* Terminfo on irix does not have some keys */
1398 if (mc_global
.tty
.xterm_flag
1400 && (strncmp (term
, "iris-ansi", 9) == 0
1401 || strncmp (term
, "xterm", 5) == 0
1402 || strncmp (term
, "rxvt", 4) == 0 || strcmp (term
, "screen") == 0)))
1403 define_sequences (xterm_key_defines
);
1405 /* load some additional keys (e.g. direct Alt-? support) */
1406 load_xtra_key_defines ();
1409 if ((term
!= NULL
) && (strncmp (term
, "qnx", 3) == 0))
1411 /* Modify the default value of use_8th_bit_as_meta: we would
1412 * like to provide a working mc for a newbie who knows nothing
1413 * about [Options|Display bits|Full 8 bits input]...
1415 * Don't use 'meta'-bit, when we are dealing with a
1416 * 'qnx*'-type terminal: clear the default value!
1417 * These terminal types use 0xFF as an escape character,
1418 * so use_8th_bit_as_meta==1 must not be enabled!
1420 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
1421 * is not used now (doesn't even depend on use_8th_bit_as_meta
1422 * as in mc-3.1.2)...GREAT!...no additional code is required!]
1424 use_8th_bit_as_meta
= 0;
1426 #endif /* __QNX__ */
1430 /* Load the qansi-m key definitions
1431 if we are running under the qansi-m terminal */
1432 if (term
!= NULL
&& (strncmp (term
, "qansi-m", 7) == 0))
1433 define_sequences (qansi_key_defines
);
1436 /* --------------------------------------------------------------------------------------------- */
1438 * This has to be called after SLang_init_tty/slint_init
1442 init_key_input_fd (void)
1445 input_fd
= SLang_TT_Read_FD
;
1449 /* --------------------------------------------------------------------------------------------- */
1455 s_dispose (select_list
);
1457 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1459 mc_XCloseDisplay (x11_display
);
1463 /* --------------------------------------------------------------------------------------------- */
1466 add_select_channel (int fd
, select_fn callback
, void *info
)
1470 new = g_new (SelectList
, 1);
1472 new->callback
= callback
;
1474 new->next
= select_list
;
1478 /* --------------------------------------------------------------------------------------------- */
1481 delete_select_channel (int fd
)
1483 SelectList
*p
= select_list
;
1484 SelectList
*p_prev
= NULL
;
1493 p_prev
->next
= p_next
;
1495 select_list
= p_next
;
1507 /* --------------------------------------------------------------------------------------------- */
1512 if (disabled_channels
== 0)
1513 fputs ("Error: channels_up called with disabled_channels = 0\n", stderr
);
1514 disabled_channels
--;
1517 /* --------------------------------------------------------------------------------------------- */
1520 channels_down (void)
1522 disabled_channels
++;
1525 /* --------------------------------------------------------------------------------------------- */
1527 * Return the code associated with the symbolic name keyname
1531 lookup_key (const char *name
, char **label
)
1533 char **lc_keys
, **p
;
1545 name
= g_strstrip (g_strdup (name
));
1546 p
= lc_keys
= g_strsplit_set (name
, "-+ ", -1);
1547 g_free ((char *) name
);
1549 while ((p
!= NULL
) && (*p
!= NULL
))
1551 if ((*p
)[0] != '\0')
1555 key
= lookup_keyname (g_strstrip (*p
), &idx
);
1557 if (key
== KEY_M_ALT
)
1559 else if (key
== KEY_M_CTRL
)
1561 else if (key
== KEY_M_SHIFT
)
1574 g_strfreev (lc_keys
);
1585 s
= g_string_new ("");
1589 g_string_append (s
, key_conv_tab_sorted
[use_meta
]->shortcut
);
1590 g_string_append_c (s
, '-');
1594 g_string_append (s
, key_conv_tab_sorted
[use_ctrl
]->shortcut
);
1595 g_string_append_c (s
, '-');
1597 if (use_shift
!= -1)
1600 g_string_append_c (s
, (gchar
) g_ascii_toupper ((gchar
) k
));
1603 g_string_append (s
, key_conv_tab_sorted
[use_shift
]->shortcut
);
1604 g_string_append_c (s
, '-');
1605 g_string_append (s
, key_conv_tab_sorted
[lc_index
]->shortcut
);
1610 if ((k
>= 'A') || (lc_index
< 0) || (key_conv_tab_sorted
[lc_index
]->shortcut
== NULL
))
1611 g_string_append_c (s
, (gchar
) g_ascii_tolower ((gchar
) k
));
1613 g_string_append (s
, key_conv_tab_sorted
[lc_index
]->shortcut
);
1615 else if ((lc_index
!= -1) && (key_conv_tab_sorted
[lc_index
]->shortcut
!= NULL
))
1616 g_string_append (s
, key_conv_tab_sorted
[lc_index
]->shortcut
);
1618 g_string_append_c (s
, (gchar
) g_ascii_tolower ((gchar
) key
));
1620 *label
= g_string_free (s
, FALSE
);
1623 if (use_shift
!= -1)
1625 if (k
< 127 && k
> 31)
1626 k
= g_ascii_toupper ((gchar
) k
);
1645 /* --------------------------------------------------------------------------------------------- */
1648 lookup_key_by_code (const int keycode
)
1650 /* code without modifier */
1651 unsigned int k
= keycode
& ~KEY_M_MASK
;
1653 unsigned int mod
= keycode
& KEY_M_MASK
;
1663 s
= g_string_sized_new (8);
1665 if (lookup_keycode (k
, &key_idx
) || (k
> 0 && k
< 256))
1667 if (mod
& KEY_M_ALT
)
1669 if (lookup_keycode (KEY_M_ALT
, &idx
))
1672 g_string_append (s
, key_conv_tab_sorted
[use_meta
]->name
);
1673 g_string_append_c (s
, '-');
1676 if (mod
& KEY_M_CTRL
)
1678 /* non printeble chars like a CTRL-[A..Z] */
1682 if (lookup_keycode (KEY_M_CTRL
, &idx
))
1685 g_string_append (s
, key_conv_tab_sorted
[use_ctrl
]->name
);
1686 g_string_append_c (s
, '-');
1689 if (mod
& KEY_M_SHIFT
)
1691 if (lookup_keycode (KEY_M_ALT
, &idx
))
1695 g_string_append_c (s
, (gchar
) g_ascii_toupper ((gchar
) k
));
1698 g_string_append (s
, key_conv_tab_sorted
[use_shift
]->name
);
1699 g_string_append_c (s
, '-');
1700 g_string_append (s
, key_conv_tab_sorted
[key_idx
]->name
);
1706 if ((k
>= 'A') || (key_idx
< 0) || (key_conv_tab_sorted
[key_idx
]->name
== NULL
))
1707 g_string_append_c (s
, (gchar
) k
);
1709 g_string_append (s
, key_conv_tab_sorted
[key_idx
]->name
);
1711 else if ((key_idx
!= -1) && (key_conv_tab_sorted
[key_idx
]->name
!= NULL
))
1712 g_string_append (s
, key_conv_tab_sorted
[key_idx
]->name
);
1714 g_string_append_c (s
, (gchar
) keycode
);
1717 return g_string_free (s
, s
->len
== 0);
1720 /* --------------------------------------------------------------------------------------------- */
1722 * Return TRUE on success, FALSE on error.
1723 * An error happens if SEQ is a beginning of an existing longer sequence.
1727 define_sequence (int code
, const char *seq
, int action
)
1731 if (strlen (seq
) > SEQ_BUFFER_LEN
- 1)
1734 for (base
= keys
; (base
!= NULL
) && (*seq
!= '\0');)
1735 if (*seq
== base
->ch
)
1737 if (base
->child
== 0)
1739 if (*(seq
+ 1) != '\0')
1740 base
->child
= create_sequence (seq
+ 1, code
, action
);
1743 /* The sequence matches an existing one. */
1745 base
->action
= action
;
1759 base
->next
= create_sequence (seq
, code
, action
);
1766 /* Attempt to redefine a sequence with a shorter sequence. */
1770 keys
= create_sequence (seq
, code
, action
);
1774 /* --------------------------------------------------------------------------------------------- */
1776 * Check if we are idle, i.e. there are no pending keyboard or mouse
1777 * events. Return 1 is idle, 0 is there are pending events.
1784 struct timeval time_out
;
1786 FD_ZERO (&select_set
);
1787 FD_SET (input_fd
, &select_set
);
1790 if (mouse_enabled
&& (use_mouse_p
== MOUSE_GPM
) && (gpm_fd
> 0))
1792 FD_SET (gpm_fd
, &select_set
);
1793 maxfdp
= max (maxfdp
, gpm_fd
);
1796 time_out
.tv_sec
= 0;
1797 time_out
.tv_usec
= 0;
1798 return (select (maxfdp
+ 1, &select_set
, 0, 0, &time_out
) <= 0);
1801 /* --------------------------------------------------------------------------------------------- */
1804 get_key_code (int no_delay
)
1807 static key_def
*this = NULL
, *parent
;
1808 static struct timeval esctime
= { -1, -1 };
1809 static int lastnodelay
= -1;
1811 if (no_delay
!= lastnodelay
)
1814 lastnodelay
= no_delay
;
1818 if (pending_keys
!= NULL
)
1822 m
= parse_extended_mouse_coordinates ();
1825 pending_keys
= seq_append
= NULL
;
1827 return MCKEY_EXTENDED_MOUSE
;
1831 int d
= *pending_keys
++;
1833 if (*pending_keys
== 0)
1835 pending_keys
= NULL
;
1838 if ((d
== ESC_CHAR
) && (pending_keys
!= NULL
))
1840 d
= ALT (*pending_keys
++);
1843 if ((d
> 127 && d
< 256) && use_8th_bit_as_meta
)
1846 return correct_key_code (d
);
1848 /* else if (m == 0), just let it continue */
1855 c
= tty_lowlevel_getch ();
1856 #if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE)
1857 if (c
== KEY_RESIZE
)
1858 goto nodelay_try_again
;
1862 tty_nodelay (FALSE
);
1865 if (this != NULL
&& parent
!= NULL
&& parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
)
1867 struct timeval current
, time_out
;
1869 if (esctime
.tv_sec
== -1)
1872 time_out
.tv_sec
= old_esc_mode_timeout
/ 1000000 + esctime
.tv_sec
;
1873 time_out
.tv_usec
= old_esc_mode_timeout
% 1000000 + esctime
.tv_usec
;
1874 if (time_out
.tv_usec
> 1000000)
1876 time_out
.tv_usec
-= 1000000;
1879 if (current
.tv_sec
< time_out
.tv_sec
)
1881 if (current
.tv_sec
== time_out
.tv_sec
&& current
.tv_usec
< time_out
.tv_usec
)
1884 pending_keys
= seq_append
= NULL
;
1892 /* Maybe we got an incomplete match.
1893 This we do only in delay mode, since otherwise
1894 tty_lowlevel_getch can return -1 at any time. */
1895 if (seq_append
!= NULL
)
1897 pending_keys
= seq_buffer
;
1904 /* Search the key on the root */
1905 if (!no_delay
|| this == NULL
)
1910 if ((c
> 127 && c
< 256) && use_8th_bit_as_meta
)
1914 /* The first sequence defined starts with esc */
1919 while (this != NULL
)
1927 pending_keys
= seq_buffer
;
1932 if (parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
)
1939 /* Shouldn't happen */
1940 fputs ("Internal error\n", stderr
);
1941 exit (EXIT_FAILURE
);
1943 goto nodelay_try_again
;
1945 esctime
.tv_sec
= -1;
1946 c
= xgetch_second ();
1949 pending_keys
= seq_append
= NULL
;
1957 goto nodelay_try_again
;
1958 c
= tty_lowlevel_getch ();
1963 /* We got a complete match, return and reset search */
1966 pending_keys
= seq_append
= NULL
;
1969 return correct_key_code (code
);
1974 if (this->next
!= NULL
)
1978 if ((parent
!= NULL
) && (parent
->action
== MCKEY_ESCAPE
))
1980 /* Convert escape-digits to F-keys */
1981 if (g_ascii_isdigit (c
))
1982 c
= KEY_F (c
- '0');
1988 pending_keys
= seq_append
= NULL
;
1990 return correct_key_code (c
);
1992 /* Did not find a match or {c} was changed in the if above,
1993 so we have to return everything we had skipped
1996 pending_keys
= seq_buffer
;
2002 return correct_key_code (c
);
2005 /* --------------------------------------------------------------------------------------------- */
2006 /* Returns a character read from stdin with appropriate interpretation */
2007 /* Also takes care of generated mouse events */
2008 /* Returns EV_MOUSE if it is a mouse event */
2009 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
2012 tty_get_event (struct Gpm_Event
*event
, gboolean redo_event
, gboolean block
)
2015 static int flag
= 0; /* Return value from select */
2017 static struct Gpm_Event ev
; /* Mouse event */
2019 struct timeval time_out
;
2020 struct timeval
*time_addr
= NULL
;
2021 static int dirty
= 3;
2023 if ((dirty
== 3) || is_idle ())
2031 vfs_timeout_handler ();
2033 /* Ok, we use (event->x < 0) to signal that the event does not contain
2034 a suitable position for the mouse, so we can't use show_mouse_pointer
2039 show_mouse_pointer (event
->x
, event
->y
);
2044 /* Repeat if using mouse */
2045 while (pending_keys
== NULL
)
2050 FD_ZERO (&select_set
);
2051 FD_SET (input_fd
, &select_set
);
2052 maxfdp
= max (add_selects (&select_set
), input_fd
);
2055 if (mouse_enabled
&& (use_mouse_p
== MOUSE_GPM
))
2059 /* Connection to gpm broken, possibly gpm has died */
2060 mouse_enabled
= FALSE
;
2061 use_mouse_p
= MOUSE_NONE
;
2065 FD_SET (gpm_fd
, &select_set
);
2066 maxfdp
= max (maxfdp
, gpm_fd
);
2072 time_out
.tv_usec
= mou_auto_repeat
* 1000;
2073 time_out
.tv_sec
= 0;
2075 time_addr
= &time_out
;
2081 seconds
= vfs_timeouts ();
2086 /* the timeout could be improved and actually be
2087 * the number of seconds until the next vfs entry
2088 * timeouts in the stamp list.
2091 time_out
.tv_sec
= seconds
;
2092 time_out
.tv_usec
= 0;
2093 time_addr
= &time_out
;
2097 if (!block
|| mc_global
.tty
.winch_flag
)
2099 time_addr
= &time_out
;
2100 time_out
.tv_sec
= 0;
2101 time_out
.tv_usec
= 0;
2104 tty_enable_interrupt_key ();
2105 flag
= select (maxfdp
+ 1, &select_set
, NULL
, NULL
, time_addr
);
2106 tty_disable_interrupt_key ();
2108 /* select timed out: it could be for any of the following reasons:
2109 * redo_event -> it was because of the MOU_REPEAT handler
2110 * !block -> we did not block in the select call
2111 * else -> 10 second timeout to check the vfs status.
2117 if (!block
|| mc_global
.tty
.winch_flag
)
2119 vfs_timeout_handler ();
2121 if (flag
== -1 && errno
== EINTR
)
2124 check_selects (&select_set
);
2126 if (FD_ISSET (input_fd
, &select_set
))
2129 if (mouse_enabled
&& use_mouse_p
== MOUSE_GPM
2130 && gpm_fd
> 0 && FD_ISSET (gpm_fd
, &select_set
))
2137 #endif /* !HAVE_LIBGPM */
2141 flag
= is_wintouched (stdscr
);
2142 untouchwin (stdscr
);
2143 #endif /* !HAVE_SLANG */
2144 c
= block
? getch_with_delay () : get_key_code (1);
2148 tty_touch_screen ();
2149 #endif /* !HAVE_SLANG */
2151 if (mouse_enabled
&& (c
== MCKEY_MOUSE
2154 #endif /* KEY_MOUSE */
2155 || c
== MCKEY_EXTENDED_MOUSE
))
2158 /* In case of extended coordinates, mouse_btn, mouse_x and mouse_y are already filled in. */
2159 if (c
!= MCKEY_EXTENDED_MOUSE
)
2161 /* Variable btn has following meaning: */
2162 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
2163 mouse_btn
= tty_lowlevel_getch () - 32;
2164 /* Coordinates are 33-based */
2165 /* Transform them to 1-based */
2166 mouse_x
= tty_lowlevel_getch () - 32;
2167 mouse_y
= tty_lowlevel_getch () - 32;
2169 xmouse_get_event (event
);
2170 return (event
->type
!= 0) ? EV_MOUSE
: EV_NONE
;
2176 /* --------------------------------------------------------------------------------------------- */
2177 /* Returns a key press, mouse events are discarded */
2186 while ((key
= tty_get_event (&ev
, FALSE
, TRUE
)) == EV_NONE
);
2190 /* --------------------------------------------------------------------------------------------- */
2195 /* LEARN_TIMEOUT in usec */
2196 #define LEARN_TIMEOUT 200000
2199 struct timeval endtime
;
2200 struct timeval time_out
;
2205 tty_keypad (FALSE
); /* disable intepreting keys by ncurses */
2206 c
= tty_lowlevel_getch ();
2208 c
= tty_lowlevel_getch (); /* Sanity check, should be unnecessary */
2209 learn_store_key (buffer
, &p
, c
);
2211 endtime
.tv_usec
+= LEARN_TIMEOUT
;
2212 if (endtime
.tv_usec
> 1000000)
2214 endtime
.tv_usec
-= 1000000;
2220 while ((c
= tty_lowlevel_getch ()) == -1)
2222 GET_TIME (time_out
);
2223 time_out
.tv_usec
= endtime
.tv_usec
- time_out
.tv_usec
;
2224 if (time_out
.tv_usec
< 0)
2226 time_out
.tv_sec
= endtime
.tv_sec
- time_out
.tv_sec
;
2227 if (time_out
.tv_sec
>= 0 && time_out
.tv_usec
> 0)
2229 FD_ZERO (&Read_FD_Set
);
2230 FD_SET (input_fd
, &Read_FD_Set
);
2231 select (input_fd
+ 1, &Read_FD_Set
, NULL
, NULL
, &time_out
);
2238 learn_store_key (buffer
, &p
, c
);
2241 tty_nodelay (FALSE
);
2243 return g_strdup (buffer
);
2244 #undef LEARN_TIMEOUT
2247 /* --------------------------------------------------------------------------------------------- */
2248 /* xterm and linux console only: set keypad to numeric or application
2249 mode. Only in application keypad mode it's possible to distinguish
2250 the '+' key and the '+' on the keypad ('*' and '-' ditto) */
2253 numeric_keypad_mode (void)
2255 if (mc_global
.tty
.console_flag
!= '\0' || mc_global
.tty
.xterm_flag
)
2257 fputs (ESC_STR
">", stdout
);
2262 /* --------------------------------------------------------------------------------------------- */
2265 application_keypad_mode (void)
2267 if (mc_global
.tty
.console_flag
!= '\0' || mc_global
.tty
.xterm_flag
)
2269 fputs (ESC_STR
"=", stdout
);
2274 /* --------------------------------------------------------------------------------------------- */