root/lib/tty/key.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. select_cmp_by_fd_set
  2. select_cmp_by_fd
  3. add_selects
  4. check_selects
  5. try_channels
  6. create_sequence
  7. define_sequences
  8. init_key_x11
  9. getch_with_delay
  10. xmouse_get_event
  11. get_modifier
  12. push_char
  13. correct_key_code
  14. getch_with_timeout
  15. learn_store_key
  16. k_dispose
  17. key_code_comparator_by_name
  18. key_code_comparator_by_code
  19. sort_key_conv_tab
  20. lookup_keyname
  21. lookup_keycode
  22. init_key
  23. init_key_input_fd
  24. done_key
  25. add_select_channel
  26. delete_select_channel
  27. channels_up
  28. channels_down
  29. tty_keyname_to_keycode
  30. tty_keycode_to_keyname
  31. define_sequence
  32. is_idle
  33. get_key_code
  34. tty_get_event
  35. tty_getch
  36. learn_key
  37. numeric_keypad_mode
  38. application_keypad_mode
  39. enable_bracketed_paste
  40. disable_bracketed_paste

   1 /*
   2    Keyboard support routines.
   3 
   4    Copyright (C) 1994-2025
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Miguel de Icaza, 1994, 1995
   9    Janne Kukonlehto, 1994, 1995
  10    Jakub Jelinek, 1995
  11    Norbert Warmuth, 1997
  12    Denys Vlasenko <vda.linux@googlemail.com>, 2013
  13    Slava Zanko <slavazanko@gmail.com>, 2013
  14    Egmont Koblinger <egmont@gmail.com>, 2013
  15 
  16    This file is part of the Midnight Commander.
  17 
  18    The Midnight Commander is free software: you can redistribute it
  19    and/or modify it under the terms of the GNU General Public License as
  20    published by the Free Software Foundation, either version 3 of the License,
  21    or (at your option) any later version.
  22 
  23    The Midnight Commander is distributed in the hope that it will be useful,
  24    but WITHOUT ANY WARRANTY; without even the implied warranty of
  25    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26    GNU General Public License for more details.
  27 
  28    You should have received a copy of the GNU General Public License
  29    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  30  */
  31 
  32 /** \file key.c
  33  *  \brief Source: keyboard support routines
  34  */
  35 
  36 #include <config.h>
  37 
  38 #include <ctype.h>
  39 #include <errno.h>
  40 #include <stdio.h>
  41 #include <stdlib.h>
  42 #include <string.h>
  43 #ifdef HAVE_SYS_SELECT_H
  44 #    include <sys/select.h>
  45 #else
  46 #    include <sys/time.h>
  47 #    include <sys/types.h>
  48 #    include <unistd.h>
  49 #endif
  50 
  51 #include "lib/global.h"
  52 
  53 #include "lib/vfs/vfs.h"
  54 
  55 #include "tty.h"
  56 #include "tty-internal.h"  // mouse_enabled
  57 #include "mouse.h"
  58 #include "key.h"
  59 
  60 #include "lib/widget.h"  // mc_refresh()
  61 
  62 #ifdef HAVE_TEXTMODE_X11_SUPPORT
  63 #    include "x11conn.h"
  64 #endif
  65 
  66 #ifdef __linux__
  67 #    if defined(__GLIBC__) && (__GLIBC__ < 2)
  68 #        include <linux/termios.h>  // TIOCLINUX
  69 #    else
  70 #        include <termios.h>
  71 #    endif
  72 #    ifdef HAVE_SYS_IOCTL_H
  73 #        include <sys/ioctl.h>
  74 #    endif
  75 #endif
  76 
  77 #ifdef __CYGWIN__
  78 #    include <termios.h>
  79 #    ifdef HAVE_SYS_IOCTL_H
  80 #        include <sys/ioctl.h>
  81 #    endif
  82 #endif
  83 
  84 #ifdef __QNXNTO__
  85 #    include <dlfcn.h>
  86 #    include <Ph.h>
  87 #    include <sys/dcmd_chr.h>
  88 #endif
  89 
  90 /*** global variables ****************************************************************************/
  91 
  92 int mou_auto_repeat = 100;     // ms
  93 int double_click_speed = 250;  // ms
  94 gboolean old_esc_mode = TRUE;
  95 /* timeout for old_esc_mode in usec */
  96 int old_esc_mode_timeout = G_USEC_PER_SEC;  // us, settable via env
  97 gboolean use_8th_bit_as_meta = FALSE;
  98 
  99 gboolean bracketed_pasting_in_progress = FALSE;
 100 
 101 /* This table is a mapping between names and the constants we use
 102  * We use this to allow users to define alternate definitions for
 103  * certain keys that may be missing from the terminal database
 104  */
 105 const key_code_name_t key_name_conv_tab[] = {
 106     { ESC_CHAR, "escape", N_ ("Escape"), "Esc" },
 107     /* KEY_F(0) is not here, since we are mapping it to f10, so there is no reason
 108        to define f0 as well. Also, it makes Learn keys a bunch of problems :( */
 109     { KEY_F (1), "f1", N_ ("Function key 1"), "F1" },
 110     { KEY_F (2), "f2", N_ ("Function key 2"), "F2" },
 111     { KEY_F (3), "f3", N_ ("Function key 3"), "F3" },
 112     { KEY_F (4), "f4", N_ ("Function key 4"), "F4" },
 113     { KEY_F (5), "f5", N_ ("Function key 5"), "F5" },
 114     { KEY_F (6), "f6", N_ ("Function key 6"), "F6" },
 115     { KEY_F (7), "f7", N_ ("Function key 7"), "F7" },
 116     { KEY_F (8), "f8", N_ ("Function key 8"), "F8" },
 117     { KEY_F (9), "f9", N_ ("Function key 9"), "F9" },
 118     { KEY_F (10), "f10", N_ ("Function key 10"), "F10" },
 119     { KEY_F (11), "f11", N_ ("Function key 11"), "F11" },
 120     { KEY_F (12), "f12", N_ ("Function key 12"), "F12" },
 121     { KEY_F (13), "f13", N_ ("Function key 13"), "F13" },
 122     { KEY_F (14), "f14", N_ ("Function key 14"), "F14" },
 123     { KEY_F (15), "f15", N_ ("Function key 15"), "F15" },
 124     { KEY_F (16), "f16", N_ ("Function key 16"), "F16" },
 125     { KEY_F (17), "f17", N_ ("Function key 17"), "F17" },
 126     { KEY_F (18), "f18", N_ ("Function key 18"), "F18" },
 127     { KEY_F (19), "f19", N_ ("Function key 19"), "F19" },
 128     { KEY_F (20), "f20", N_ ("Function key 20"), "F20" },
 129     { ALT ('\t'), "complete", N_ ("Completion/M-tab"), "Meta-Tab" },
 130     { KEY_BTAB, "backtab", N_ ("BackTab/S-tab"), "Shift-Tab" },
 131     { KEY_BACKSPACE, "backspace", N_ ("Backspace"), "Backspace" },
 132     { KEY_UP, "up", N_ ("Up arrow"), "Up" },
 133     { KEY_DOWN, "down", N_ ("Down arrow"), "Down" },
 134     { KEY_LEFT, "left", N_ ("Left arrow"), "Left" },
 135     { KEY_RIGHT, "right", N_ ("Right arrow"), "Right" },
 136     { KEY_IC, "insert", N_ ("Insert"), "Ins" },
 137     { KEY_DC, "delete", N_ ("Delete"), "Del" },
 138     { KEY_HOME, "home", N_ ("Home"), "Home" },
 139     { KEY_END, "end", N_ ("End key"), "End" },
 140     { KEY_PPAGE, "pgup", N_ ("Page Up"), "PgUp" },
 141     { KEY_NPAGE, "pgdn", N_ ("Page Down"), "PgDn" },
 142     { (int) '/', "kpslash", N_ ("/ on keypad"), "/" },
 143     { KEY_KP_MULTIPLY, "kpasterisk", N_ ("* on keypad"), "*" },
 144     { KEY_KP_SUBTRACT, "kpminus", N_ ("- on keypad"), "-" },
 145     { KEY_KP_ADD, "kpplus", N_ ("+ on keypad"), "+" },
 146 
 147     // From here on, these won't be shown in Learn keys (no space)
 148     { KEY_LEFT, "kpleft", N_ ("Left arrow keypad"), "Left" },
 149     { KEY_RIGHT, "kpright", N_ ("Right arrow keypad"), "Right" },
 150     { KEY_UP, "kpup", N_ ("Up arrow keypad"), "Up" },
 151     { KEY_DOWN, "kpdown", N_ ("Down arrow keypad"), "Down" },
 152     { KEY_HOME, "kphome", N_ ("Home on keypad"), "Home" },
 153     { KEY_END, "kpend", N_ ("End on keypad"), "End" },
 154     { KEY_NPAGE, "kpnpage", N_ ("Page Down keypad"), "PgDn" },
 155     { KEY_PPAGE, "kpppage", N_ ("Page Up keypad"), "PgUp" },
 156     { KEY_IC, "kpinsert", N_ ("Insert on keypad"), "Ins" },
 157     { KEY_DC, "kpdelete", N_ ("Delete on keypad"), "Del" },
 158     { (int) '\n', "kpenter", N_ ("Enter on keypad"), "Enter" },
 159     { KEY_F (21), "f21", N_ ("Function key 21"), "F21" },
 160     { KEY_F (22), "f22", N_ ("Function key 22"), "F22" },
 161     { KEY_F (23), "f23", N_ ("Function key 23"), "F23" },
 162     { KEY_F (24), "f24", N_ ("Function key 24"), "F24" },
 163     { KEY_A1, "a1", N_ ("A1 key"), "A1" },
 164     { KEY_C1, "c1", N_ ("C1 key"), "C1" },
 165 
 166     // Alternative label
 167     { ESC_CHAR, "esc", N_ ("Escape"), "Esc" },
 168     { KEY_BACKSPACE, "bs", N_ ("Backspace"), "Bakspace" },
 169     { KEY_IC, "ins", N_ ("Insert"), "Ins" },
 170     { KEY_DC, "del", N_ ("Delete"), "Del" },
 171     { (int) '*', "asterisk", N_ ("Asterisk"), "*" },
 172     { (int) '-', "minus", N_ ("Minus"), "-" },
 173     { (int) '+', "plus", N_ ("Plus"), "+" },
 174     { (int) '.', "dot", N_ ("Dot"), "." },
 175     { (int) '<', "lt", N_ ("Less than"), "<" },
 176     { (int) '>', "gt", N_ ("Great than"), ">" },
 177     { (int) '=', "equal", N_ ("Equal"), "=" },
 178     { (int) ',', "comma", N_ ("Comma"), "," },
 179     { (int) '\'', "apostrophe", N_ ("Apostrophe"), "\'" },
 180     { (int) ':', "colon", N_ ("Colon"), ":" },
 181     { (int) ';', "semicolon", N_ ("Semicolon"), ";" },
 182     { (int) '!', "exclamation", N_ ("Exclamation mark"), "!" },
 183     { (int) '?', "question", N_ ("Question mark"), "?" },
 184     { (int) '&', "ampersand", N_ ("Ampersand"), "&" },
 185     { (int) '$', "dollar", N_ ("Dollar sign"), "$" },
 186     { (int) '"', "quota", N_ ("Quotation mark"), "\"" },
 187     { (int) '%', "percent", N_ ("Percent sign"), "%" },
 188     { (int) '^', "caret", N_ ("Caret"), "^" },
 189     { (int) '~', "tilda", N_ ("Tilda"), "~" },
 190     { (int) '`', "prime", N_ ("Prime"), "`" },
 191     { (int) '_', "underline", N_ ("Underline"), "_" },
 192     { (int) '_', "understrike", N_ ("Understrike"), "_" },
 193     { (int) '|', "pipe", N_ ("Pipe"), "|" },
 194     { (int) '(', "lparenthesis", N_ ("Left parenthesis"), "(" },
 195     { (int) ')', "rparenthesis", N_ ("Right parenthesis"), ")" },
 196     { (int) '[', "lbracket", N_ ("Left bracket"), "[" },
 197     { (int) ']', "rbracket", N_ ("Right bracket"), "]" },
 198     { (int) '{', "lbrace", N_ ("Left brace"), "{" },
 199     { (int) '}', "rbrace", N_ ("Right brace"), "}" },
 200     { (int) '\n', "enter", N_ ("Enter"), "Enter" },
 201     { (int) '\t', "tab", N_ ("Tab key"), "Tab" },
 202     { (int) ' ', "space", N_ ("Space key"), "Space" },
 203     { (int) '/', "slash", N_ ("Slash key"), "/" },
 204     { (int) '\\', "backslash", N_ ("Backslash key"), "\\" },
 205     { (int) '#', "number", N_ ("Number sign #"), "#" },
 206     { (int) '#', "hash", N_ ("Number sign #"), "#" },
 207     // TRANSLATORS: Please translate as in "at sign" (@).
 208     { (int) '@', "at", N_ ("At sign"), "@" },
 209 
 210     // meta keys
 211     { KEY_M_CTRL, "control", N_ ("Ctrl"), "C" },
 212     { KEY_M_CTRL, "ctrl", N_ ("Ctrl"), "C" },
 213     { KEY_M_ALT, "meta", N_ ("Alt"), "M" },
 214     { KEY_M_ALT, "alt", N_ ("Alt"), "M" },
 215     { KEY_M_ALT, "ralt", N_ ("Alt"), "M" },
 216     { KEY_M_SHIFT, "shift", N_ ("Shift"), "S" },
 217 
 218     { 0, NULL, NULL, NULL },
 219 };
 220 
 221 /*** file scope macro definitions ****************************************************************/
 222 
 223 #define MC_USEC_PER_MSEC 1000
 224 
 225 /* The maximum sequence length (32 + null terminator) */
 226 #define SEQ_BUFFER_LEN 33
 227 
 228 /*** file scope type declarations ****************************************************************/
 229 
 230 /* Linux console keyboard modifiers */
 231 typedef enum
 232 {
 233     SHIFT_PRESSED = (1 << 0),
 234     ALTR_PRESSED = (1 << 1),
 235     CONTROL_PRESSED = (1 << 2),
 236     ALTL_PRESSED = (1 << 3)
 237 } mod_pressed_t;
 238 
 239 typedef struct key_def
 240 {
 241     char ch;   // Holds the matching char code
 242     int code;  // The code returned, valid if child == NULL
 243     struct key_def *next;
 244     struct key_def *child;  // sequence continuation
 245     int action;             /* optional action to be done. Now used only
 246                                to mark that we are just after the first
 247                                Escape */
 248 } key_def;
 249 
 250 typedef struct
 251 {
 252     int code;
 253     const char *seq;
 254     int action;
 255 } key_define_t;
 256 
 257 /* File descriptor monitoring add/remove routines */
 258 typedef struct
 259 {
 260     int fd;
 261     select_fn callback;
 262     void *info;
 263 } select_t;
 264 
 265 typedef enum KeySortType
 266 {
 267     KEY_NOSORT = 0,
 268     KEY_SORTBYNAME,
 269     KEY_SORTBYCODE
 270 } KeySortType;
 271 
 272 #ifdef __QNXNTO__
 273 typedef int (*ph_dv_f) (void *, void *);
 274 typedef int (*ph_ov_f) (void *);
 275 typedef int (*ph_pqc_f) (unsigned short, PhCursorInfo_t *);
 276 #endif
 277 
 278 /*** forward declarations (file scope functions) *************************************************/
 279 
 280 /*** file scope variables ************************************************************************/
 281 
 282 static key_define_t mc_default_keys[] = {
 283     { ESC_CHAR, ESC_STR, MCKEY_ESCAPE },
 284     { ESC_CHAR, ESC_STR ESC_STR, MCKEY_NOACTION },
 285     { MCKEY_BRACKETED_PASTING_START, ESC_STR "[200~", MCKEY_NOACTION },
 286     { MCKEY_BRACKETED_PASTING_END, ESC_STR "[201~", MCKEY_NOACTION },
 287     { 0, NULL, MCKEY_NOACTION },
 288 };
 289 
 290 /* Broken terminfo and termcap databases on xterminals */
 291 static key_define_t xterm_key_defines[] = {
 292     { KEY_F (1), ESC_STR "OP", MCKEY_NOACTION },
 293     { KEY_F (2), ESC_STR "OQ", MCKEY_NOACTION },
 294     { KEY_F (3), ESC_STR "OR", MCKEY_NOACTION },
 295     { KEY_F (4), ESC_STR "OS", MCKEY_NOACTION },
 296     { KEY_F (1), ESC_STR "[11~", MCKEY_NOACTION },
 297     { KEY_F (2), ESC_STR "[12~", MCKEY_NOACTION },
 298     { KEY_F (3), ESC_STR "[13~", MCKEY_NOACTION },
 299     { KEY_F (4), ESC_STR "[14~", MCKEY_NOACTION },
 300     { KEY_F (5), ESC_STR "[15~", MCKEY_NOACTION },
 301     { KEY_F (6), ESC_STR "[17~", MCKEY_NOACTION },
 302     { KEY_F (7), ESC_STR "[18~", MCKEY_NOACTION },
 303     { KEY_F (8), ESC_STR "[19~", MCKEY_NOACTION },
 304     { KEY_F (9), ESC_STR "[20~", MCKEY_NOACTION },
 305     { KEY_F (10), ESC_STR "[21~", MCKEY_NOACTION },
 306 
 307     // old xterm Shift-arrows
 308     { KEY_M_SHIFT | KEY_UP, ESC_STR "O2A", MCKEY_NOACTION },
 309     { KEY_M_SHIFT | KEY_DOWN, ESC_STR "O2B", MCKEY_NOACTION },
 310     { KEY_M_SHIFT | KEY_RIGHT, ESC_STR "O2C", MCKEY_NOACTION },
 311     { KEY_M_SHIFT | KEY_LEFT, ESC_STR "O2D", MCKEY_NOACTION },
 312 
 313     // new xterm Shift-arrows
 314     { KEY_M_SHIFT | KEY_UP, ESC_STR "[1;2A", MCKEY_NOACTION },
 315     { KEY_M_SHIFT | KEY_DOWN, ESC_STR "[1;2B", MCKEY_NOACTION },
 316     { KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[1;2C", MCKEY_NOACTION },
 317     { KEY_M_SHIFT | KEY_LEFT, ESC_STR "[1;2D", MCKEY_NOACTION },
 318 
 319     // more xterm keys with modifiers
 320     { KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5;5~", MCKEY_NOACTION },
 321     { KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6;5~", MCKEY_NOACTION },
 322     { KEY_M_CTRL | KEY_IC, ESC_STR "[2;5~", MCKEY_NOACTION },
 323     { KEY_M_CTRL | KEY_DC, ESC_STR "[3;5~", MCKEY_NOACTION },
 324     { KEY_M_CTRL | KEY_HOME, ESC_STR "[1;5H", MCKEY_NOACTION },
 325     { KEY_M_CTRL | KEY_END, ESC_STR "[1;5F", MCKEY_NOACTION },
 326     { KEY_M_SHIFT | KEY_HOME, ESC_STR "[1;2H", MCKEY_NOACTION },
 327     { KEY_M_SHIFT | KEY_END, ESC_STR "[1;2F", MCKEY_NOACTION },
 328     { KEY_M_CTRL | KEY_UP, ESC_STR "[1;5A", MCKEY_NOACTION },
 329     { KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;5B", MCKEY_NOACTION },
 330     { KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;5C", MCKEY_NOACTION },
 331     { KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;5D", MCKEY_NOACTION },
 332     { KEY_M_SHIFT | KEY_IC, ESC_STR "[2;2~", MCKEY_NOACTION },
 333     { KEY_M_SHIFT | KEY_DC, ESC_STR "[3;2~", MCKEY_NOACTION },
 334     { KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[1;6A", MCKEY_NOACTION },
 335     { KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;6B", MCKEY_NOACTION },
 336     { KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;6C", MCKEY_NOACTION },
 337     { KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;6D", MCKEY_NOACTION },
 338     { KEY_M_SHIFT | '\t', ESC_STR "[Z", MCKEY_NOACTION },
 339 
 340     // putty
 341     { KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[[1;6A", MCKEY_NOACTION },
 342     { KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[[1;6B", MCKEY_NOACTION },
 343     { KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[[1;6C", MCKEY_NOACTION },
 344     { KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[[1;6D", MCKEY_NOACTION },
 345 
 346     // putty alt-arrow keys
 347     // removed as source esc esc esc trouble
 348     /*
 349        { KEY_M_ALT | KEY_UP,    ESC_STR ESC_STR "OA", MCKEY_NOACTION },
 350        { KEY_M_ALT | KEY_DOWN,  ESC_STR ESC_STR "OB", MCKEY_NOACTION },
 351        { KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "OC", MCKEY_NOACTION },
 352        { KEY_M_ALT | KEY_LEFT,  ESC_STR ESC_STR "OD", MCKEY_NOACTION },
 353        { KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[5~", MCKEY_NOACTION },
 354        { KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[6~", MCKEY_NOACTION },
 355        { KEY_M_ALT | KEY_HOME,  ESC_STR ESC_STR "[1~", MCKEY_NOACTION },
 356        { KEY_M_ALT | KEY_END,   ESC_STR ESC_STR "[4~", MCKEY_NOACTION },
 357 
 358        { KEY_M_CTRL | KEY_M_ALT | KEY_UP,    ESC_STR ESC_STR "[1;2A", MCKEY_NOACTION },
 359        { KEY_M_CTRL | KEY_M_ALT | KEY_DOWN,  ESC_STR ESC_STR "[1;2B", MCKEY_NOACTION },
 360        { KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "[1;2C", MCKEY_NOACTION },
 361        { KEY_M_CTRL | KEY_M_ALT | KEY_LEFT,  ESC_STR ESC_STR "[1;2D", MCKEY_NOACTION },
 362 
 363        { KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[[5;5~", MCKEY_NOACTION },
 364        { KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[[6;5~", MCKEY_NOACTION },
 365        { KEY_M_CTRL | KEY_M_ALT | KEY_HOME,  ESC_STR ESC_STR "[1;5H", MCKEY_NOACTION },
 366        { KEY_M_CTRL | KEY_M_ALT | KEY_END,   ESC_STR ESC_STR "[1;5F", MCKEY_NOACTION },
 367      */
 368     // xterm alt-arrow keys
 369     { KEY_M_ALT | KEY_UP, ESC_STR "[1;3A", MCKEY_NOACTION },
 370     { KEY_M_ALT | KEY_DOWN, ESC_STR "[1;3B", MCKEY_NOACTION },
 371     { KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;3C", MCKEY_NOACTION },
 372     { KEY_M_ALT | KEY_LEFT, ESC_STR "[1;3D", MCKEY_NOACTION },
 373     { KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;3~", MCKEY_NOACTION },
 374     { KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;3~", MCKEY_NOACTION },
 375     { KEY_M_ALT | KEY_HOME, ESC_STR "[1~", MCKEY_NOACTION },
 376     { KEY_M_ALT | KEY_END, ESC_STR "[4~", MCKEY_NOACTION },
 377     { KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR "[1;7A", MCKEY_NOACTION },
 378     { KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR "[1;7B", MCKEY_NOACTION },
 379     { KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;7C", MCKEY_NOACTION },
 380     { KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR "[1;7D", MCKEY_NOACTION },
 381     { KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;7~", MCKEY_NOACTION },
 382     { KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;7~", MCKEY_NOACTION },
 383     { KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR "OH", MCKEY_NOACTION },
 384     { KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR "OF", MCKEY_NOACTION },
 385 
 386     { KEY_M_SHIFT | KEY_M_ALT | KEY_UP, ESC_STR "[1;4A", MCKEY_NOACTION },
 387     { KEY_M_SHIFT | KEY_M_ALT | KEY_DOWN, ESC_STR "[1;4B", MCKEY_NOACTION },
 388     { KEY_M_SHIFT | KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;4C", MCKEY_NOACTION },
 389     { KEY_M_SHIFT | KEY_M_ALT | KEY_LEFT, ESC_STR "[1;4D", MCKEY_NOACTION },
 390 
 391     // rxvt keys with modifiers
 392     { KEY_M_SHIFT | KEY_UP, ESC_STR "[a", MCKEY_NOACTION },
 393     { KEY_M_SHIFT | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION },
 394     { KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION },
 395     { KEY_M_SHIFT | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION },
 396     { KEY_M_CTRL | KEY_UP, ESC_STR "Oa", MCKEY_NOACTION },
 397     { KEY_M_CTRL | KEY_DOWN, ESC_STR "Ob", MCKEY_NOACTION },
 398     { KEY_M_CTRL | KEY_RIGHT, ESC_STR "Oc", MCKEY_NOACTION },
 399     { KEY_M_CTRL | KEY_LEFT, ESC_STR "Od", MCKEY_NOACTION },
 400     { KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5^", MCKEY_NOACTION },
 401     { KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6^", MCKEY_NOACTION },
 402     { KEY_M_CTRL | KEY_HOME, ESC_STR "[7^", MCKEY_NOACTION },
 403     { KEY_M_CTRL | KEY_END, ESC_STR "[8^", MCKEY_NOACTION },
 404     { KEY_M_SHIFT | KEY_HOME, ESC_STR "[7$", MCKEY_NOACTION },
 405     { KEY_M_SHIFT | KEY_END, ESC_STR "[8$", MCKEY_NOACTION },
 406     { KEY_M_CTRL | KEY_IC, ESC_STR "[2^", MCKEY_NOACTION },
 407     { KEY_M_CTRL | KEY_DC, ESC_STR "[3^", MCKEY_NOACTION },
 408     { KEY_M_SHIFT | KEY_DC, ESC_STR "[3$", MCKEY_NOACTION },
 409 
 410     // konsole keys with modifiers
 411     { KEY_M_SHIFT | KEY_HOME, ESC_STR "O2H", MCKEY_NOACTION },
 412     { KEY_M_SHIFT | KEY_END, ESC_STR "O2F", MCKEY_NOACTION },
 413 
 414     // gnome-terminal
 415     { KEY_M_SHIFT | KEY_UP, ESC_STR "[2A", MCKEY_NOACTION },
 416     { KEY_M_SHIFT | KEY_DOWN, ESC_STR "[2B", MCKEY_NOACTION },
 417     { KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[2C", MCKEY_NOACTION },
 418     { KEY_M_SHIFT | KEY_LEFT, ESC_STR "[2D", MCKEY_NOACTION },
 419     { KEY_M_CTRL | KEY_UP, ESC_STR "[5A", MCKEY_NOACTION },
 420     { KEY_M_CTRL | KEY_DOWN, ESC_STR "[5B", MCKEY_NOACTION },
 421     { KEY_M_CTRL | KEY_RIGHT, ESC_STR "[5C", MCKEY_NOACTION },
 422     { KEY_M_CTRL | KEY_LEFT, ESC_STR "[5D", MCKEY_NOACTION },
 423     { KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[6A", MCKEY_NOACTION },
 424     { KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[6B", MCKEY_NOACTION },
 425     { KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[6C", MCKEY_NOACTION },
 426     { KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[6D", MCKEY_NOACTION },
 427 
 428     // gnome-terminal - application mode
 429     { KEY_M_CTRL | KEY_UP, ESC_STR "O5A", MCKEY_NOACTION },
 430     { KEY_M_CTRL | KEY_DOWN, ESC_STR "O5B", MCKEY_NOACTION },
 431     { KEY_M_CTRL | KEY_RIGHT, ESC_STR "O5C", MCKEY_NOACTION },
 432     { KEY_M_CTRL | KEY_LEFT, ESC_STR "O5D", MCKEY_NOACTION },
 433     { KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "O6A", MCKEY_NOACTION },
 434     { KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "O6B", MCKEY_NOACTION },
 435     { KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "O6C", MCKEY_NOACTION },
 436     { KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "O6D", MCKEY_NOACTION },
 437 
 438     // iTerm
 439     { KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[5;2~", MCKEY_NOACTION },
 440     { KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[6;2~", MCKEY_NOACTION },
 441 
 442     // putty
 443     { KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[[5;53~", MCKEY_NOACTION },
 444     { KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[[6;53~", MCKEY_NOACTION },
 445 
 446     // keypad keys
 447     { KEY_IC, ESC_STR "Op", MCKEY_NOACTION },
 448     { KEY_DC, ESC_STR "On", MCKEY_NOACTION },
 449     { '/', ESC_STR "Oo", MCKEY_NOACTION },
 450     { '\n', ESC_STR "OM", MCKEY_NOACTION },
 451 
 452     { 0, NULL, MCKEY_NOACTION },
 453 };
 454 
 455 /* qansi-m terminals have a much more key combinations,
 456    which are undefined in termcap/terminfo */
 457 static key_define_t qansi_key_defines[] = {
 458     // qansi-m terminal
 459     { KEY_M_CTRL | KEY_NPAGE, ESC_STR "[u", MCKEY_NOACTION },        // Ctrl-PgDown
 460     { KEY_M_CTRL | KEY_PPAGE, ESC_STR "[v", MCKEY_NOACTION },        // Ctrl-PgUp
 461     { KEY_M_CTRL | KEY_HOME, ESC_STR "[h", MCKEY_NOACTION },         // Ctrl-Home
 462     { KEY_M_CTRL | KEY_END, ESC_STR "[y", MCKEY_NOACTION },          // Ctrl-End
 463     { KEY_M_CTRL | KEY_IC, ESC_STR "[`", MCKEY_NOACTION },           // Ctrl-Insert
 464     { KEY_M_CTRL | KEY_DC, ESC_STR "[p", MCKEY_NOACTION },           // Ctrl-Delete
 465     { KEY_M_CTRL | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION },         // Ctrl-Left
 466     { KEY_M_CTRL | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION },        // Ctrl-Right
 467     { KEY_M_CTRL | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION },         // Ctrl-Down
 468     { KEY_M_CTRL | KEY_UP, ESC_STR "[a", MCKEY_NOACTION },           // Ctrl-Up
 469     { KEY_M_CTRL | KEY_KP_ADD, ESC_STR "[s", MCKEY_NOACTION },       // Ctrl-Gr-Plus
 470     { KEY_M_CTRL | KEY_KP_SUBTRACT, ESC_STR "[t", MCKEY_NOACTION },  // Ctrl-Gr-Minus
 471     { KEY_M_CTRL | '\t', ESC_STR "[z", MCKEY_NOACTION },             // Ctrl-Tab
 472     { KEY_M_SHIFT | '\t', ESC_STR "[Z", MCKEY_NOACTION },            // Shift-Tab
 473     { KEY_M_CTRL | KEY_F (1), ESC_STR "[1~", MCKEY_NOACTION },       // Ctrl-F1
 474     { KEY_M_CTRL | KEY_F (2), ESC_STR "[2~", MCKEY_NOACTION },       // Ctrl-F2
 475     { KEY_M_CTRL | KEY_F (3), ESC_STR "[3~", MCKEY_NOACTION },       // Ctrl-F3
 476     { KEY_M_CTRL | KEY_F (4), ESC_STR "[4~", MCKEY_NOACTION },       // Ctrl-F4
 477     { KEY_M_CTRL | KEY_F (5), ESC_STR "[5~", MCKEY_NOACTION },       // Ctrl-F5
 478     { KEY_M_CTRL | KEY_F (6), ESC_STR "[6~", MCKEY_NOACTION },       // Ctrl-F6
 479     { KEY_M_CTRL | KEY_F (7), ESC_STR "[7~", MCKEY_NOACTION },       // Ctrl-F7
 480     { KEY_M_CTRL | KEY_F (8), ESC_STR "[8~", MCKEY_NOACTION },       // Ctrl-F8
 481     { KEY_M_CTRL | KEY_F (9), ESC_STR "[9~", MCKEY_NOACTION },       // Ctrl-F9
 482     { KEY_M_CTRL | KEY_F (10), ESC_STR "[10~", MCKEY_NOACTION },     // Ctrl-F10
 483     { KEY_M_CTRL | KEY_F (11), ESC_STR "[11~", MCKEY_NOACTION },     // Ctrl-F11
 484     { KEY_M_CTRL | KEY_F (12), ESC_STR "[12~", MCKEY_NOACTION },     // Ctrl-F12
 485     { KEY_M_ALT | KEY_F (1), ESC_STR "[17~", MCKEY_NOACTION },       // Alt-F1
 486     { KEY_M_ALT | KEY_F (2), ESC_STR "[18~", MCKEY_NOACTION },       // Alt-F2
 487     { KEY_M_ALT | KEY_F (3), ESC_STR "[19~", MCKEY_NOACTION },       // Alt-F3
 488     { KEY_M_ALT | KEY_F (4), ESC_STR "[20~", MCKEY_NOACTION },       // Alt-F4
 489     { KEY_M_ALT | KEY_F (5), ESC_STR "[21~", MCKEY_NOACTION },       // Alt-F5
 490     { KEY_M_ALT | KEY_F (6), ESC_STR "[22~", MCKEY_NOACTION },       // Alt-F6
 491     { KEY_M_ALT | KEY_F (7), ESC_STR "[23~", MCKEY_NOACTION },       // Alt-F7
 492     { KEY_M_ALT | KEY_F (8), ESC_STR "[24~", MCKEY_NOACTION },       // Alt-F8
 493     { KEY_M_ALT | KEY_F (9), ESC_STR "[25~", MCKEY_NOACTION },       // Alt-F9
 494     { KEY_M_ALT | KEY_F (10), ESC_STR "[26~", MCKEY_NOACTION },      // Alt-F10
 495     { KEY_M_ALT | KEY_F (11), ESC_STR "[27~", MCKEY_NOACTION },      // Alt-F11
 496     { KEY_M_ALT | KEY_F (12), ESC_STR "[28~", MCKEY_NOACTION },      // Alt-F12
 497     { KEY_M_ALT | 'a', ESC_STR "Na", MCKEY_NOACTION },               // Alt-a
 498     { KEY_M_ALT | 'b', ESC_STR "Nb", MCKEY_NOACTION },               // Alt-b
 499     { KEY_M_ALT | 'c', ESC_STR "Nc", MCKEY_NOACTION },               // Alt-c
 500     { KEY_M_ALT | 'd', ESC_STR "Nd", MCKEY_NOACTION },               // Alt-d
 501     { KEY_M_ALT | 'e', ESC_STR "Ne", MCKEY_NOACTION },               // Alt-e
 502     { KEY_M_ALT | 'f', ESC_STR "Nf", MCKEY_NOACTION },               // Alt-f
 503     { KEY_M_ALT | 'g', ESC_STR "Ng", MCKEY_NOACTION },               // Alt-g
 504     { KEY_M_ALT | 'h', ESC_STR "Nh", MCKEY_NOACTION },               // Alt-h
 505     { KEY_M_ALT | 'i', ESC_STR "Ni", MCKEY_NOACTION },               // Alt-i
 506     { KEY_M_ALT | 'j', ESC_STR "Nj", MCKEY_NOACTION },               // Alt-j
 507     { KEY_M_ALT | 'k', ESC_STR "Nk", MCKEY_NOACTION },               // Alt-k
 508     { KEY_M_ALT | 'l', ESC_STR "Nl", MCKEY_NOACTION },               // Alt-l
 509     { KEY_M_ALT | 'm', ESC_STR "Nm", MCKEY_NOACTION },               // Alt-m
 510     { KEY_M_ALT | 'n', ESC_STR "Nn", MCKEY_NOACTION },               // Alt-n
 511     { KEY_M_ALT | 'o', ESC_STR "No", MCKEY_NOACTION },               // Alt-o
 512     { KEY_M_ALT | 'p', ESC_STR "Np", MCKEY_NOACTION },               // Alt-p
 513     { KEY_M_ALT | 'q', ESC_STR "Nq", MCKEY_NOACTION },               // Alt-q
 514     { KEY_M_ALT | 'r', ESC_STR "Nr", MCKEY_NOACTION },               // Alt-r
 515     { KEY_M_ALT | 's', ESC_STR "Ns", MCKEY_NOACTION },               // Alt-s
 516     { KEY_M_ALT | 't', ESC_STR "Nt", MCKEY_NOACTION },               // Alt-t
 517     { KEY_M_ALT | 'u', ESC_STR "Nu", MCKEY_NOACTION },               // Alt-u
 518     { KEY_M_ALT | 'v', ESC_STR "Nv", MCKEY_NOACTION },               // Alt-v
 519     { KEY_M_ALT | 'w', ESC_STR "Nw", MCKEY_NOACTION },               // Alt-w
 520     { KEY_M_ALT | 'x', ESC_STR "Nx", MCKEY_NOACTION },               // Alt-x
 521     { KEY_M_ALT | 'y', ESC_STR "Ny", MCKEY_NOACTION },               // Alt-y
 522     { KEY_M_ALT | 'z', ESC_STR "Nz", MCKEY_NOACTION },               // Alt-z
 523     { KEY_KP_SUBTRACT, ESC_STR "[S", MCKEY_NOACTION },               // Gr-Minus
 524     { KEY_KP_ADD, ESC_STR "[T", MCKEY_NOACTION },                    // Gr-Plus
 525     { 0, NULL, MCKEY_NOACTION },
 526 };
 527 
 528 /* This holds all the key definitions */
 529 static key_def *keys = NULL;
 530 
 531 static int input_fd;
 532 static int disabled_channels = 0;  // Disable channels checking
 533 
 534 static GSList *select_list = NULL;
 535 
 536 static int seq_buffer[SEQ_BUFFER_LEN];
 537 static int *seq_append = NULL;
 538 
 539 static int *pending_keys = NULL;
 540 
 541 #ifdef __QNXNTO__
 542 ph_dv_f ph_attach;
 543 ph_ov_f ph_input_group;
 544 ph_pqc_f ph_query_cursor;
 545 #endif
 546 
 547 #ifdef HAVE_TEXTMODE_X11_SUPPORT
 548 static Display *x11_display;
 549 static Window x11_window;
 550 #endif
 551 
 552 static KeySortType has_been_sorted = KEY_NOSORT;
 553 
 554 static const size_t key_conv_tab_size = G_N_ELEMENTS (key_name_conv_tab) - 1;
 555 
 556 static const key_code_name_t *key_conv_tab_sorted[G_N_ELEMENTS (key_name_conv_tab) - 1];
 557 
 558 /* --------------------------------------------------------------------------------------------- */
 559 /*** file scope functions ************************************************************************/
 560 /* --------------------------------------------------------------------------------------------- */
 561 
 562 static int
 563 select_cmp_by_fd_set (gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 564 {
 565     const select_t *s = (const select_t *) a;
 566     const fd_set *f = (const fd_set *) b;
 567 
 568     return (FD_ISSET (s->fd, f) ? 0 : 1);
 569 }
 570 
 571 /* --------------------------------------------------------------------------------------------- */
 572 
 573 static int
 574 select_cmp_by_fd (gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 575 {
 576     const select_t *s = (const select_t *) a;
 577     const int fd = GPOINTER_TO_INT (b);
 578 
 579     return (s->fd == fd ? 0 : 1);
 580 }
 581 
 582 /* --------------------------------------------------------------------------------------------- */
 583 
 584 static int
 585 add_selects (fd_set *select_set)
     /* [previous][next][first][last][top][bottom][index][help]  */
 586 {
 587     int top_fd = 0;
 588 
 589     if (disabled_channels == 0)
 590     {
 591         GSList *s;
 592 
 593         for (s = select_list; s != NULL; s = g_slist_next (s))
 594         {
 595             select_t *p = (select_t *) s->data;
 596 
 597             FD_SET (p->fd, select_set);
 598             if (p->fd > top_fd)
 599                 top_fd = p->fd;
 600         }
 601     }
 602 
 603     return top_fd;
 604 }
 605 
 606 /* --------------------------------------------------------------------------------------------- */
 607 
 608 static void
 609 check_selects (fd_set *select_set)
     /* [previous][next][first][last][top][bottom][index][help]  */
 610 {
 611     while (disabled_channels == 0)
 612     {
 613         GSList *s;
 614         select_t *p;
 615 
 616         s = g_slist_find_custom (select_list, select_set, select_cmp_by_fd_set);
 617         if (s == NULL)
 618             break;
 619 
 620         p = (select_t *) s->data;
 621         FD_CLR (p->fd, select_set);
 622         p->callback (p->fd, p->info);
 623     }
 624 }
 625 
 626 /* --------------------------------------------------------------------------------------------- */
 627 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
 628 
 629 static void
 630 try_channels (gboolean set_timeout)
     /* [previous][next][first][last][top][bottom][index][help]  */
 631 {
 632     struct timeval time_out;
 633     static fd_set select_set;
 634 
 635     while (TRUE)
 636     {
 637         struct timeval *timeptr = NULL;
 638         int maxfdp, v;
 639 
 640         FD_ZERO (&select_set);
 641         FD_SET (input_fd, &select_set);  // Add stdin
 642         maxfdp = MAX (add_selects (&select_set), input_fd);
 643 
 644         if (set_timeout)
 645         {
 646             time_out.tv_sec = 0;
 647             time_out.tv_usec = 100 * MC_USEC_PER_MSEC;
 648             timeptr = &time_out;
 649         }
 650 
 651         v = select (maxfdp + 1, &select_set, NULL, NULL, timeptr);
 652         if (v > 0)
 653         {
 654             check_selects (&select_set);
 655             if (FD_ISSET (input_fd, &select_set))
 656                 break;
 657         }
 658     }
 659 }
 660 
 661 /* --------------------------------------------------------------------------------------------- */
 662 
 663 static key_def *
 664 create_sequence (const char *seq, int code, int action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 665 {
 666     key_def *base, *attach;
 667 
 668     for (base = attach = NULL; *seq != '\0'; seq++)
 669     {
 670         key_def *p;
 671 
 672         p = g_new (key_def, 1);
 673         if (base == NULL)
 674             base = p;
 675         if (attach != NULL)
 676             attach->child = p;
 677 
 678         p->ch = *seq;
 679         p->code = code;
 680         p->child = NULL;
 681         p->next = NULL;
 682         p->action = seq[1] == '\0' ? action : MCKEY_NOACTION;
 683         attach = p;
 684     }
 685     return base;
 686 }
 687 
 688 /* --------------------------------------------------------------------------------------------- */
 689 
 690 static void
 691 define_sequences (const key_define_t *kd)
     /* [previous][next][first][last][top][bottom][index][help]  */
 692 {
 693     int i;
 694 
 695     for (i = 0; kd[i].code != 0; i++)
 696         define_sequence (kd[i].code, kd[i].seq, kd[i].action);
 697 }
 698 
 699 /* --------------------------------------------------------------------------------------------- */
 700 
 701 #ifdef HAVE_TEXTMODE_X11_SUPPORT
 702 static void
 703 init_key_x11 (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 704 {
 705     if (getenv ("DISPLAY") != NULL && !mc_global.tty.disable_x11)
 706     {
 707         x11_display = mc_XOpenDisplay (0);
 708 
 709         if (x11_display != NULL)
 710             x11_window = DefaultRootWindow (x11_display);
 711     }
 712 }
 713 #endif
 714 
 715 /* --------------------------------------------------------------------------------------------- */
 716 /* Workaround for System V Curses vt100 bug */
 717 
 718 static int
 719 getch_with_delay (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 720 {
 721     int c;
 722 
 723     /* This routine could be used on systems without mouse support,
 724        so we need to do the select check :-( */
 725     while (TRUE)
 726     {
 727         if (pending_keys == NULL)
 728             try_channels (FALSE);
 729 
 730         // Try to get a character
 731         c = get_key_code (0);
 732         if (c != -1)
 733             break;
 734 
 735         // Failed -> wait 0.1 secs and try again
 736         try_channels (TRUE);
 737     }
 738 
 739     // Success -> return the character
 740     return c;
 741 }
 742 
 743 /* --------------------------------------------------------------------------------------------- */
 744 
 745 static void
 746 xmouse_get_event (Gpm_Event *ev, gboolean extended)
     /* [previous][next][first][last][top][bottom][index][help]  */
 747 {
 748     static gint64 tv1 = 0;  // Force first click as single
 749     static int clicks = 0;
 750     static int last_btn = 0;
 751     int btn;
 752 
 753     // Decode Xterm mouse information to a GPM style event
 754 
 755     if (!extended)
 756     {
 757         // Variable btn has following meaning:
 758         // 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up
 759         btn = tty_lowlevel_getch () - 32;
 760         // Coordinates are 33-based
 761         // Transform them to 1-based
 762         ev->x = tty_lowlevel_getch () - 32;
 763         ev->y = tty_lowlevel_getch () - 32;
 764     }
 765     else
 766     {
 767         /* SGR 1006 extension (e.g. "\e[<0;12;300M"):
 768            - Numbers are encoded in decimal to make it ASCII-safe
 769            and to overcome the limit of 223 columns/rows.
 770            - Mouse release is encoded by trailing 'm' rather than 'M'
 771            so that the released button can be reported.
 772            - Numbers are no longer offset by 32. */
 773         char c;
 774 
 775         btn = ev->x = ev->y = 0;
 776         ev->type = 0;  // In case we return on an invalid sequence
 777 
 778         while ((c = tty_lowlevel_getch ()) != ';')
 779         {
 780             if (c < '0' || c > '9')
 781                 return;
 782             btn = 10 * btn + (c - '0');
 783         }
 784         while ((c = tty_lowlevel_getch ()) != ';')
 785         {
 786             if (c < '0' || c > '9')
 787                 return;
 788             ev->x = 10 * ev->x + (c - '0');
 789         }
 790         while ((c = tty_lowlevel_getch ()) != 'M' && c != 'm')
 791         {
 792             if (c < '0' || c > '9')
 793                 return;
 794             ev->y = 10 * ev->y + (c - '0');
 795         }
 796         /* Legacy mouse protocol doesn't tell which button was released,
 797            conveniently all of mc's widgets are written not to rely on this
 798            information. With the SGR extension the released button becomes
 799            known, but for the sake of simplicity we just ignore it. */
 800         if (c == 'm')
 801             btn = 3;
 802     }
 803 
 804     // There seems to be no way of knowing which button was released
 805     // So we assume all the buttons were released
 806 
 807     if (btn == 3)
 808     {
 809         if (last_btn != 0)
 810         {
 811             if ((last_btn & (GPM_B_UP | GPM_B_DOWN)) != 0)
 812             {
 813                 // FIXME: DIRTY HACK
 814                 // don't generate GPM_UP after mouse wheel
 815                 // need for menu event handling
 816                 ev->type = 0;
 817                 tv1 = 0;
 818             }
 819             else
 820             {
 821                 ev->type = GPM_UP | (GPM_SINGLE << clicks);
 822                 tv1 = g_get_monotonic_time ();
 823             }
 824             ev->buttons = 0;
 825             last_btn = 0;
 826             clicks = 0;
 827         }
 828         else
 829         {
 830             // Bogus event, maybe mouse wheel
 831             ev->type = 0;
 832         }
 833     }
 834     else
 835     {
 836         gint64 tv2;
 837 
 838         if (btn >= 32 && btn <= 34)
 839         {
 840             btn -= 32;
 841             ev->type = GPM_DRAG;
 842         }
 843         else
 844             ev->type = GPM_DOWN;
 845 
 846         tv2 = g_get_monotonic_time ();
 847         if (tv1 != 0 && tv2 - tv1 < (gint64) double_click_speed * MC_USEC_PER_MSEC)
 848         {
 849             clicks++;
 850             clicks %= 3;
 851         }
 852         else
 853             clicks = 0;
 854 
 855         switch (btn)
 856         {
 857         case 0:
 858             ev->buttons = GPM_B_LEFT;
 859             break;
 860         case 1:
 861             ev->buttons = GPM_B_MIDDLE;
 862             break;
 863         case 2:
 864             ev->buttons = GPM_B_RIGHT;
 865             break;
 866         case 64:
 867             ev->buttons = GPM_B_UP;
 868             clicks = 0;
 869             break;
 870         case 65:
 871             ev->buttons = GPM_B_DOWN;
 872             clicks = 0;
 873             break;
 874         default:
 875             // Nothing
 876             ev->type = 0;
 877             ev->buttons = 0;
 878             break;
 879         }
 880         last_btn = ev->buttons;
 881     }
 882 }
 883 
 884 /* --------------------------------------------------------------------------------------------- */
 885 /**
 886  * Get modifier state (shift, alt, ctrl) for the last key pressed.
 887  * We are assuming that the state didn't change since the key press.
 888  * This is only correct if get_modifier() is called very fast after
 889  * the input was received, so that the user didn't release the
 890  * modifier keys yet.
 891  */
 892 
 893 static int
 894 get_modifier (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 895 {
 896     int result = 0;
 897 #ifdef __QNXNTO__
 898     static int in_photon = 0;
 899     static int ph_ig = 0;
 900 #endif
 901 
 902 #ifdef HAVE_TEXTMODE_X11_SUPPORT
 903     if (x11_window != 0)
 904     {
 905         Window root, child;
 906         int root_x, root_y;
 907         int win_x, win_y;
 908         unsigned int mask;
 909 
 910         mc_XQueryPointer (x11_display, x11_window, &root, &child, &root_x, &root_y, &win_x, &win_y,
 911                           &mask);
 912 
 913         if ((mask & ShiftMask) != 0)
 914             result |= KEY_M_SHIFT;
 915         if ((mask & ControlMask) != 0)
 916             result |= KEY_M_CTRL;
 917         return result;
 918     }
 919 #endif
 920 
 921 #ifdef __QNXNTO__
 922     if (in_photon == 0)
 923     {
 924         // First time here, let's load Photon library and attach to Photon
 925         in_photon = -1;
 926 
 927         if (getenv ("PHOTON2_PATH") != NULL)
 928         {
 929             // QNX 6.x has no support for RTLD_LAZY
 930             void *ph_handle;
 931 
 932             ph_handle = dlopen ("/usr/lib/libph.so", RTLD_NOW);
 933             if (ph_handle != NULL)
 934             {
 935                 ph_attach = (ph_dv_f) dlsym (ph_handle, "PhAttach");
 936                 ph_input_group = (ph_ov_f) dlsym (ph_handle, "PhInputGroup");
 937                 ph_query_cursor = (ph_pqc_f) dlsym (ph_handle, "PhQueryCursor");
 938                 if ((ph_attach != NULL) && (ph_input_group != NULL) && (ph_query_cursor != NULL)
 939                     && (*ph_attach) (0, 0) != NULL)
 940                 {
 941                     // Attached
 942                     ph_ig = (*ph_input_group) (0);
 943                     in_photon = 1;
 944                 }
 945             }
 946         }
 947     }
 948     // We do not have Photon running. Assume we are in text console or xterm
 949     if (in_photon == -1)
 950     {
 951         int mod_status;
 952         int shift_ext_status;
 953 
 954         if (devctl (fileno (stdin), DCMD_CHR_LINESTATUS, &mod_status, sizeof (mod_status), NULL)
 955             == -1)
 956             return 0;
 957 
 958         shift_ext_status = mod_status & 0xffffff00UL;
 959         mod_status &= 0x7f;
 960         if ((mod_status & _LINESTATUS_CON_ALT) != 0)
 961             result |= KEY_M_ALT;
 962         if ((mod_status & _LINESTATUS_CON_CTRL) != 0)
 963             result |= KEY_M_CTRL;
 964         if ((mod_status & _LINESTATUS_CON_SHIFT) != 0 || (shift_ext_status & 0x00000800UL) != 0)
 965             result |= KEY_M_SHIFT;
 966     }
 967     else
 968     {
 969         PhCursorInfo_t cursor_info;
 970 
 971         (*ph_query_cursor) (ph_ig, &cursor_info);
 972         if ((cursor_info.key_mods & 0x04) != 0)
 973             result |= KEY_M_ALT;
 974         if ((cursor_info.key_mods & 0x02) != 0)
 975             result |= KEY_M_CTRL;
 976         if ((cursor_info.key_mods & 0x01) != 0)
 977             result |= KEY_M_SHIFT;
 978     }
 979 #endif
 980 
 981 #if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX)
 982     {
 983         unsigned char modifiers = 6;
 984 
 985         if (ioctl (0, TIOCLINUX, &modifiers) < 0)
 986             return 0;
 987 
 988         // Translate Linux modifiers into mc modifiers
 989         if ((modifiers & SHIFT_PRESSED) != 0)
 990             result |= KEY_M_SHIFT;
 991         if ((modifiers & (ALTL_PRESSED | ALTR_PRESSED)) != 0)
 992             result |= KEY_M_ALT;
 993         if ((modifiers & CONTROL_PRESSED) != 0)
 994             result |= KEY_M_CTRL;
 995     }
 996 #endif
 997 
 998     return result;
 999 }
1000 
1001 /* --------------------------------------------------------------------------------------------- */
1002 
1003 static gboolean
1004 push_char (int c)
     /* [previous][next][first][last][top][bottom][index][help]  */
1005 {
1006     gboolean ret = FALSE;
1007 
1008     if (seq_append == NULL)
1009         seq_append = seq_buffer;
1010 
1011     if (seq_append != &(seq_buffer[SEQ_BUFFER_LEN - 2]))
1012     {
1013         *(seq_append++) = c;
1014         *seq_append = '\0';
1015         ret = TRUE;
1016     }
1017 
1018     return ret;
1019 }
1020 
1021 /* --------------------------------------------------------------------------------------------- */
1022 /* Apply corrections for the keycode generated in get_key_code() */
1023 
1024 static int
1025 correct_key_code (int code)
     /* [previous][next][first][last][top][bottom][index][help]  */
1026 {
1027     unsigned int c = code & ~KEY_M_MASK;   // code without modifier
1028     unsigned int mod = code & KEY_M_MASK;  // modifier
1029 #ifdef __QNXNTO__
1030     unsigned int qmod; /* bunch of the QNX console
1031                           modifiers needs unchanged */
1032 #endif
1033 
1034     /*
1035      * Add key modifiers directly from X11 or OS.
1036      * Ordinary characters only get modifiers from sequences.
1037      */
1038     if (c < 32 || c >= 256)
1039         mod |= get_modifier ();
1040 
1041     // This is needed if the newline is reported as carriage return
1042     if (c == '\r')
1043         c = '\n';
1044 
1045     // This is reported to be useful on AIX
1046     if (c == KEY_SCANCEL)
1047         c = '\t';
1048 
1049     // Convert Back Tab to Shift+Tab
1050     if (c == KEY_BTAB)
1051     {
1052         c = '\t';
1053         mod = KEY_M_SHIFT;
1054     }
1055 
1056     // F0 is the same as F10 for out purposes
1057     if (c == KEY_F (0))
1058         c = KEY_F (10);
1059 
1060     /*
1061      * We are not interested if Ctrl was pressed when entering control
1062      * characters, so assume that it was.  When checking for such keys,
1063      * XCTRL macro should be used.  In some cases, we are interested,
1064      * e.g. to distinguish Ctrl-Enter from Enter.
1065      */
1066     if (c == '\b')
1067     {
1068         // Special case for backspase ('\b' < 32)
1069         c = KEY_BACKSPACE;
1070         mod &= ~KEY_M_CTRL;
1071     }
1072     else if (c < 32 && c != ESC_CHAR && c != '\t' && c != '\n')
1073         mod |= KEY_M_CTRL;
1074 
1075 #ifdef __QNXNTO__
1076     qmod = get_modifier ();
1077 
1078     if (c == 127 && mod == 0)
1079     {
1080         // Add Ctrl/Alt/Shift-BackSpace
1081         mod |= get_modifier ();
1082         c = KEY_BACKSPACE;
1083     }
1084 
1085     if (c == '0' && mod == 0 && (qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1086     {
1087         // Add Shift-Insert on key pad
1088         mod = KEY_M_SHIFT;
1089         c = KEY_IC;
1090     }
1091 
1092     if (c == '.' && mod == 0 && (qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1093     {
1094         // Add Shift-Del on key pad
1095         mod = KEY_M_SHIFT;
1096         c = KEY_DC;
1097     }
1098 #endif
1099 
1100     // Unrecognized 0177 is delete (preserve Ctrl)
1101     if (c == 0177)
1102         c = KEY_BACKSPACE;
1103 
1104 #if 0
1105     // Unrecognized Ctrl-d is delete 
1106     if (c == 'd' & 31)
1107     {
1108         c = KEY_DC;
1109         mod &= ~KEY_M_CTRL;
1110     }
1111 
1112     // Unrecognized Ctrl-h is backspace 
1113     if (c == 'h' & 31)
1114     {
1115         c = KEY_BACKSPACE;
1116         mod &= ~KEY_M_CTRL;
1117     }
1118 #endif
1119 
1120     // Shift+BackSpace is backspace
1121     if (c == KEY_BACKSPACE && (mod & KEY_M_SHIFT) != 0)
1122         mod &= ~KEY_M_SHIFT;
1123 
1124     // Convert Shift+Fn to F(n+10)
1125     if (c >= KEY_F (1) && c <= KEY_F (10) && (mod & KEY_M_SHIFT) != 0)
1126         c += 10;
1127 
1128     // Remove Shift information from function keys
1129     if (c >= KEY_F (1) && c <= KEY_F (20))
1130         mod &= ~KEY_M_SHIFT;
1131 
1132     if (!mc_global.tty.alternate_plus_minus)
1133         switch (c)
1134         {
1135         case KEY_KP_ADD:
1136             c = '+';
1137             break;
1138         case KEY_KP_SUBTRACT:
1139             c = '-';
1140             break;
1141         case KEY_KP_MULTIPLY:
1142             c = '*';
1143             break;
1144         default:
1145             break;
1146         }
1147 
1148     return (mod | c);
1149 }
1150 
1151 /* --------------------------------------------------------------------------------------------- */
1152 
1153 static int
1154 getch_with_timeout (unsigned int delay_us)
     /* [previous][next][first][last][top][bottom][index][help]  */
1155 {
1156     fd_set Read_FD_Set;
1157     int c;
1158     struct timeval time_out;
1159 
1160     time_out.tv_sec = delay_us / G_USEC_PER_SEC;
1161     time_out.tv_usec = delay_us % G_USEC_PER_SEC;
1162     tty_nodelay (TRUE);
1163     FD_ZERO (&Read_FD_Set);
1164     FD_SET (input_fd, &Read_FD_Set);
1165     select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
1166     c = tty_lowlevel_getch ();
1167     tty_nodelay (FALSE);
1168     return c;
1169 }
1170 
1171 /* --------------------------------------------------------------------------------------------- */
1172 
1173 static void
1174 learn_store_key (GString *buffer, int c)
     /* [previous][next][first][last][top][bottom][index][help]  */
1175 {
1176     if (c == ESC_CHAR)
1177         g_string_append (buffer, "\\e");
1178     else if (c < ' ')
1179     {
1180         g_string_append_c (buffer, '^');
1181         g_string_append_c (buffer, c + 'a' - 1);
1182     }
1183     else if (c == '^')
1184         g_string_append (buffer, "^^");
1185     else
1186         g_string_append_c (buffer, (char) c);
1187 }
1188 
1189 /* --------------------------------------------------------------------------------------------- */
1190 
1191 static void
1192 k_dispose (key_def *k)
     /* [previous][next][first][last][top][bottom][index][help]  */
1193 {
1194     if (k != NULL)
1195     {
1196         k_dispose (k->child);
1197         k_dispose (k->next);
1198         g_free (k);
1199     }
1200 }
1201 
1202 /* --------------------------------------------------------------------------------------------- */
1203 
1204 static int
1205 key_code_comparator_by_name (const void *p1, const void *p2)
     /* [previous][next][first][last][top][bottom][index][help]  */
1206 {
1207     const key_code_name_t *n1 = *(const key_code_name_t *const *) p1;
1208     const key_code_name_t *n2 = *(const key_code_name_t *const *) p2;
1209 
1210     return g_ascii_strcasecmp (n1->name, n2->name);
1211 }
1212 
1213 /* --------------------------------------------------------------------------------------------- */
1214 
1215 static int
1216 key_code_comparator_by_code (const void *p1, const void *p2)
     /* [previous][next][first][last][top][bottom][index][help]  */
1217 {
1218     const key_code_name_t *n1 = *(const key_code_name_t *const *) p1;
1219     const key_code_name_t *n2 = *(const key_code_name_t *const *) p2;
1220 
1221     return n1->code - n2->code;
1222 }
1223 
1224 /* --------------------------------------------------------------------------------------------- */
1225 
1226 static inline void
1227 sort_key_conv_tab (enum KeySortType type_sort)
     /* [previous][next][first][last][top][bottom][index][help]  */
1228 {
1229     if (has_been_sorted != type_sort)
1230     {
1231         size_t i;
1232 
1233         for (i = 0; i < key_conv_tab_size; i++)
1234             key_conv_tab_sorted[i] = &key_name_conv_tab[i];
1235 
1236         if (type_sort == KEY_SORTBYNAME)
1237             qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1238                    &key_code_comparator_by_name);
1239         else if (type_sort == KEY_SORTBYCODE)
1240             qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1241                    &key_code_comparator_by_code);
1242 
1243         has_been_sorted = type_sort;
1244     }
1245 }
1246 
1247 /* --------------------------------------------------------------------------------------------- */
1248 
1249 static int
1250 lookup_keyname (const char *name, int *idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1251 {
1252     if (name[0] != '\0')
1253     {
1254         const key_code_name_t key = { 0, name, NULL, NULL };
1255         const key_code_name_t *keyp = &key;
1256         const key_code_name_t **res;
1257 
1258         if (name[1] == '\0')
1259         {
1260             *idx = -1;
1261             return (int) name[0];
1262         }
1263 
1264         sort_key_conv_tab (KEY_SORTBYNAME);
1265 
1266         res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1267                        sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_name);
1268 
1269         if (res != NULL)
1270         {
1271             *idx = (int) (res - key_conv_tab_sorted);
1272             return (*res)->code;
1273         }
1274     }
1275 
1276     *idx = -1;
1277     return 0;
1278 }
1279 
1280 /* --------------------------------------------------------------------------------------------- */
1281 
1282 static gboolean
1283 lookup_keycode (const long code, int *idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1284 {
1285     if (code != 0)
1286     {
1287         const key_code_name_t key = { code, NULL, NULL, NULL };
1288         const key_code_name_t *keyp = &key;
1289         const key_code_name_t **res;
1290 
1291         sort_key_conv_tab (KEY_SORTBYCODE);
1292 
1293         res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1294                        sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_code);
1295 
1296         if (res != NULL)
1297         {
1298             *idx = (int) (res - key_conv_tab_sorted);
1299             return TRUE;
1300         }
1301     }
1302 
1303     *idx = -1;
1304     return FALSE;
1305 }
1306 
1307 /* --------------------------------------------------------------------------------------------- */
1308 /*** public functions ****************************************************************************/
1309 /* --------------------------------------------------------------------------------------------- */
1310 /* This has to be called before init_slang or whatever routine
1311    calls any define_sequence */
1312 
1313 void
1314 init_key (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1315 {
1316     const char *term;
1317 
1318     term = getenv ("TERM");
1319 
1320     // This has to be the first define_sequence
1321     // So, we can assume that the first keys member has ESC
1322     define_sequences (mc_default_keys);
1323 
1324     // Terminfo on irix does not have some keys
1325     if (mc_global.tty.xterm_flag
1326         || (term != NULL
1327             && (strncmp (term, "iris-ansi", 9) == 0 || strncmp (term, "xterm", 5) == 0
1328                 || strncmp (term, "rxvt", 4) == 0 || strncmp (term, "screen", 6) == 0)))
1329         define_sequences (xterm_key_defines);
1330 
1331     // load some additional keys (e.g. direct Alt-? support)
1332     load_xtra_key_defines ();
1333 
1334 #ifdef __QNX__
1335     if ((term != NULL) && (strncmp (term, "qnx", 3) == 0))
1336     {
1337         /* Modify the default value of use_8th_bit_as_meta: we would
1338          * like to provide a working mc for a newbie who knows nothing
1339          * about [Options|Display bits|Full 8 bits input]...
1340          *
1341          * Don't use 'meta'-bit, when we are dealing with a
1342          * 'qnx*'-type terminal: clear the default value!
1343          * These terminal types use 0xFF as an escape character,
1344          * so use_8th_bit_as_meta==1 must not be enabled!
1345          *
1346          * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
1347          * is not used now (doesn't even depend on use_8th_bit_as_meta
1348          * as in mc-3.1.2)...GREAT!...no additional code is required!]
1349          */
1350         use_8th_bit_as_meta = FALSE;
1351     }
1352 #endif
1353 
1354 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1355     init_key_x11 ();
1356 #endif
1357 
1358     /* Load the qansi-m key definitions
1359        if we are running under the qansi-m terminal */
1360     if (term != NULL && (strncmp (term, "qansi-m", 7) == 0))
1361         define_sequences (qansi_key_defines);
1362 }
1363 
1364 /* --------------------------------------------------------------------------------------------- */
1365 /**
1366  * This has to be called after SLang_init_tty/slint_init
1367  */
1368 
1369 void
1370 init_key_input_fd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1371 {
1372 #ifdef HAVE_SLANG
1373     input_fd = SLang_TT_Read_FD;
1374 #endif
1375 }
1376 
1377 /* --------------------------------------------------------------------------------------------- */
1378 
1379 void
1380 done_key (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1381 {
1382     k_dispose (keys);
1383     g_slist_free_full (select_list, g_free);
1384 
1385 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1386     if (x11_display)
1387         mc_XCloseDisplay (x11_display);
1388 #endif
1389 }
1390 
1391 /* --------------------------------------------------------------------------------------------- */
1392 
1393 void
1394 add_select_channel (int fd, select_fn callback, void *info)
     /* [previous][next][first][last][top][bottom][index][help]  */
1395 {
1396     select_t *new;
1397 
1398     new = g_new (select_t, 1);
1399     new->fd = fd;
1400     new->callback = callback;
1401     new->info = info;
1402 
1403     select_list = g_slist_prepend (select_list, new);
1404 }
1405 
1406 /* --------------------------------------------------------------------------------------------- */
1407 
1408 void
1409 delete_select_channel (int fd)
     /* [previous][next][first][last][top][bottom][index][help]  */
1410 {
1411     GSList *p;
1412 
1413     p = g_slist_find_custom (select_list, GINT_TO_POINTER (fd), select_cmp_by_fd);
1414     if (p != NULL)
1415         select_list = g_slist_delete_link (select_list, p);
1416 }
1417 
1418 /* --------------------------------------------------------------------------------------------- */
1419 
1420 void
1421 channels_up (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1422 {
1423     if (disabled_channels == 0)
1424         fputs ("Error: channels_up called with disabled_channels = 0\n", stderr);
1425     disabled_channels--;
1426 }
1427 
1428 /* --------------------------------------------------------------------------------------------- */
1429 
1430 void
1431 channels_down (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1432 {
1433     disabled_channels++;
1434 }
1435 
1436 /* --------------------------------------------------------------------------------------------- */
1437 /**
1438  * Return the code associated with the symbolic name keyname
1439  */
1440 
1441 long
1442 tty_keyname_to_keycode (const char *name, char **label)
     /* [previous][next][first][last][top][bottom][index][help]  */
1443 {
1444     char **lc_keys, **p;
1445     char *cname;
1446     int k = -1;
1447     int key = 0;
1448     int lc_index = -1;
1449 
1450     int use_meta = -1;
1451     int use_ctrl = -1;
1452     int use_shift = -1;
1453 
1454     if (name == NULL)
1455         return 0;
1456 
1457     cname = g_strstrip (g_strdup (name));
1458     lc_keys = g_strsplit_set (cname, "-+ ", -1);
1459     g_free (cname);
1460 
1461     for (p = lc_keys; p != NULL && *p != NULL; p++)
1462     {
1463         if ((*p)[0] != '\0')
1464         {
1465             int idx;
1466 
1467             key = lookup_keyname (g_strstrip (*p), &idx);
1468 
1469             if (key == KEY_M_ALT)
1470                 use_meta = idx;
1471             else if (key == KEY_M_CTRL)
1472                 use_ctrl = idx;
1473             else if (key == KEY_M_SHIFT)
1474                 use_shift = idx;
1475             else
1476             {
1477                 k = key;
1478                 lc_index = idx;
1479                 break;
1480             }
1481         }
1482     }
1483 
1484     g_strfreev (lc_keys);
1485 
1486     // output
1487     if (k <= 0)
1488         return 0;
1489 
1490     if (label != NULL)
1491     {
1492         GString *s;
1493 
1494         s = g_string_new ("");
1495 
1496         if (use_meta != -1)
1497         {
1498             g_string_append (s, key_conv_tab_sorted[use_meta]->shortcut);
1499             g_string_append_c (s, '-');
1500         }
1501         if (use_ctrl != -1)
1502         {
1503             g_string_append (s, key_conv_tab_sorted[use_ctrl]->shortcut);
1504             g_string_append_c (s, '-');
1505         }
1506         if (use_shift != -1)
1507         {
1508             if (k < 127)
1509                 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1510             else
1511             {
1512                 g_string_append (s, key_conv_tab_sorted[use_shift]->shortcut);
1513                 g_string_append_c (s, '-');
1514                 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1515             }
1516         }
1517         else if (k < 128)
1518         {
1519             if ((k >= 'A') || (lc_index < 0) || (key_conv_tab_sorted[lc_index]->shortcut == NULL))
1520                 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) k));
1521             else
1522                 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1523         }
1524         else if ((lc_index != -1) && (key_conv_tab_sorted[lc_index]->shortcut != NULL))
1525             g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1526         else
1527             g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) key));
1528 
1529         *label = g_string_free (s, FALSE);
1530     }
1531 
1532     if (use_shift != -1)
1533     {
1534         if (k < 127 && k > 31)
1535             k = g_ascii_toupper ((gchar) k);
1536         else
1537             k |= KEY_M_SHIFT;
1538     }
1539 
1540     if (use_ctrl != -1)
1541     {
1542         if (k < 256)
1543             k = XCTRL (k);
1544         else
1545             k |= KEY_M_CTRL;
1546     }
1547 
1548     if (use_meta != -1)
1549         k = ALT (k);
1550 
1551     return (long) k;
1552 }
1553 
1554 /* --------------------------------------------------------------------------------------------- */
1555 
1556 char *
1557 tty_keycode_to_keyname (const int keycode)
     /* [previous][next][first][last][top][bottom][index][help]  */
1558 {
1559     // code without modifier
1560     unsigned int k = keycode & ~KEY_M_MASK;
1561     // modifier
1562     unsigned int mod = keycode & KEY_M_MASK;
1563 
1564     int key_idx = -1;
1565 
1566     GString *s;
1567     int idx;
1568 
1569     s = g_string_sized_new (8);
1570 
1571     if (lookup_keycode (k, &key_idx) || (k > 0 && k < 256))
1572     {
1573         if ((mod & KEY_M_ALT) != 0 && lookup_keycode (KEY_M_ALT, &idx))
1574         {
1575             g_string_append (s, key_conv_tab_sorted[idx]->name);
1576             g_string_append_c (s, '-');
1577         }
1578 
1579         if ((mod & KEY_M_CTRL) != 0)
1580         {
1581             // non printeble chars like a CTRL-[A..Z]
1582             if (k < 32)
1583                 k += 64;
1584 
1585             if (lookup_keycode (KEY_M_CTRL, &idx))
1586             {
1587                 g_string_append (s, key_conv_tab_sorted[idx]->name);
1588                 g_string_append_c (s, '-');
1589             }
1590         }
1591 
1592         if ((mod & KEY_M_SHIFT) != 0)
1593         {
1594             if (lookup_keycode (KEY_M_ALT, &idx))
1595             {
1596                 if (k < 127)
1597                     g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1598                 else
1599                 {
1600                     g_string_append (s, key_conv_tab_sorted[idx]->name);
1601                     g_string_append_c (s, '-');
1602                     g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1603                 }
1604             }
1605         }
1606         else if (k < 128)
1607         {
1608             if ((k >= 'A') || (key_idx < 0) || (key_conv_tab_sorted[key_idx]->name == NULL))
1609                 g_string_append_c (s, (gchar) k);
1610             else
1611                 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1612         }
1613         else if ((key_idx != -1) && (key_conv_tab_sorted[key_idx]->name != NULL))
1614             g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1615         else
1616             g_string_append_c (s, (gchar) keycode);
1617     }
1618 
1619     return g_string_free (s, s->len == 0);
1620 }
1621 
1622 /* --------------------------------------------------------------------------------------------- */
1623 /**
1624  * Return TRUE on success, FALSE on error.
1625  * An error happens if SEQ is a beginning of an existing longer sequence.
1626  */
1627 
1628 gboolean
1629 define_sequence (int code, const char *seq, int action)
     /* [previous][next][first][last][top][bottom][index][help]  */
1630 {
1631     key_def *base;
1632 
1633     if (strlen (seq) > SEQ_BUFFER_LEN - 1)
1634         return FALSE;
1635 
1636     for (base = keys; (base != NULL) && (*seq != '\0');)
1637         if (*seq == base->ch)
1638         {
1639             if (base->child == NULL)
1640             {
1641                 if (*(seq + 1) != '\0')
1642                     base->child = create_sequence (seq + 1, code, action);
1643                 else
1644                 {
1645                     // The sequence matches an existing one.
1646                     base->code = code;
1647                     base->action = action;
1648                 }
1649                 return TRUE;
1650             }
1651 
1652             base = base->child;
1653             seq++;
1654         }
1655         else
1656         {
1657             if (base->next != NULL)
1658                 base = base->next;
1659             else
1660             {
1661                 base->next = create_sequence (seq, code, action);
1662                 return TRUE;
1663             }
1664         }
1665 
1666     if (*seq == '\0')
1667     {
1668         // Attempt to redefine a sequence with a shorter sequence.
1669         return FALSE;
1670     }
1671 
1672     keys = create_sequence (seq, code, action);
1673     return TRUE;
1674 }
1675 
1676 /* --------------------------------------------------------------------------------------------- */
1677 /**
1678  * Check if we are idle, i.e. there are no pending keyboard or mouse
1679  * events.  Return 1 is idle, 0 is there are pending events.
1680  */
1681 gboolean
1682 is_idle (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1683 {
1684     int nfd;
1685     fd_set select_set;
1686     struct timeval time_out;
1687 
1688     FD_ZERO (&select_set);
1689     FD_SET (input_fd, &select_set);
1690     nfd = MAX (0, input_fd) + 1;
1691     time_out.tv_sec = 0;
1692     time_out.tv_usec = 0;
1693 #ifdef HAVE_LIBGPM
1694     if (mouse_enabled && use_mouse_p == MOUSE_GPM)
1695     {
1696         if (gpm_fd >= 0)
1697         {
1698             FD_SET (gpm_fd, &select_set);
1699             nfd = MAX (nfd, gpm_fd + 1);
1700         }
1701         else
1702         {
1703             if (mouse_fd >= 0)  // error indicative
1704             {
1705                 if (FD_ISSET (mouse_fd, &select_set))
1706                     FD_CLR (mouse_fd, &select_set);
1707                 mouse_fd = gpm_fd;
1708             }
1709             // gpm_fd == -2 means under some X terminal
1710             if (gpm_fd == -1)
1711             {
1712                 mouse_enabled = FALSE;
1713                 use_mouse_p = MOUSE_NONE;
1714             }
1715         }
1716     }
1717 #endif
1718     return (select (nfd, &select_set, 0, 0, &time_out) <= 0);
1719 }
1720 
1721 /* --------------------------------------------------------------------------------------------- */
1722 
1723 int
1724 get_key_code (int no_delay)
     /* [previous][next][first][last][top][bottom][index][help]  */
1725 {
1726     int c;
1727     static key_def *this = NULL, *parent;
1728     static gint64 esc_time = -1;
1729     static int lastnodelay = -1;
1730 
1731     if (no_delay != lastnodelay)
1732     {
1733         this = NULL;
1734         lastnodelay = no_delay;
1735     }
1736 
1737 pend_send:
1738     if (pending_keys != NULL)
1739     {
1740         gboolean bad_seq;
1741 
1742         c = *pending_keys++;
1743         while (c == ESC_CHAR)
1744             c = ALT (*pending_keys++);
1745 
1746         bad_seq = (*pending_keys != ESC_CHAR && *pending_keys != '\0');
1747         if (*pending_keys == '\0' || bad_seq)
1748             pending_keys = seq_append = NULL;
1749 
1750         if (bad_seq)
1751         {
1752             /* This is an unknown ESC sequence.
1753              * To prevent interpreting its tail as a random garbage,
1754              * eat and discard all buffered and quickly following chars.
1755              * Small, but non-zero timeout is needed to reconnect
1756              * escape sequence split up by e.g. a serial line.
1757              */
1758             int paranoia = 20;
1759 
1760             while (getch_with_timeout (old_esc_mode_timeout) >= 0 && --paranoia != 0)
1761                 ;
1762         }
1763         else
1764         {
1765             if (c > 127 && c < 256 && use_8th_bit_as_meta)
1766                 c = ALT (c & 0x7f);
1767 
1768             goto done;
1769         }
1770     }
1771 
1772 nodelay_try_again:
1773     if (no_delay != 0)
1774         tty_nodelay (TRUE);
1775 
1776     c = tty_lowlevel_getch ();
1777 #if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE)
1778     if (c == KEY_RESIZE)
1779         goto nodelay_try_again;
1780 #endif
1781 
1782     if (no_delay != 0)
1783     {
1784         tty_nodelay (FALSE);
1785         if (c == -1)
1786         {
1787             if (this == NULL || parent == NULL || parent->action != MCKEY_ESCAPE || !old_esc_mode
1788                 || esc_time == -1 || g_get_monotonic_time () < esc_time + old_esc_mode_timeout)
1789                 return -1;
1790 
1791             this = NULL;
1792             pending_keys = seq_append = NULL;
1793             return ESC_CHAR;
1794         }
1795     }
1796     else if (c == -1)
1797     {
1798         /* Maybe we got an incomplete match.
1799            This we do only in delay mode, since otherwise
1800            tty_lowlevel_getch can return -1 at any time. */
1801         if (seq_append == NULL)
1802         {
1803             this = NULL;
1804             return -1;
1805         }
1806 
1807         pending_keys = seq_buffer;
1808         goto pend_send;
1809     }
1810 
1811     // Search the key on the root
1812     if (no_delay == 0 || this == NULL)
1813     {
1814         this = keys;
1815         parent = NULL;
1816 
1817         if (c > 127 && c < 256 && use_8th_bit_as_meta)
1818         {
1819             c &= 0x7f;
1820 
1821             // The first sequence defined starts with esc
1822             parent = keys;
1823             this = keys->child;
1824         }
1825     }
1826 
1827     while (this != NULL)
1828     {
1829         if (c == this->ch)
1830         {
1831             if (this->child == NULL)
1832             {
1833                 // We got a complete match, return and reset search
1834                 pending_keys = seq_append = NULL;
1835                 c = this->code;
1836                 goto done;
1837             }
1838 
1839             // No match yet, but it may be a prefix for a valid seq
1840             if (!push_char (c))
1841             {
1842                 pending_keys = seq_buffer;
1843                 goto pend_send;
1844             }
1845 
1846             parent = this;
1847             this = this->child;
1848             if (parent->action == MCKEY_ESCAPE && old_esc_mode)
1849             {
1850                 if (no_delay != 0)
1851                 {
1852                     esc_time = g_get_monotonic_time ();
1853                     goto nodelay_try_again;
1854                 }
1855 
1856                 esc_time = -1;
1857                 c = getch_with_timeout (old_esc_mode_timeout);
1858                 if (c != -1)
1859                     continue;
1860 
1861                 pending_keys = seq_append = NULL;
1862                 this = NULL;
1863                 return ESC_CHAR;
1864             }
1865 
1866             if (no_delay != 0)
1867                 goto nodelay_try_again;
1868             c = tty_lowlevel_getch ();
1869             continue;
1870         }
1871 
1872         // c != this->ch. Try other keys with this prefix
1873         if (this->next != NULL)
1874         {
1875             this = this->next;
1876             continue;
1877         }
1878 
1879         // No match found. Is it one of our ESC <key> specials?
1880         if ((parent != NULL) && (parent->action == MCKEY_ESCAPE))
1881         {
1882             // Convert escape-digits to F-keys
1883             if (g_ascii_isdigit (c))
1884                 c = KEY_F (c - '0');
1885             else if (c == ' ')
1886                 c = ESC_CHAR;
1887             else
1888                 c = ALT (c);
1889 
1890             pending_keys = seq_append = NULL;
1891             goto done;
1892         }
1893 
1894         // Unknown sequence. Maybe a prefix of a longer one. Save it.
1895         push_char (c);
1896         pending_keys = seq_buffer;
1897         goto pend_send;
1898     }  // while (this != NULL)
1899 
1900 done:
1901     this = NULL;
1902     return correct_key_code (c);
1903 }
1904 
1905 /* --------------------------------------------------------------------------------------------- */
1906 /* Returns a character read from stdin with appropriate interpretation */
1907 /* Also takes care of generated mouse events */
1908 /* Returns EV_MOUSE if it is a mouse event */
1909 /* Returns EV_NONE  if non-blocking or interrupt set and nothing was done */
1910 
1911 int
1912 tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block)
     /* [previous][next][first][last][top][bottom][index][help]  */
1913 {
1914     int c;
1915     int flag = 0;  // Return value from select
1916 #ifdef HAVE_LIBGPM
1917     static struct Gpm_Event ev;  // Mouse event
1918 #endif
1919     struct timeval time_out;
1920     struct timeval *time_addr = NULL;
1921     static int dirty = 3;
1922 
1923     if ((dirty == 3) || is_idle ())
1924     {
1925         mc_refresh ();
1926         dirty = 1;
1927     }
1928     else
1929         dirty++;
1930 
1931     vfs_timeout_handler ();
1932 
1933     /* Ok, we use (event->x < 0) to signal that the event does not contain
1934        a suitable position for the mouse, so we can't use show_mouse_pointer
1935        on it.
1936      */
1937     if (event->x > 0)
1938     {
1939         show_mouse_pointer (event->x, event->y);
1940         if (!redo_event)
1941             event->x = -1;
1942     }
1943 
1944     // Repeat if using mouse
1945     while (pending_keys == NULL)
1946     {
1947         int nfd;
1948         fd_set select_set;
1949 
1950         FD_ZERO (&select_set);
1951         FD_SET (input_fd, &select_set);
1952         nfd = MAX (add_selects (&select_set), MAX (0, input_fd)) + 1;
1953 
1954 #ifdef HAVE_LIBGPM
1955         if (mouse_enabled && (use_mouse_p == MOUSE_GPM))
1956         {
1957             if (gpm_fd >= 0)
1958             {
1959                 FD_SET (gpm_fd, &select_set);
1960                 nfd = MAX (nfd, gpm_fd + 1);
1961             }
1962             else
1963             {
1964                 if (mouse_fd >= 0)  // error indicative
1965                 {
1966                     if (FD_ISSET (mouse_fd, &select_set))
1967                         FD_CLR (mouse_fd, &select_set);
1968                     mouse_fd = gpm_fd;
1969                 }
1970                 // gpm_fd == -2 means under some X terminal
1971                 if (gpm_fd == -1)
1972                 {
1973                     mouse_enabled = FALSE;
1974                     use_mouse_p = MOUSE_NONE;
1975                 }
1976                 break;
1977             }
1978         }
1979 #endif
1980 
1981         if (redo_event)
1982         {
1983             time_out.tv_usec = mou_auto_repeat * MC_USEC_PER_MSEC;
1984             time_out.tv_sec = 0;
1985 
1986             time_addr = &time_out;
1987         }
1988         else
1989         {
1990             int seconds;
1991 
1992             seconds = vfs_timeouts ();
1993             time_addr = NULL;
1994 
1995             if (seconds != 0)
1996             {
1997                 /* the timeout could be improved and actually be
1998                  * the number of seconds until the next vfs entry
1999                  * timeouts in the stamp list.
2000                  */
2001 
2002                 time_out.tv_sec = seconds;
2003                 time_out.tv_usec = 0;
2004                 time_addr = &time_out;
2005             }
2006         }
2007 
2008         if (!block || tty_got_winch ())
2009         {
2010             time_addr = &time_out;
2011             time_out.tv_sec = 0;
2012             time_out.tv_usec = 0;
2013         }
2014 
2015         tty_enable_interrupt_key ();
2016         flag = select (nfd, &select_set, NULL, NULL, time_addr);
2017         tty_disable_interrupt_key ();
2018 
2019         /* select timed out: it could be for any of the following reasons:
2020          * redo_event -> it was because of the MOU_REPEAT handler
2021          * !block     -> we did not block in the select call
2022          * else       -> 10 second timeout to check the vfs status.
2023          */
2024         if (flag == 0)
2025         {
2026             if (redo_event)
2027                 return EV_MOUSE;
2028             if (!block || tty_got_winch ())
2029                 return EV_NONE;
2030             vfs_timeout_handler ();
2031         }
2032         if (flag == -1 && errno == EINTR)
2033             return EV_NONE;
2034 
2035         check_selects (&select_set);
2036 
2037         if (FD_ISSET (input_fd, &select_set))
2038             break;
2039 
2040 #ifdef HAVE_LIBGPM
2041         if (mouse_enabled && use_mouse_p == MOUSE_GPM)
2042         {
2043             if (gpm_fd >= 0)
2044             {
2045                 if (FD_ISSET (gpm_fd, &select_set))
2046                 {
2047                     int status;
2048 
2049                     status = Gpm_GetEvent (&ev);
2050                     if (status == 1)  // success
2051                     {
2052                         Gpm_FitEvent (&ev);
2053                         *event = ev;
2054                         return EV_MOUSE;
2055                     }
2056                     if (status <= 0)  // connection closed; -1 == error
2057                     {
2058                         if (mouse_fd >= 0 && FD_ISSET (mouse_fd, &select_set))
2059                             FD_CLR (mouse_fd, &select_set);
2060 
2061                         disable_mouse ();
2062                         return EV_NONE;
2063                     }
2064                 }
2065             }
2066             else
2067             {
2068                 if (mouse_fd >= 0)  // error indicative
2069                 {
2070                     if (FD_ISSET (mouse_fd, &select_set))
2071                         FD_CLR (mouse_fd, &select_set);
2072                     mouse_fd = gpm_fd;
2073                 }
2074                 // gpm_fd == -2 means under some X terminal
2075                 if (gpm_fd == -1)
2076                 {
2077                     mouse_enabled = FALSE;
2078                     use_mouse_p = MOUSE_NONE;
2079                 }
2080                 break;
2081             }
2082         }
2083 #endif
2084     }
2085 
2086 #ifndef HAVE_SLANG
2087     flag = is_wintouched (stdscr);
2088     untouchwin (stdscr);
2089 #endif
2090     c = block ? getch_with_delay () : get_key_code (1);
2091 
2092 #ifndef HAVE_SLANG
2093     if (flag > 0)
2094         tty_touch_screen ();
2095 #endif
2096 
2097     if (mouse_enabled
2098         && (c == MCKEY_MOUSE
2099 #ifdef KEY_MOUSE
2100             || c == KEY_MOUSE
2101 #endif
2102             || c == MCKEY_EXTENDED_MOUSE))
2103     {
2104         // Mouse event. See tickets 2956 and 3954 for extended mode detection.
2105         gboolean extended = c == MCKEY_EXTENDED_MOUSE;
2106 
2107 #ifdef KEY_MOUSE
2108         extended =
2109             extended || (c == KEY_MOUSE && xmouse_seq == NULL && xmouse_extended_seq != NULL);
2110 #endif
2111 
2112         xmouse_get_event (event, extended);
2113         c = (event->type != 0) ? EV_MOUSE : EV_NONE;
2114     }
2115     else if (c == MCKEY_BRACKETED_PASTING_START)
2116     {
2117         bracketed_pasting_in_progress = TRUE;
2118         c = EV_NONE;
2119     }
2120     else if (c == MCKEY_BRACKETED_PASTING_END)
2121     {
2122         bracketed_pasting_in_progress = FALSE;
2123         c = EV_NONE;
2124     }
2125 
2126     return c;
2127 }
2128 
2129 /* --------------------------------------------------------------------------------------------- */
2130 /* Returns a key press, mouse events are discarded */
2131 
2132 int
2133 tty_getch (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2134 {
2135     Gpm_Event ev;
2136     int key;
2137 
2138     ev.x = -1;
2139     while ((key = tty_get_event (&ev, FALSE, TRUE)) == EV_NONE)
2140         ;
2141     return key;
2142 }
2143 
2144 /* --------------------------------------------------------------------------------------------- */
2145 
2146 char *
2147 learn_key (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2148 {
2149     // LEARN_TIMEOUT in ms
2150 #define LEARN_TIMEOUT 200
2151 
2152     fd_set Read_FD_Set;
2153     gint64 end_time;
2154     int c;
2155     GString *buffer;
2156 
2157     buffer = g_string_sized_new (16);
2158 
2159     tty_keypad (FALSE);  // disable interpreting keys by ncurses
2160     c = tty_lowlevel_getch ();
2161     while (c == -1)
2162         c = tty_lowlevel_getch ();  // Sanity check, should be unnecessary
2163     learn_store_key (buffer, c);
2164 
2165     end_time = g_get_monotonic_time () + LEARN_TIMEOUT * MC_USEC_PER_MSEC;
2166 
2167     tty_nodelay (TRUE);
2168     while (TRUE)
2169     {
2170         while ((c = tty_lowlevel_getch ()) == -1)
2171         {
2172             gint64 time_out;
2173             struct timeval tv;
2174 
2175             time_out = end_time - g_get_monotonic_time ();
2176             if (time_out <= 0)
2177                 break;
2178 
2179             tv.tv_sec = time_out / G_USEC_PER_SEC;
2180             tv.tv_usec = time_out % G_USEC_PER_SEC;
2181             FD_ZERO (&Read_FD_Set);
2182             FD_SET (input_fd, &Read_FD_Set);
2183             select (input_fd + 1, &Read_FD_Set, NULL, NULL, &tv);
2184         }
2185         if (c == -1)
2186             break;
2187         learn_store_key (buffer, c);
2188     }
2189     tty_keypad (TRUE);
2190     tty_nodelay (FALSE);
2191 
2192     return g_string_free (buffer, buffer->len == 0);
2193 #undef LEARN_TIMEOUT
2194 }
2195 
2196 /* --------------------------------------------------------------------------------------------- */
2197 /* xterm and linux console only: set keypad to numeric or application
2198    mode. Only in application keypad mode it's possible to distinguish
2199    the '+' key and the '+' on the keypad ('*' and '-' ditto) */
2200 
2201 void
2202 numeric_keypad_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2203 {
2204     if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2205     {
2206         fputs (ESC_STR ">", stdout);
2207         fflush (stdout);
2208     }
2209 }
2210 
2211 /* --------------------------------------------------------------------------------------------- */
2212 
2213 void
2214 application_keypad_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2215 {
2216     if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2217     {
2218         fputs (ESC_STR "=", stdout);
2219         fflush (stdout);
2220     }
2221 }
2222 
2223 /* --------------------------------------------------------------------------------------------- */
2224 
2225 void
2226 enable_bracketed_paste (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2227 {
2228     printf (ESC_STR "[?2004h");
2229     fflush (stdout);
2230 }
2231 
2232 /* --------------------------------------------------------------------------------------------- */
2233 
2234 void
2235 disable_bracketed_paste (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2236 {
2237     printf (ESC_STR "[?2004l");
2238     fflush (stdout);
2239     bracketed_pasting_in_progress = FALSE;
2240 }
2241 
2242 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */