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_BTAB
, "backtab", N_("Back Tabulation S-tab"), "Shift-Tab"},
129 {KEY_KP_ADD
, "kpplus", N_("+ on keypad"), "+"},
130 {KEY_KP_SUBTRACT
, "kpminus", N_("- on keypad"), "-"},
131 {(int) '/', "kpslash", N_("Slash on keypad"), "/"},
132 {KEY_KP_MULTIPLY
, "kpasterisk", N_("* on keypad"), "*"},
134 /* From here on, these won't be shown in Learn keys (no space) */
135 {ESC_CHAR
, "escape", N_("Escape key"), "Esc"},
136 {KEY_LEFT
, "kpleft", N_("Left arrow keypad"), "Left"},
137 {KEY_RIGHT
, "kpright", N_("Right arrow keypad"), "Right"},
138 {KEY_UP
, "kpup", N_("Up arrow keypad"), "Up"},
139 {KEY_DOWN
, "kpdown", N_("Down arrow keypad"), "Down"},
140 {KEY_HOME
, "kphome", N_("Home on keypad"), "Home"},
141 {KEY_END
, "kpend", N_("End on keypad"), "End"},
142 {KEY_NPAGE
, "kpnpage", N_("Page Down keypad"), "PgDn"},
143 {KEY_PPAGE
, "kpppage", N_("Page Up keypad"), "PgUp"},
144 {KEY_IC
, "kpinsert", N_("Insert on keypad"), "Ins"},
145 {KEY_DC
, "kpdelete", N_("Delete on keypad"), "Del"},
146 {(int) '\n', "kpenter", N_("Enter on keypad"), "Enter"},
147 {KEY_F (21), "f21", N_("Function key 21"), "F21"},
148 {KEY_F (22), "f22", N_("Function key 22"), "F22"},
149 {KEY_F (23), "f23", N_("Function key 23"), "F23"},
150 {KEY_F (24), "f24", N_("Function key 24"), "F24"},
151 {KEY_A1
, "a1", N_("A1 key"), "A1"},
152 {KEY_C1
, "c1", N_("C1 key"), "C1"},
154 /* Alternative label */
155 {ESC_CHAR
, "esc", N_("Escape key"), "Esc"},
156 {KEY_BACKSPACE
, "bs", N_("Backspace key"), "Bakspace"},
157 {KEY_IC
, "ins", N_("Insert key"), "Ins"},
158 {KEY_DC
, "del", N_("Delete key"), "Del"},
159 {(int) '+', "plus", N_("Plus"), "+"},
160 {(int) '-', "minus", N_("Minus"), "-"},
161 {(int) '*', "asterisk", N_("Asterisk"), "*"},
162 {(int) '.', "dot", N_("Dot"), "."},
163 {(int) '<', "lt", N_("Less than"), "<"},
164 {(int) '>', "gt", N_("Great than"), ">"},
165 {(int) '=', "equal", N_("Equal"), "="},
166 {(int) ',', "comma", N_("Comma"), ","},
167 {(int) '\'', "apostrophe", N_("Apostrophe"), "\'"},
168 {(int) ':', "colon", N_("Colon"), ":"},
169 {(int) '!', "exclamation", N_("Exclamation mark"), "!"},
170 {(int) '?', "question", N_("Question mark"), "?"},
171 {(int) '&', "ampersand", N_("Ampersand"), "&"},
172 {(int) '$', "dollar", N_("Dollar sign"), "$"},
173 {(int) '"', "quota", N_("Quotation mark"), "\""},
174 {(int) '%', "percent", N_("Percent sign"), "%"},
175 {(int) '^', "caret", N_("Caret"), "^"},
176 {(int) '~', "tilda", N_("Tilda"), "~"},
177 {(int) '`', "prime", N_("Prime"), "`"},
178 {(int) '_', "underline", N_("Underline"), "_"},
179 {(int) '_', "understrike", N_("Understrike"), "_"},
180 {(int) '|', "pipe", N_("Pipe"), "|"},
181 {(int) '(', "lparenthesis", N_("Left parenthesis"), "("},
182 {(int) ')', "rparenthesis", N_("Right parenthesis"), ")"},
183 {(int) '[', "lbracket", N_("Left bracket"), "["},
184 {(int) ']', "rbracket", N_("Right bracket"), "]"},
185 {(int) '{', "lbrace", N_("Left brace"), "{"},
186 {(int) '}', "rbrace", N_("Right brace"), "}"},
187 {(int) '\n', "enter", N_("Enter"), "Enter"},
188 {(int) '\t', "tab", N_("Tab key"), "Tab"},
189 {(int) ' ', "space", N_("Space key"), "Space"},
190 {(int) '/', "slash", N_("Slash key"), "/"},
191 {(int) '\\', "backslash", N_("Backslash key"), "\\"},
192 {(int) '#', "number", N_("Number sign #"), "#"},
193 {(int) '#', "hash", N_("Number sign #"), "#"},
194 /* TRANSLATORS: Please translate as in "at sign" (@). */
195 {(int) '@', "at", N_("At sign"), "@"},
198 {KEY_M_CTRL
, "control", N_("Ctrl"), "C"},
199 {KEY_M_CTRL
, "ctrl", N_("Ctrl"), "C"},
200 {KEY_M_ALT
, "meta", N_("Alt"), "M"},
201 {KEY_M_ALT
, "alt", N_("Alt"), "M"},
202 {KEY_M_ALT
, "ralt", N_("Alt"), "M"},
203 {KEY_M_SHIFT
, "shift", N_("Shift"), "S"},
205 {0, NULL
, NULL
, NULL
}
208 /*** file scope macro definitions ****************************************************************/
210 #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *) NULL))
211 #define DIF_TIME(t1, t2) ((t2.tv_sec - t1.tv_sec) * 1000 + (t2.tv_usec - t1.tv_usec)/1000)
213 /* The maximum sequence length (32 + null terminator) */
214 #define SEQ_BUFFER_LEN 33
216 /*** file scope type declarations ****************************************************************/
218 /* Linux console keyboard modifiers */
221 SHIFT_PRESSED
= (1 << 0),
222 ALTR_PRESSED
= (1 << 1),
223 CONTROL_PRESSED
= (1 << 2),
224 ALTL_PRESSED
= (1 << 3)
227 typedef struct key_def
229 char ch
; /* Holds the matching char code */
230 int code
; /* The code returned, valid if child == NULL */
231 struct key_def
*next
;
232 struct key_def
*child
; /* sequence continuation */
233 int action
; /* optional action to be done. Now used only
234 to mark that we are just after the first
245 /* File descriptor monitoring add/remove routines */
246 typedef struct SelectList
251 struct SelectList
*next
;
254 typedef enum KeySortType
262 typedef int (*ph_dv_f
) (void *, void *);
263 typedef int (*ph_ov_f
) (void *);
264 typedef int (*ph_pqc_f
) (unsigned short, PhCursorInfo_t
*);
267 /*** file scope variables ************************************************************************/
269 static key_define_t mc_default_keys
[] = {
270 {ESC_CHAR
, ESC_STR
, MCKEY_ESCAPE
},
271 {ESC_CHAR
, ESC_STR ESC_STR
, MCKEY_NOACTION
},
272 {0, NULL
, MCKEY_NOACTION
},
275 /* Broken terminfo and termcap databases on xterminals */
276 static key_define_t xterm_key_defines
[] = {
277 {KEY_F (1), ESC_STR
"OP", MCKEY_NOACTION
},
278 {KEY_F (2), ESC_STR
"OQ", MCKEY_NOACTION
},
279 {KEY_F (3), ESC_STR
"OR", MCKEY_NOACTION
},
280 {KEY_F (4), ESC_STR
"OS", MCKEY_NOACTION
},
281 {KEY_F (1), ESC_STR
"[11~", MCKEY_NOACTION
},
282 {KEY_F (2), ESC_STR
"[12~", MCKEY_NOACTION
},
283 {KEY_F (3), ESC_STR
"[13~", MCKEY_NOACTION
},
284 {KEY_F (4), ESC_STR
"[14~", MCKEY_NOACTION
},
285 {KEY_F (5), ESC_STR
"[15~", MCKEY_NOACTION
},
286 {KEY_F (6), ESC_STR
"[17~", MCKEY_NOACTION
},
287 {KEY_F (7), ESC_STR
"[18~", MCKEY_NOACTION
},
288 {KEY_F (8), ESC_STR
"[19~", MCKEY_NOACTION
},
289 {KEY_F (9), ESC_STR
"[20~", MCKEY_NOACTION
},
290 {KEY_F (10), ESC_STR
"[21~", MCKEY_NOACTION
},
292 /* old xterm Shift-arrows */
293 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"O2A", MCKEY_NOACTION
},
294 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"O2B", MCKEY_NOACTION
},
295 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"O2C", MCKEY_NOACTION
},
296 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"O2D", MCKEY_NOACTION
},
298 /* new xterm Shift-arrows */
299 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"[1;2A", MCKEY_NOACTION
},
300 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"[1;2B", MCKEY_NOACTION
},
301 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"[1;2C", MCKEY_NOACTION
},
302 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"[1;2D", MCKEY_NOACTION
},
304 /* more xterm keys with modifiers */
305 {KEY_M_CTRL
| KEY_PPAGE
, ESC_STR
"[5;5~", MCKEY_NOACTION
},
306 {KEY_M_CTRL
| KEY_NPAGE
, ESC_STR
"[6;5~", MCKEY_NOACTION
},
307 {KEY_M_CTRL
| KEY_IC
, ESC_STR
"[2;5~", MCKEY_NOACTION
},
308 {KEY_M_CTRL
| KEY_DC
, ESC_STR
"[3;5~", MCKEY_NOACTION
},
309 {KEY_M_CTRL
| KEY_HOME
, ESC_STR
"[1;5H", MCKEY_NOACTION
},
310 {KEY_M_CTRL
| KEY_END
, ESC_STR
"[1;5F", MCKEY_NOACTION
},
311 {KEY_M_SHIFT
| KEY_HOME
, ESC_STR
"[1;2H", MCKEY_NOACTION
},
312 {KEY_M_SHIFT
| KEY_END
, ESC_STR
"[1;2F", MCKEY_NOACTION
},
313 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"[1;5A", MCKEY_NOACTION
},
314 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[1;5B", MCKEY_NOACTION
},
315 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[1;5C", MCKEY_NOACTION
},
316 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[1;5D", MCKEY_NOACTION
},
317 {KEY_M_SHIFT
| KEY_IC
, ESC_STR
"[2;2~", MCKEY_NOACTION
},
318 {KEY_M_SHIFT
| KEY_DC
, ESC_STR
"[3;2~", MCKEY_NOACTION
},
319 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"[1;6A", MCKEY_NOACTION
},
320 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[1;6B", MCKEY_NOACTION
},
321 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[1;6C", MCKEY_NOACTION
},
322 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[1;6D", MCKEY_NOACTION
},
325 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"[[1;6A", MCKEY_NOACTION
},
326 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[[1;6B", MCKEY_NOACTION
},
327 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[[1;6C", MCKEY_NOACTION
},
328 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[[1;6D", MCKEY_NOACTION
},
330 /* putty alt-arrow keys */
331 /* removed as source esc esc esc trouble */
333 { KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "OA", MCKEY_NOACTION },
334 { KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "OB", MCKEY_NOACTION },
335 { KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "OC", MCKEY_NOACTION },
336 { KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "OD", MCKEY_NOACTION },
337 { KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[5~", MCKEY_NOACTION },
338 { KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[6~", MCKEY_NOACTION },
339 { KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1~", MCKEY_NOACTION },
340 { KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[4~", MCKEY_NOACTION },
342 { KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "[1;2A", MCKEY_NOACTION },
343 { KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "[1;2B", MCKEY_NOACTION },
344 { KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "[1;2C", MCKEY_NOACTION },
345 { KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "[1;2D", MCKEY_NOACTION },
347 { KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[[5;5~", MCKEY_NOACTION },
348 { KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[[6;5~", MCKEY_NOACTION },
349 { KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1;5H", MCKEY_NOACTION },
350 { KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[1;5F", MCKEY_NOACTION },
352 /* xterm alt-arrow keys */
353 {KEY_M_ALT
| KEY_UP
, ESC_STR
"[1;3A", MCKEY_NOACTION
},
354 {KEY_M_ALT
| KEY_DOWN
, ESC_STR
"[1;3B", MCKEY_NOACTION
},
355 {KEY_M_ALT
| KEY_RIGHT
, ESC_STR
"[1;3C", MCKEY_NOACTION
},
356 {KEY_M_ALT
| KEY_LEFT
, ESC_STR
"[1;3D", MCKEY_NOACTION
},
357 {KEY_M_ALT
| KEY_PPAGE
, ESC_STR
"[5;3~", MCKEY_NOACTION
},
358 {KEY_M_ALT
| KEY_NPAGE
, ESC_STR
"[6;3~", MCKEY_NOACTION
},
359 {KEY_M_ALT
| KEY_HOME
, ESC_STR
"[1~", MCKEY_NOACTION
},
360 {KEY_M_ALT
| KEY_END
, ESC_STR
"[4~", MCKEY_NOACTION
},
361 {KEY_M_CTRL
| KEY_M_ALT
| KEY_UP
, ESC_STR
"[1;7A", MCKEY_NOACTION
},
362 {KEY_M_CTRL
| KEY_M_ALT
| KEY_DOWN
, ESC_STR
"[1;7B", MCKEY_NOACTION
},
363 {KEY_M_CTRL
| KEY_M_ALT
| KEY_RIGHT
, ESC_STR
"[1;7C", MCKEY_NOACTION
},
364 {KEY_M_CTRL
| KEY_M_ALT
| KEY_LEFT
, ESC_STR
"[1;7D", MCKEY_NOACTION
},
365 {KEY_M_CTRL
| KEY_M_ALT
| KEY_PPAGE
, ESC_STR
"[5;7~", MCKEY_NOACTION
},
366 {KEY_M_CTRL
| KEY_M_ALT
| KEY_NPAGE
, ESC_STR
"[6;7~", MCKEY_NOACTION
},
367 {KEY_M_CTRL
| KEY_M_ALT
| KEY_HOME
, ESC_STR
"OH", MCKEY_NOACTION
},
368 {KEY_M_CTRL
| KEY_M_ALT
| KEY_END
, ESC_STR
"OF", MCKEY_NOACTION
},
370 /* rxvt keys with modifiers */
371 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"[a", MCKEY_NOACTION
},
372 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"[b", MCKEY_NOACTION
},
373 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"[c", MCKEY_NOACTION
},
374 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"[d", MCKEY_NOACTION
},
375 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"Oa", MCKEY_NOACTION
},
376 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"Ob", MCKEY_NOACTION
},
377 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"Oc", MCKEY_NOACTION
},
378 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"Od", MCKEY_NOACTION
},
379 {KEY_M_CTRL
| KEY_PPAGE
, ESC_STR
"[5^", MCKEY_NOACTION
},
380 {KEY_M_CTRL
| KEY_NPAGE
, ESC_STR
"[6^", MCKEY_NOACTION
},
381 {KEY_M_CTRL
| KEY_HOME
, ESC_STR
"[7^", MCKEY_NOACTION
},
382 {KEY_M_CTRL
| KEY_END
, ESC_STR
"[8^", MCKEY_NOACTION
},
383 {KEY_M_SHIFT
| KEY_HOME
, ESC_STR
"[7$", MCKEY_NOACTION
},
384 {KEY_M_SHIFT
| KEY_END
, ESC_STR
"[8$", MCKEY_NOACTION
},
385 {KEY_M_CTRL
| KEY_IC
, ESC_STR
"[2^", MCKEY_NOACTION
},
386 {KEY_M_CTRL
| KEY_DC
, ESC_STR
"[3^", MCKEY_NOACTION
},
387 {KEY_M_SHIFT
| KEY_DC
, ESC_STR
"[3$", MCKEY_NOACTION
},
389 /* konsole keys with modifiers */
390 {KEY_M_SHIFT
| KEY_HOME
, ESC_STR
"O2H", MCKEY_NOACTION
},
391 {KEY_M_SHIFT
| KEY_END
, ESC_STR
"O2F", MCKEY_NOACTION
},
394 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"[2A", MCKEY_NOACTION
},
395 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"[2B", MCKEY_NOACTION
},
396 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"[2C", MCKEY_NOACTION
},
397 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"[2D", MCKEY_NOACTION
},
398 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"[5A", MCKEY_NOACTION
},
399 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[5B", MCKEY_NOACTION
},
400 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[5C", MCKEY_NOACTION
},
401 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[5D", MCKEY_NOACTION
},
402 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"[6A", MCKEY_NOACTION
},
403 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[6B", MCKEY_NOACTION
},
404 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[6C", MCKEY_NOACTION
},
405 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[6D", MCKEY_NOACTION
},
407 /* gnome-terminal - application mode */
408 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"O5A", MCKEY_NOACTION
},
409 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"O5B", MCKEY_NOACTION
},
410 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"O5C", MCKEY_NOACTION
},
411 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"O5D", MCKEY_NOACTION
},
412 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"O6A", MCKEY_NOACTION
},
413 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"O6B", MCKEY_NOACTION
},
414 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"O6C", MCKEY_NOACTION
},
415 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"O6D", MCKEY_NOACTION
},
418 {KEY_M_SHIFT
| KEY_PPAGE
, ESC_STR
"[5;2~", MCKEY_NOACTION
},
419 {KEY_M_SHIFT
| KEY_NPAGE
, ESC_STR
"[6;2~", MCKEY_NOACTION
},
422 {KEY_M_SHIFT
| KEY_PPAGE
, ESC_STR
"[[5;53~", MCKEY_NOACTION
},
423 {KEY_M_SHIFT
| KEY_NPAGE
, ESC_STR
"[[6;53~", MCKEY_NOACTION
},
426 {KEY_IC
, ESC_STR
"Op", MCKEY_NOACTION
},
427 {KEY_DC
, ESC_STR
"On", MCKEY_NOACTION
},
428 {'/', ESC_STR
"Oo", MCKEY_NOACTION
},
429 {'\n', ESC_STR
"OM", MCKEY_NOACTION
},
431 {0, NULL
, MCKEY_NOACTION
},
434 /* qansi-m terminals have a much more key combinatios,
435 which are undefined in termcap/terminfo */
436 static key_define_t qansi_key_defines
[] = {
437 /* qansi-m terminal */
438 {KEY_M_CTRL
| KEY_NPAGE
, ESC_STR
"[u", MCKEY_NOACTION
}, /* Ctrl-PgDown */
439 {KEY_M_CTRL
| KEY_PPAGE
, ESC_STR
"[v", MCKEY_NOACTION
}, /* Ctrl-PgUp */
440 {KEY_M_CTRL
| KEY_HOME
, ESC_STR
"[h", MCKEY_NOACTION
}, /* Ctrl-Home */
441 {KEY_M_CTRL
| KEY_END
, ESC_STR
"[y", MCKEY_NOACTION
}, /* Ctrl-End */
442 {KEY_M_CTRL
| KEY_IC
, ESC_STR
"[`", MCKEY_NOACTION
}, /* Ctrl-Insert */
443 {KEY_M_CTRL
| KEY_DC
, ESC_STR
"[p", MCKEY_NOACTION
}, /* Ctrl-Delete */
444 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[d", MCKEY_NOACTION
}, /* Ctrl-Left */
445 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[c", MCKEY_NOACTION
}, /* Ctrl-Right */
446 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[b", MCKEY_NOACTION
}, /* Ctrl-Down */
447 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"[a", MCKEY_NOACTION
}, /* Ctrl-Up */
448 {KEY_M_CTRL
| KEY_KP_ADD
, ESC_STR
"[s", MCKEY_NOACTION
}, /* Ctrl-Gr-Plus */
449 {KEY_M_CTRL
| KEY_KP_SUBTRACT
, ESC_STR
"[t", MCKEY_NOACTION
}, /* Ctrl-Gr-Minus */
450 {KEY_M_CTRL
| '\t', ESC_STR
"[z", MCKEY_NOACTION
}, /* Ctrl-Tab */
451 {KEY_M_SHIFT
| '\t', ESC_STR
"[Z", MCKEY_NOACTION
}, /* Shift-Tab */
452 {KEY_M_CTRL
| KEY_F (1), ESC_STR
"[1~", MCKEY_NOACTION
}, /* Ctrl-F1 */
453 {KEY_M_CTRL
| KEY_F (2), ESC_STR
"[2~", MCKEY_NOACTION
}, /* Ctrl-F2 */
454 {KEY_M_CTRL
| KEY_F (3), ESC_STR
"[3~", MCKEY_NOACTION
}, /* Ctrl-F3 */
455 {KEY_M_CTRL
| KEY_F (4), ESC_STR
"[4~", MCKEY_NOACTION
}, /* Ctrl-F4 */
456 {KEY_M_CTRL
| KEY_F (5), ESC_STR
"[5~", MCKEY_NOACTION
}, /* Ctrl-F5 */
457 {KEY_M_CTRL
| KEY_F (6), ESC_STR
"[6~", MCKEY_NOACTION
}, /* Ctrl-F6 */
458 {KEY_M_CTRL
| KEY_F (7), ESC_STR
"[7~", MCKEY_NOACTION
}, /* Ctrl-F7 */
459 {KEY_M_CTRL
| KEY_F (8), ESC_STR
"[8~", MCKEY_NOACTION
}, /* Ctrl-F8 */
460 {KEY_M_CTRL
| KEY_F (9), ESC_STR
"[9~", MCKEY_NOACTION
}, /* Ctrl-F9 */
461 {KEY_M_CTRL
| KEY_F (10), ESC_STR
"[10~", MCKEY_NOACTION
}, /* Ctrl-F10 */
462 {KEY_M_CTRL
| KEY_F (11), ESC_STR
"[11~", MCKEY_NOACTION
}, /* Ctrl-F11 */
463 {KEY_M_CTRL
| KEY_F (12), ESC_STR
"[12~", MCKEY_NOACTION
}, /* Ctrl-F12 */
464 {KEY_M_ALT
| KEY_F (1), ESC_STR
"[17~", MCKEY_NOACTION
}, /* Alt-F1 */
465 {KEY_M_ALT
| KEY_F (2), ESC_STR
"[18~", MCKEY_NOACTION
}, /* Alt-F2 */
466 {KEY_M_ALT
| KEY_F (3), ESC_STR
"[19~", MCKEY_NOACTION
}, /* Alt-F3 */
467 {KEY_M_ALT
| KEY_F (4), ESC_STR
"[20~", MCKEY_NOACTION
}, /* Alt-F4 */
468 {KEY_M_ALT
| KEY_F (5), ESC_STR
"[21~", MCKEY_NOACTION
}, /* Alt-F5 */
469 {KEY_M_ALT
| KEY_F (6), ESC_STR
"[22~", MCKEY_NOACTION
}, /* Alt-F6 */
470 {KEY_M_ALT
| KEY_F (7), ESC_STR
"[23~", MCKEY_NOACTION
}, /* Alt-F7 */
471 {KEY_M_ALT
| KEY_F (8), ESC_STR
"[24~", MCKEY_NOACTION
}, /* Alt-F8 */
472 {KEY_M_ALT
| KEY_F (9), ESC_STR
"[25~", MCKEY_NOACTION
}, /* Alt-F9 */
473 {KEY_M_ALT
| KEY_F (10), ESC_STR
"[26~", MCKEY_NOACTION
}, /* Alt-F10 */
474 {KEY_M_ALT
| KEY_F (11), ESC_STR
"[27~", MCKEY_NOACTION
}, /* Alt-F11 */
475 {KEY_M_ALT
| KEY_F (12), ESC_STR
"[28~", MCKEY_NOACTION
}, /* Alt-F12 */
476 {KEY_M_ALT
| 'a', ESC_STR
"Na", MCKEY_NOACTION
}, /* Alt-a */
477 {KEY_M_ALT
| 'b', ESC_STR
"Nb", MCKEY_NOACTION
}, /* Alt-b */
478 {KEY_M_ALT
| 'c', ESC_STR
"Nc", MCKEY_NOACTION
}, /* Alt-c */
479 {KEY_M_ALT
| 'd', ESC_STR
"Nd", MCKEY_NOACTION
}, /* Alt-d */
480 {KEY_M_ALT
| 'e', ESC_STR
"Ne", MCKEY_NOACTION
}, /* Alt-e */
481 {KEY_M_ALT
| 'f', ESC_STR
"Nf", MCKEY_NOACTION
}, /* Alt-f */
482 {KEY_M_ALT
| 'g', ESC_STR
"Ng", MCKEY_NOACTION
}, /* Alt-g */
483 {KEY_M_ALT
| 'h', ESC_STR
"Nh", MCKEY_NOACTION
}, /* Alt-h */
484 {KEY_M_ALT
| 'i', ESC_STR
"Ni", MCKEY_NOACTION
}, /* Alt-i */
485 {KEY_M_ALT
| 'j', ESC_STR
"Nj", MCKEY_NOACTION
}, /* Alt-j */
486 {KEY_M_ALT
| 'k', ESC_STR
"Nk", MCKEY_NOACTION
}, /* Alt-k */
487 {KEY_M_ALT
| 'l', ESC_STR
"Nl", MCKEY_NOACTION
}, /* Alt-l */
488 {KEY_M_ALT
| 'm', ESC_STR
"Nm", MCKEY_NOACTION
}, /* Alt-m */
489 {KEY_M_ALT
| 'n', ESC_STR
"Nn", MCKEY_NOACTION
}, /* Alt-n */
490 {KEY_M_ALT
| 'o', ESC_STR
"No", MCKEY_NOACTION
}, /* Alt-o */
491 {KEY_M_ALT
| 'p', ESC_STR
"Np", MCKEY_NOACTION
}, /* Alt-p */
492 {KEY_M_ALT
| 'q', ESC_STR
"Nq", MCKEY_NOACTION
}, /* Alt-q */
493 {KEY_M_ALT
| 'r', ESC_STR
"Nr", MCKEY_NOACTION
}, /* Alt-r */
494 {KEY_M_ALT
| 's', ESC_STR
"Ns", MCKEY_NOACTION
}, /* Alt-s */
495 {KEY_M_ALT
| 't', ESC_STR
"Nt", MCKEY_NOACTION
}, /* Alt-t */
496 {KEY_M_ALT
| 'u', ESC_STR
"Nu", MCKEY_NOACTION
}, /* Alt-u */
497 {KEY_M_ALT
| 'v', ESC_STR
"Nv", MCKEY_NOACTION
}, /* Alt-v */
498 {KEY_M_ALT
| 'w', ESC_STR
"Nw", MCKEY_NOACTION
}, /* Alt-w */
499 {KEY_M_ALT
| 'x', ESC_STR
"Nx", MCKEY_NOACTION
}, /* Alt-x */
500 {KEY_M_ALT
| 'y', ESC_STR
"Ny", MCKEY_NOACTION
}, /* Alt-y */
501 {KEY_M_ALT
| 'z', ESC_STR
"Nz", MCKEY_NOACTION
}, /* Alt-z */
502 {KEY_KP_SUBTRACT
, ESC_STR
"[S", MCKEY_NOACTION
}, /* Gr-Minus */
503 {KEY_KP_ADD
, ESC_STR
"[T", MCKEY_NOACTION
}, /* Gr-Plus */
504 {0, NULL
, MCKEY_NOACTION
},
507 /* This holds all the key definitions */
508 static key_def
*keys
= NULL
;
511 static int disabled_channels
= 0; /* Disable channels checking */
513 static SelectList
*select_list
= NULL
;
515 static int seq_buffer
[SEQ_BUFFER_LEN
];
516 static int *seq_append
= NULL
;
518 static int *pending_keys
= NULL
;
520 static int mouse_btn
, mouse_x
, mouse_y
;
524 ph_ov_f ph_input_group
;
525 ph_pqc_f ph_query_cursor
;
528 #ifdef HAVE_TEXTMODE_X11_SUPPORT
529 static Display
*x11_display
;
530 static Window x11_window
;
531 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
533 static KeySortType has_been_sorted
= KEY_NOSORT
;
536 static const size_t key_conv_tab_size
= G_N_ELEMENTS (key_name_conv_tab
) - 1;
539 static const key_code_name_t
*key_conv_tab_sorted
[G_N_ELEMENTS (key_name_conv_tab
) - 1];
541 /*** file scope functions ************************************************************************/
542 /* --------------------------------------------------------------------------------------------- */
545 add_selects (fd_set
* select_set
)
549 if (disabled_channels
== 0)
553 for (p
= select_list
; p
!= NULL
; p
= p
->next
)
555 FD_SET (p
->fd
, select_set
);
564 /* --------------------------------------------------------------------------------------------- */
567 check_selects (fd_set
* select_set
)
569 if (disabled_channels
== 0)
578 for (p
= select_list
; p
; p
= p
->next
)
579 if (FD_ISSET (p
->fd
, select_set
))
581 FD_CLR (p
->fd
, select_set
);
582 (*p
->callback
) (p
->fd
, p
->info
);
591 /* --------------------------------------------------------------------------------------------- */
592 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
595 try_channels (int set_timeout
)
597 struct timeval time_out
;
598 static fd_set select_set
;
599 struct timeval
*timeptr
;
605 FD_ZERO (&select_set
);
606 FD_SET (input_fd
, &select_set
); /* Add stdin */
607 maxfdp
= max (add_selects (&select_set
), input_fd
);
613 time_out
.tv_usec
= 100000;
617 v
= select (maxfdp
+ 1, &select_set
, NULL
, NULL
, timeptr
);
620 check_selects (&select_set
);
621 if (FD_ISSET (input_fd
, &select_set
))
627 /* --------------------------------------------------------------------------------------------- */
630 create_sequence (const char *seq
, int code
, int action
)
632 key_def
*base
, *p
, *attach
;
634 for (base
= attach
= NULL
; *seq
; seq
++)
636 p
= g_new (key_def
, 1);
644 p
->child
= p
->next
= NULL
;
648 p
->action
= MCKEY_NOACTION
;
654 /* --------------------------------------------------------------------------------------------- */
657 define_sequences (const key_define_t
* kd
)
661 for (i
= 0; kd
[i
].code
!= 0; i
++)
662 define_sequence (kd
[i
].code
, kd
[i
].seq
, kd
[i
].action
);
665 /* --------------------------------------------------------------------------------------------- */
670 #ifdef HAVE_TEXTMODE_X11_SUPPORT
671 if (getenv ("DISPLAY") != NULL
&& !mc_global
.tty
.disable_x11
)
673 x11_display
= mc_XOpenDisplay (0);
675 if (x11_display
!= NULL
)
676 x11_window
= DefaultRootWindow (x11_display
);
678 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
681 /* --------------------------------------------------------------------------------------------- */
682 /* Workaround for System V Curses vt100 bug */
685 getch_with_delay (void)
689 /* This routine could be used on systems without mouse support,
690 so we need to do the select check :-( */
693 if (pending_keys
== NULL
)
696 /* Try to get a character */
697 c
= get_key_code (0);
700 /* Failed -> wait 0.1 secs and try again */
703 /* Success -> return the character */
707 /* --------------------------------------------------------------------------------------------- */
710 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;
718 /* Decode Xterm mouse information to a GPM style event */
720 /* There seems to be no way of knowing which button was released */
721 /* So we assume all the buttons were released */
727 if ((last_btn
& (GPM_B_UP
| GPM_B_DOWN
)) != 0)
729 /* FIXME: DIRTY HACK */
730 /* don't generate GPM_UP after mouse wheel */
731 /* need for menu event handling */
738 ev
->type
= GPM_UP
| (GPM_SINGLE
<< clicks
);
747 /* Bogus event, maybe mouse wheel */
753 if (btn
>= 32 && btn
<= 34)
762 if (tv1
.tv_sec
&& (DIF_TIME (tv1
, tv2
) < double_click_speed
))
773 ev
->buttons
= GPM_B_LEFT
;
776 ev
->buttons
= GPM_B_MIDDLE
;
779 ev
->buttons
= GPM_B_RIGHT
;
782 ev
->buttons
= GPM_B_UP
;
786 ev
->buttons
= GPM_B_DOWN
;
795 last_btn
= ev
->buttons
;
801 /* --------------------------------------------------------------------------------------------- */
803 * Get modifier state (shift, alt, ctrl) for the last key pressed.
804 * We are assuming that the state didn't change since the key press.
805 * This is only correct if get_modifier() is called very fast after
806 * the input was received, so that the user didn't release the
815 int mod_status
, shift_ext_status
;
816 static int in_photon
= 0;
817 static int ph_ig
= 0;
818 PhCursorInfo_t cursor_info
;
819 #endif /* __QNXNTO__ */
821 #ifdef HAVE_TEXTMODE_X11_SUPPORT
829 mc_XQueryPointer (x11_display
, x11_window
, &root
, &child
, &root_x
,
830 &root_y
, &win_x
, &win_y
, &mask
);
832 if (mask
& ShiftMask
)
833 result
|= KEY_M_SHIFT
;
834 if (mask
& ControlMask
)
835 result
|= KEY_M_CTRL
;
838 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
843 /* First time here, let's load Photon library and attach
846 if (getenv ("PHOTON2_PATH") != NULL
)
848 /* QNX 6.x has no support for RTLD_LAZY */
849 void *ph_handle
= dlopen ("/usr/lib/libph.so", RTLD_NOW
);
850 if (ph_handle
!= NULL
)
852 ph_attach
= (ph_dv_f
) dlsym (ph_handle
, "PhAttach");
853 ph_input_group
= (ph_ov_f
) dlsym (ph_handle
, "PhInputGroup");
854 ph_query_cursor
= (ph_pqc_f
) dlsym (ph_handle
, "PhQueryCursor");
855 if ((ph_attach
!= NULL
) && (ph_input_group
!= NULL
) && (ph_query_cursor
!= NULL
))
857 if ((*ph_attach
) (0, 0))
859 ph_ig
= (*ph_input_group
) (0);
866 /* We do not have Photon running. Assume we are in text
870 if (devctl (fileno (stdin
), DCMD_CHR_LINESTATUS
, &mod_status
, sizeof (int), NULL
) == -1)
872 shift_ext_status
= mod_status
& 0xffffff00UL
;
874 if (mod_status
& _LINESTATUS_CON_ALT
)
876 if (mod_status
& _LINESTATUS_CON_CTRL
)
877 result
|= KEY_M_CTRL
;
878 if ((mod_status
& _LINESTATUS_CON_SHIFT
) || (shift_ext_status
& 0x00000800UL
))
879 result
|= KEY_M_SHIFT
;
883 (*ph_query_cursor
) (ph_ig
, &cursor_info
);
884 if (cursor_info
.key_mods
& 0x04)
886 if (cursor_info
.key_mods
& 0x02)
887 result
|= KEY_M_CTRL
;
888 if (cursor_info
.key_mods
& 0x01)
889 result
|= KEY_M_SHIFT
;
891 #endif /* __QNXNTO__ */
893 #if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX)
895 unsigned char modifiers
= 6;
897 if (ioctl (0, TIOCLINUX
, &modifiers
) < 0)
900 /* Translate Linux modifiers into mc modifiers */
901 if (modifiers
& SHIFT_PRESSED
)
902 result
|= KEY_M_SHIFT
;
903 if (modifiers
& (ALTL_PRESSED
| ALTR_PRESSED
))
905 if (modifiers
& CONTROL_PRESSED
)
906 result
|= KEY_M_CTRL
;
908 #endif /* !__linux__ */
912 /* --------------------------------------------------------------------------------------------- */
917 gboolean ret
= FALSE
;
919 if (seq_append
== NULL
)
920 seq_append
= seq_buffer
;
922 if (seq_append
!= &(seq_buffer
[SEQ_BUFFER_LEN
- 2]))
932 /* --------------------------------------------------------------------------------------------- */
933 /* Parse extended mouse coordinates.
934 Returns -1 if pending_keys (up to seq_append) cannot be a prefix of extended mouse coordinates.
935 Returns 0 if pending_keys (up to seq_append) is a valid (but still incomplete) prefix for
936 extended mouse coordinates, e.g. "^[[32;4".
937 Returns 1 and fills the mouse_btn, mouse_x, mouse_y values if pending_keys (up to seq_append) is
938 a complete extended mouse sequence, e.g. "^[[32;42;5M"
941 /* Technical info (Egmont Koblinger <egmont@gmail.com>):
943 The ancient way of reporting mouse coordinates only supports coordinates up to 223,
944 so if your terminal is wider (or taller, but that's unlikely), you cannot use your mouse
945 in the rightmost columns.
947 * The old way of reporting mouse coordinates is the following:
948 + Output DECSET 1000 to enable mouse
949 + Expect escape sequences in the format \e[M<action+32><x+32><y+32> whereas <action+32>,
950 <x+32> and <y+32> are single bytes. (Action is 0 for left click, 1 for middle click,
951 2 for right click, 3 for release, or something like this.)
952 + Disadvantages of this format:
953 + x and y can only go up to 223.
954 + Coordinates above 95 are not ascii-compatible, so any character set converting
955 layer (e.g. luit) messes them up.
956 + The stream is not valid UTF-8, even if everything else is.
958 * The first new extension, introduced by xterm-262, is the following:
959 + Output DECSET 1000 to enable mouse, followed by DECSET 1005 to activate extended mode.
960 + Expect escape sequences in the format \e[M<action+32><<x+32>><<y+32>> whereas <<x+32>>
961 and <<y+32>> each can be up to two bytes long: coordinate+32 is encoded in UTF-8.
962 + Disadvantates of this format:
963 + There's still a limit of 2015 rows/columns (okay, it's not a real life problem).
964 + Doesn't solve the luit issue.
965 + It is "horribly broken" (quoting urxvt's changelog) in terms of compatibility
966 with the previous standard. There is no way for an application to tell whether
967 the underlying terminal supports this new mode (whether DECSET 1005 did actually change
968 the behavior or not), but depending on this a completely different user action might
969 generate the same input. Example:
970 + If the terminal doesn't support this extension, then clicking at (162, 129)
971 generates \e[M<32><194><161>.
972 + If the terminal supports this extension, then clicking at (129, 1) [bit of math:
973 129+32 = 161, U+0161 in UTF-8 is 194 161] generates \e[M<32><194><161><33>.
974 + so there's no way to tell whether the terminal ignored the 1005 escape sequence,
975 the user clicked on (162, 129) and then typed an exclamation mark; or whether
976 the terminal recognized the escape, and the user clicked on (129, 1).
977 + Due to this horrible brokenness, there's no way to implement support it without
978 explicitly asking the user (via a setting) if the terminal can speak this extension.
980 * The second new extension, introduced by rxvt-unicode-9.10, is the following:
981 + Output DECSET 1000 to enable mouse, followed by DECSET 1015 to activate this extended mode.
982 + Expect escape sequences in the format \e[{action+32};{x};{y}M where this time I used
983 the braces to denote spelling out the numbers in decimal, rather than using raw bytes.
984 + The only thing I don't understand is why they kept the offset of 32 at action, but other
985 than that, this format is totally okay, and solves all the weaknesses of the previous ones.
987 Currently, at least the following terminal emulators have support for these:
988 * xterm supports the xterm extension
989 * rxvt-unicode >= 9.10 supports both extensions
990 * iterm2 supports both extensions
991 * vte >= 0.31 supports the urxvt extension
995 parse_extended_mouse_coordinates (void)
997 int c
, btn
= 0, x
= 0, y
= 0;
998 const int *p
= pending_keys
;
999 const int *endp
= seq_append
;
1020 if (c
< '0' || c
> '9')
1022 btn
= 10 * btn
+ c
- '0';
1035 if (c
< '0' || c
> '9')
1037 x
= 10 * x
+ c
- '0';
1049 if (c
< '0' || c
> '9')
1051 y
= 10 * y
+ c
- '0';
1062 /* --------------------------------------------------------------------------------------------- */
1063 /* Apply corrections for the keycode generated in get_key_code() */
1066 correct_key_code (int code
)
1068 unsigned int c
= code
& ~KEY_M_MASK
; /* code without modifier */
1069 unsigned int mod
= code
& KEY_M_MASK
; /* modifier */
1071 unsigned int qmod
; /* bunch of the QNX console
1072 modifiers needs unchanged */
1073 #endif /* __QNXNTO__ */
1076 * Add key modifiers directly from X11 or OS.
1077 * Ordinary characters only get modifiers from sequences.
1079 if (c
< 32 || c
>= 256)
1081 mod
|= get_modifier ();
1084 /* This is needed if the newline is reported as carriage return */
1088 /* This is reported to be useful on AIX */
1089 if (c
== KEY_SCANCEL
)
1092 /* Convert Shift+Tab and Ctrl+Tab to Back Tab
1093 * only if modifiers directly from X11
1095 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1096 if (x11_window
!= 0)
1097 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
1099 if ((c
== '\t') && (mod
& (KEY_M_SHIFT
| KEY_M_CTRL
)))
1106 /* F0 is the same as F10 for out purposes */
1111 * We are not interested if Ctrl was pressed when entering control
1112 * characters, so assume that it was. When checking for such keys,
1113 * XCTRL macro should be used. In some cases, we are interested,
1114 * e.g. to distinguish Ctrl-Enter from Enter.
1118 /* Special case for backspase ('\b' < 32) */
1122 else if (c
< 32 && c
!= ESC_CHAR
&& c
!= '\t' && c
!= '\n')
1128 qmod
= get_modifier ();
1130 if ((c
== 127) && (mod
== 0))
1131 { /* Add Ctrl/Alt/Shift-BackSpace */
1132 mod
|= get_modifier ();
1136 if ((c
== '0') && (mod
== 0))
1137 { /* Add Shift-Insert on key pad */
1138 if ((qmod
& KEY_M_SHIFT
) == KEY_M_SHIFT
)
1145 if ((c
== '.') && (mod
== 0))
1146 { /* Add Shift-Del on key pad */
1147 if ((qmod
& KEY_M_SHIFT
) == KEY_M_SHIFT
)
1153 #endif /* __QNXNTO__ */
1155 /* Unrecognized 0177 is delete (preserve Ctrl) */
1162 /* Unrecognized Ctrl-d is delete */
1163 if (c
== (31 & 'd'))
1169 /* Unrecognized Ctrl-h is backspace */
1170 if (c
== (31 & 'h'))
1177 /* Shift+BackSpace is backspace */
1178 if (c
== KEY_BACKSPACE
&& (mod
& KEY_M_SHIFT
))
1180 mod
&= ~KEY_M_SHIFT
;
1183 /* Convert Shift+Fn to F(n+10) */
1184 if (c
>= KEY_F (1) && c
<= KEY_F (10) && (mod
& KEY_M_SHIFT
))
1189 /* Remove Shift information from function keys */
1190 if (c
>= KEY_F (1) && c
<= KEY_F (20))
1192 mod
&= ~KEY_M_SHIFT
;
1195 if (!mc_global
.tty
.alternate_plus_minus
)
1201 case KEY_KP_SUBTRACT
:
1204 case KEY_KP_MULTIPLY
:
1212 /* --------------------------------------------------------------------------------------------- */
1215 xgetch_second (void)
1219 struct timeval time_out
;
1221 time_out
.tv_sec
= old_esc_mode_timeout
/ 1000000;
1222 time_out
.tv_usec
= old_esc_mode_timeout
% 1000000;
1224 FD_ZERO (&Read_FD_Set
);
1225 FD_SET (input_fd
, &Read_FD_Set
);
1226 select (input_fd
+ 1, &Read_FD_Set
, NULL
, NULL
, &time_out
);
1227 c
= tty_lowlevel_getch ();
1228 tty_nodelay (FALSE
);
1232 /* --------------------------------------------------------------------------------------------- */
1235 learn_store_key (char *buffer
, char **p
, int c
)
1237 if (*p
- buffer
> 253)
1247 *(*p
)++ = c
+ 'a' - 1;
1258 /* --------------------------------------------------------------------------------------------- */
1261 k_dispose (key_def
* k
)
1265 k_dispose (k
->child
);
1266 k_dispose (k
->next
);
1271 /* --------------------------------------------------------------------------------------------- */
1274 s_dispose (SelectList
* sel
)
1278 s_dispose (sel
->next
);
1283 /* --------------------------------------------------------------------------------------------- */
1286 key_code_comparator_by_name (const void *p1
, const void *p2
)
1288 const key_code_name_t
*n1
= *(const key_code_name_t
**) p1
;
1289 const key_code_name_t
*n2
= *(const key_code_name_t
**) p2
;
1291 return g_ascii_strcasecmp (n1
->name
, n2
->name
);
1294 /* --------------------------------------------------------------------------------------------- */
1297 key_code_comparator_by_code (const void *p1
, const void *p2
)
1299 const key_code_name_t
*n1
= *(const key_code_name_t
**) p1
;
1300 const key_code_name_t
*n2
= *(const key_code_name_t
**) p2
;
1302 return n1
->code
- n2
->code
;
1305 /* --------------------------------------------------------------------------------------------- */
1308 sort_key_conv_tab (enum KeySortType type_sort
)
1310 if (has_been_sorted
!= type_sort
)
1313 for (i
= 0; i
< key_conv_tab_size
; i
++)
1314 key_conv_tab_sorted
[i
] = &key_name_conv_tab
[i
];
1316 if (type_sort
== KEY_SORTBYNAME
)
1318 qsort (key_conv_tab_sorted
, key_conv_tab_size
, sizeof (key_conv_tab_sorted
[0]),
1319 &key_code_comparator_by_name
);
1321 else if (type_sort
== KEY_SORTBYCODE
)
1323 qsort (key_conv_tab_sorted
, key_conv_tab_size
, sizeof (key_conv_tab_sorted
[0]),
1324 &key_code_comparator_by_code
);
1326 has_been_sorted
= type_sort
;
1330 /* --------------------------------------------------------------------------------------------- */
1333 lookup_keyname (const char *name
, int *idx
)
1335 if (name
[0] != '\0')
1337 const key_code_name_t key
= { 0, name
, NULL
, NULL
};
1338 const key_code_name_t
*keyp
= &key
;
1339 key_code_name_t
**res
;
1341 if (name
[1] == '\0')
1344 return (int) name
[0];
1347 sort_key_conv_tab (KEY_SORTBYNAME
);
1349 res
= bsearch (&keyp
, key_conv_tab_sorted
, key_conv_tab_size
,
1350 sizeof (key_conv_tab_sorted
[0]), key_code_comparator_by_name
);
1354 *idx
= (int) (res
- (key_code_name_t
**) key_conv_tab_sorted
);
1355 return (*res
)->code
;
1363 /* --------------------------------------------------------------------------------------------- */
1366 lookup_keycode (const long code
, int *idx
)
1370 const key_code_name_t key
= { code
, NULL
, NULL
, NULL
};
1371 const key_code_name_t
*keyp
= &key
;
1372 key_code_name_t
**res
;
1374 sort_key_conv_tab (KEY_SORTBYCODE
);
1376 res
= bsearch (&keyp
, key_conv_tab_sorted
, key_conv_tab_size
,
1377 sizeof (key_conv_tab_sorted
[0]), key_code_comparator_by_code
);
1381 *idx
= (int) (res
- (key_code_name_t
**) key_conv_tab_sorted
);
1390 /* --------------------------------------------------------------------------------------------- */
1391 /*** public functions ****************************************************************************/
1392 /* --------------------------------------------------------------------------------------------- */
1393 /* This has to be called before init_slang or whatever routine
1394 calls any define_sequence */
1399 const char *term
= getenv ("TERM");
1401 /* This has to be the first define_sequence */
1402 /* So, we can assume that the first keys member has ESC */
1403 define_sequences (mc_default_keys
);
1405 /* Terminfo on irix does not have some keys */
1406 if (mc_global
.tty
.xterm_flag
1408 && (strncmp (term
, "iris-ansi", 9) == 0
1409 || strncmp (term
, "xterm", 5) == 0
1410 || strncmp (term
, "rxvt", 4) == 0 || strcmp (term
, "screen") == 0)))
1411 define_sequences (xterm_key_defines
);
1413 /* load some additional keys (e.g. direct Alt-? support) */
1414 load_xtra_key_defines ();
1417 if ((term
!= NULL
) && (strncmp (term
, "qnx", 3) == 0))
1419 /* Modify the default value of use_8th_bit_as_meta: we would
1420 * like to provide a working mc for a newbie who knows nothing
1421 * about [Options|Display bits|Full 8 bits input]...
1423 * Don't use 'meta'-bit, when we are dealing with a
1424 * 'qnx*'-type terminal: clear the default value!
1425 * These terminal types use 0xFF as an escape character,
1426 * so use_8th_bit_as_meta==1 must not be enabled!
1428 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
1429 * is not used now (doesn't even depend on use_8th_bit_as_meta
1430 * as in mc-3.1.2)...GREAT!...no additional code is required!]
1432 use_8th_bit_as_meta
= 0;
1434 #endif /* __QNX__ */
1438 /* Load the qansi-m key definitions
1439 if we are running under the qansi-m terminal */
1440 if (term
!= NULL
&& (strncmp (term
, "qansi-m", 7) == 0))
1441 define_sequences (qansi_key_defines
);
1444 /* --------------------------------------------------------------------------------------------- */
1446 * This has to be called after SLang_init_tty/slint_init
1450 init_key_input_fd (void)
1453 input_fd
= SLang_TT_Read_FD
;
1457 /* --------------------------------------------------------------------------------------------- */
1463 s_dispose (select_list
);
1465 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1467 mc_XCloseDisplay (x11_display
);
1471 /* --------------------------------------------------------------------------------------------- */
1474 add_select_channel (int fd
, select_fn callback
, void *info
)
1478 new = g_new (SelectList
, 1);
1480 new->callback
= callback
;
1482 new->next
= select_list
;
1486 /* --------------------------------------------------------------------------------------------- */
1489 delete_select_channel (int fd
)
1491 SelectList
*p
= select_list
;
1492 SelectList
*p_prev
= NULL
;
1501 p_prev
->next
= p_next
;
1503 select_list
= p_next
;
1515 /* --------------------------------------------------------------------------------------------- */
1520 if (disabled_channels
== 0)
1521 fputs ("Error: channels_up called with disabled_channels = 0\n", stderr
);
1522 disabled_channels
--;
1525 /* --------------------------------------------------------------------------------------------- */
1528 channels_down (void)
1530 disabled_channels
++;
1533 /* --------------------------------------------------------------------------------------------- */
1535 * Return the code associated with the symbolic name keyname
1539 lookup_key (const char *name
, char **label
)
1541 char **lc_keys
, **p
;
1553 name
= g_strstrip (g_strdup (name
));
1554 p
= lc_keys
= g_strsplit_set (name
, "-+ ", -1);
1555 g_free ((char *) name
);
1557 while ((p
!= NULL
) && (*p
!= NULL
))
1559 if ((*p
)[0] != '\0')
1563 key
= lookup_keyname (g_strstrip (*p
), &idx
);
1565 if (key
== KEY_M_ALT
)
1567 else if (key
== KEY_M_CTRL
)
1569 else if (key
== KEY_M_SHIFT
)
1582 g_strfreev (lc_keys
);
1593 s
= g_string_new ("");
1597 g_string_append (s
, key_conv_tab_sorted
[use_meta
]->shortcut
);
1598 g_string_append_c (s
, '-');
1602 g_string_append (s
, key_conv_tab_sorted
[use_ctrl
]->shortcut
);
1603 g_string_append_c (s
, '-');
1605 if (use_shift
!= -1)
1608 g_string_append_c (s
, (gchar
) g_ascii_toupper ((gchar
) k
));
1611 g_string_append (s
, key_conv_tab_sorted
[use_shift
]->shortcut
);
1612 g_string_append_c (s
, '-');
1613 g_string_append (s
, key_conv_tab_sorted
[lc_index
]->shortcut
);
1618 if ((k
>= 'A') || (lc_index
< 0) || (key_conv_tab_sorted
[lc_index
]->shortcut
== NULL
))
1619 g_string_append_c (s
, (gchar
) g_ascii_tolower ((gchar
) k
));
1621 g_string_append (s
, key_conv_tab_sorted
[lc_index
]->shortcut
);
1623 else if ((lc_index
!= -1) && (key_conv_tab_sorted
[lc_index
]->shortcut
!= NULL
))
1624 g_string_append (s
, key_conv_tab_sorted
[lc_index
]->shortcut
);
1626 g_string_append_c (s
, (gchar
) g_ascii_tolower ((gchar
) key
));
1628 *label
= g_string_free (s
, FALSE
);
1631 if (use_shift
!= -1)
1633 if (k
< 127 && k
> 31)
1634 k
= g_ascii_toupper ((gchar
) k
);
1653 /* --------------------------------------------------------------------------------------------- */
1656 lookup_key_by_code (const int keycode
)
1658 /* code without modifier */
1659 unsigned int k
= keycode
& ~KEY_M_MASK
;
1661 unsigned int mod
= keycode
& KEY_M_MASK
;
1671 s
= g_string_sized_new (8);
1673 if (lookup_keycode (k
, &key_idx
) || (k
> 0 && k
< 256))
1675 if (mod
& KEY_M_ALT
)
1677 if (lookup_keycode (KEY_M_ALT
, &idx
))
1680 g_string_append (s
, key_conv_tab_sorted
[use_meta
]->name
);
1681 g_string_append_c (s
, '-');
1684 if (mod
& KEY_M_CTRL
)
1686 /* non printeble chars like a CTRL-[A..Z] */
1690 if (lookup_keycode (KEY_M_CTRL
, &idx
))
1693 g_string_append (s
, key_conv_tab_sorted
[use_ctrl
]->name
);
1694 g_string_append_c (s
, '-');
1697 if (mod
& KEY_M_SHIFT
)
1699 if (lookup_keycode (KEY_M_ALT
, &idx
))
1703 g_string_append_c (s
, (gchar
) g_ascii_toupper ((gchar
) k
));
1706 g_string_append (s
, key_conv_tab_sorted
[use_shift
]->name
);
1707 g_string_append_c (s
, '-');
1708 g_string_append (s
, key_conv_tab_sorted
[key_idx
]->name
);
1714 if ((k
>= 'A') || (key_idx
< 0) || (key_conv_tab_sorted
[key_idx
]->name
== NULL
))
1715 g_string_append_c (s
, (gchar
) k
);
1717 g_string_append (s
, key_conv_tab_sorted
[key_idx
]->name
);
1719 else if ((key_idx
!= -1) && (key_conv_tab_sorted
[key_idx
]->name
!= NULL
))
1720 g_string_append (s
, key_conv_tab_sorted
[key_idx
]->name
);
1722 g_string_append_c (s
, (gchar
) keycode
);
1725 return g_string_free (s
, s
->len
== 0);
1728 /* --------------------------------------------------------------------------------------------- */
1730 * Return TRUE on success, FALSE on error.
1731 * An error happens if SEQ is a beginning of an existing longer sequence.
1735 define_sequence (int code
, const char *seq
, int action
)
1739 if (strlen (seq
) > SEQ_BUFFER_LEN
- 1)
1742 for (base
= keys
; (base
!= NULL
) && (*seq
!= '\0');)
1743 if (*seq
== base
->ch
)
1745 if (base
->child
== 0)
1747 if (*(seq
+ 1) != '\0')
1748 base
->child
= create_sequence (seq
+ 1, code
, action
);
1751 /* The sequence matches an existing one. */
1753 base
->action
= action
;
1767 base
->next
= create_sequence (seq
, code
, action
);
1774 /* Attempt to redefine a sequence with a shorter sequence. */
1778 keys
= create_sequence (seq
, code
, action
);
1782 /* --------------------------------------------------------------------------------------------- */
1784 * Check if we are idle, i.e. there are no pending keyboard or mouse
1785 * events. Return 1 is idle, 0 is there are pending events.
1792 struct timeval time_out
;
1794 FD_ZERO (&select_set
);
1795 FD_SET (input_fd
, &select_set
);
1798 if (mouse_enabled
&& (use_mouse_p
== MOUSE_GPM
) && (gpm_fd
> 0))
1800 FD_SET (gpm_fd
, &select_set
);
1801 maxfdp
= max (maxfdp
, gpm_fd
);
1804 time_out
.tv_sec
= 0;
1805 time_out
.tv_usec
= 0;
1806 return (select (maxfdp
+ 1, &select_set
, 0, 0, &time_out
) <= 0);
1809 /* --------------------------------------------------------------------------------------------- */
1812 get_key_code (int no_delay
)
1815 static key_def
*this = NULL
, *parent
;
1816 static struct timeval esctime
= { -1, -1 };
1817 static int lastnodelay
= -1;
1819 if (no_delay
!= lastnodelay
)
1822 lastnodelay
= no_delay
;
1826 if (pending_keys
!= NULL
)
1830 m
= parse_extended_mouse_coordinates ();
1833 pending_keys
= seq_append
= NULL
;
1835 return MCKEY_EXTENDED_MOUSE
;
1839 int d
= *pending_keys
++;
1841 if (*pending_keys
== 0)
1843 pending_keys
= NULL
;
1846 if ((d
== ESC_CHAR
) && (pending_keys
!= NULL
))
1848 d
= ALT (*pending_keys
++);
1851 if ((d
> 127 && d
< 256) && use_8th_bit_as_meta
)
1854 return correct_key_code (d
);
1856 /* else if (m == 0), just let it continue */
1863 c
= tty_lowlevel_getch ();
1864 #if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE)
1865 if (c
== KEY_RESIZE
)
1866 goto nodelay_try_again
;
1870 tty_nodelay (FALSE
);
1873 if (this != NULL
&& parent
!= NULL
&& parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
)
1875 struct timeval current
, time_out
;
1877 if (esctime
.tv_sec
== -1)
1880 time_out
.tv_sec
= old_esc_mode_timeout
/ 1000000 + esctime
.tv_sec
;
1881 time_out
.tv_usec
= old_esc_mode_timeout
% 1000000 + esctime
.tv_usec
;
1882 if (time_out
.tv_usec
> 1000000)
1884 time_out
.tv_usec
-= 1000000;
1887 if (current
.tv_sec
< time_out
.tv_sec
)
1889 if (current
.tv_sec
== time_out
.tv_sec
&& current
.tv_usec
< time_out
.tv_usec
)
1892 pending_keys
= seq_append
= NULL
;
1900 /* Maybe we got an incomplete match.
1901 This we do only in delay mode, since otherwise
1902 tty_lowlevel_getch can return -1 at any time. */
1903 if (seq_append
!= NULL
)
1905 pending_keys
= seq_buffer
;
1912 /* Search the key on the root */
1913 if (!no_delay
|| this == NULL
)
1918 if ((c
> 127 && c
< 256) && use_8th_bit_as_meta
)
1922 /* The first sequence defined starts with esc */
1927 while (this != NULL
)
1935 pending_keys
= seq_buffer
;
1940 if (parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
)
1947 /* Shouldn't happen */
1948 fputs ("Internal error\n", stderr
);
1949 exit (EXIT_FAILURE
);
1951 goto nodelay_try_again
;
1953 esctime
.tv_sec
= -1;
1954 c
= xgetch_second ();
1957 pending_keys
= seq_append
= NULL
;
1965 goto nodelay_try_again
;
1966 c
= tty_lowlevel_getch ();
1971 /* We got a complete match, return and reset search */
1974 pending_keys
= seq_append
= NULL
;
1977 return correct_key_code (code
);
1982 if (this->next
!= NULL
)
1986 if ((parent
!= NULL
) && (parent
->action
== MCKEY_ESCAPE
))
1988 /* Convert escape-digits to F-keys */
1989 if (g_ascii_isdigit (c
))
1990 c
= KEY_F (c
- '0');
1996 pending_keys
= seq_append
= NULL
;
1998 return correct_key_code (c
);
2000 /* Did not find a match or {c} was changed in the if above,
2001 so we have to return everything we had skipped
2004 pending_keys
= seq_buffer
;
2010 return correct_key_code (c
);
2013 /* --------------------------------------------------------------------------------------------- */
2014 /* Returns a character read from stdin with appropriate interpretation */
2015 /* Also takes care of generated mouse events */
2016 /* Returns EV_MOUSE if it is a mouse event */
2017 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
2020 tty_get_event (struct Gpm_Event
*event
, gboolean redo_event
, gboolean block
)
2023 static int flag
= 0; /* Return value from select */
2025 static struct Gpm_Event ev
; /* Mouse event */
2027 struct timeval time_out
;
2028 struct timeval
*time_addr
= NULL
;
2029 static int dirty
= 3;
2031 if ((dirty
== 3) || is_idle ())
2039 vfs_timeout_handler ();
2041 /* Ok, we use (event->x < 0) to signal that the event does not contain
2042 a suitable position for the mouse, so we can't use show_mouse_pointer
2047 show_mouse_pointer (event
->x
, event
->y
);
2052 /* Repeat if using mouse */
2053 while (pending_keys
== NULL
)
2058 FD_ZERO (&select_set
);
2059 FD_SET (input_fd
, &select_set
);
2060 maxfdp
= max (add_selects (&select_set
), input_fd
);
2063 if (mouse_enabled
&& (use_mouse_p
== MOUSE_GPM
))
2067 /* Connection to gpm broken, possibly gpm has died */
2068 mouse_enabled
= FALSE
;
2069 use_mouse_p
= MOUSE_NONE
;
2073 FD_SET (gpm_fd
, &select_set
);
2074 maxfdp
= max (maxfdp
, gpm_fd
);
2080 time_out
.tv_usec
= mou_auto_repeat
* 1000;
2081 time_out
.tv_sec
= 0;
2083 time_addr
= &time_out
;
2089 seconds
= vfs_timeouts ();
2094 /* the timeout could be improved and actually be
2095 * the number of seconds until the next vfs entry
2096 * timeouts in the stamp list.
2099 time_out
.tv_sec
= seconds
;
2100 time_out
.tv_usec
= 0;
2101 time_addr
= &time_out
;
2105 if (!block
|| mc_global
.tty
.winch_flag
)
2107 time_addr
= &time_out
;
2108 time_out
.tv_sec
= 0;
2109 time_out
.tv_usec
= 0;
2112 tty_enable_interrupt_key ();
2113 flag
= select (maxfdp
+ 1, &select_set
, NULL
, NULL
, time_addr
);
2114 tty_disable_interrupt_key ();
2116 /* select timed out: it could be for any of the following reasons:
2117 * redo_event -> it was because of the MOU_REPEAT handler
2118 * !block -> we did not block in the select call
2119 * else -> 10 second timeout to check the vfs status.
2125 if (!block
|| mc_global
.tty
.winch_flag
)
2127 vfs_timeout_handler ();
2129 if (flag
== -1 && errno
== EINTR
)
2132 check_selects (&select_set
);
2134 if (FD_ISSET (input_fd
, &select_set
))
2137 if (mouse_enabled
&& use_mouse_p
== MOUSE_GPM
2138 && gpm_fd
> 0 && FD_ISSET (gpm_fd
, &select_set
))
2145 #endif /* !HAVE_LIBGPM */
2149 flag
= is_wintouched (stdscr
);
2150 untouchwin (stdscr
);
2151 #endif /* !HAVE_SLANG */
2152 c
= block
? getch_with_delay () : get_key_code (1);
2156 tty_touch_screen ();
2157 #endif /* !HAVE_SLANG */
2159 if (mouse_enabled
&& (c
== MCKEY_MOUSE
2162 #endif /* KEY_MOUSE */
2163 || c
== MCKEY_EXTENDED_MOUSE
))
2166 /* In case of extended coordinates, mouse_btn, mouse_x and mouse_y are already filled in. */
2167 if (c
!= MCKEY_EXTENDED_MOUSE
)
2169 /* Variable btn has following meaning: */
2170 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
2171 mouse_btn
= tty_lowlevel_getch () - 32;
2172 /* Coordinates are 33-based */
2173 /* Transform them to 1-based */
2174 mouse_x
= tty_lowlevel_getch () - 32;
2175 mouse_y
= tty_lowlevel_getch () - 32;
2177 xmouse_get_event (event
);
2178 return (event
->type
!= 0) ? EV_MOUSE
: EV_NONE
;
2184 /* --------------------------------------------------------------------------------------------- */
2185 /* Returns a key press, mouse events are discarded */
2194 while ((key
= tty_get_event (&ev
, FALSE
, TRUE
)) == EV_NONE
);
2198 /* --------------------------------------------------------------------------------------------- */
2203 /* LEARN_TIMEOUT in usec */
2204 #define LEARN_TIMEOUT 200000
2207 struct timeval endtime
;
2208 struct timeval time_out
;
2213 tty_keypad (FALSE
); /* disable intepreting keys by ncurses */
2214 c
= tty_lowlevel_getch ();
2216 c
= tty_lowlevel_getch (); /* Sanity check, should be unnecessary */
2217 learn_store_key (buffer
, &p
, c
);
2219 endtime
.tv_usec
+= LEARN_TIMEOUT
;
2220 if (endtime
.tv_usec
> 1000000)
2222 endtime
.tv_usec
-= 1000000;
2228 while ((c
= tty_lowlevel_getch ()) == -1)
2230 GET_TIME (time_out
);
2231 time_out
.tv_usec
= endtime
.tv_usec
- time_out
.tv_usec
;
2232 if (time_out
.tv_usec
< 0)
2234 time_out
.tv_sec
= endtime
.tv_sec
- time_out
.tv_sec
;
2235 if (time_out
.tv_sec
>= 0 && time_out
.tv_usec
> 0)
2237 FD_ZERO (&Read_FD_Set
);
2238 FD_SET (input_fd
, &Read_FD_Set
);
2239 select (input_fd
+ 1, &Read_FD_Set
, NULL
, NULL
, &time_out
);
2246 learn_store_key (buffer
, &p
, c
);
2249 tty_nodelay (FALSE
);
2251 return g_strdup (buffer
);
2252 #undef LEARN_TIMEOUT
2255 /* --------------------------------------------------------------------------------------------- */
2256 /* xterm and linux console only: set keypad to numeric or application
2257 mode. Only in application keypad mode it's possible to distinguish
2258 the '+' key and the '+' on the keypad ('*' and '-' ditto) */
2261 numeric_keypad_mode (void)
2263 if (mc_global
.tty
.console_flag
!= '\0' || mc_global
.tty
.xterm_flag
)
2265 fputs (ESC_STR
">", stdout
);
2270 /* --------------------------------------------------------------------------------------------- */
2273 application_keypad_mode (void)
2275 if (mc_global
.tty
.console_flag
!= '\0' || mc_global
.tty
.xterm_flag
)
2277 fputs (ESC_STR
"=", stdout
);
2282 /* --------------------------------------------------------------------------------------------- */