diff --git a/src/event/gsource.c b/src/event/gsource.c new file mode 100644 index 000000000..40625cf54 --- /dev/null +++ b/src/event/gsource.c @@ -0,0 +1,43 @@ +/* + Handle any events in application. + Interface functions: add/del gsource to mainloop + + Copyright (C) 2009 The Free Software Foundation, Inc. + + Written by: + Slava Zanko , 2009. + + This file is part of the Midnight Commander. + + The Midnight Commander is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Midnight Commander is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied warranty + of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + */ + +#include "event.h" +#include "internal.h" + +/*** global variables ****************************************************************************/ + +/*** file scope macro definitions ****************************************************************/ + +/*** file scope type declarations ****************************************************************/ + +/*** file scope variables ************************************************************************/ + +/*** file scope functions ************************************************************************/ + +/*** public functions ****************************************************************************/ + +/* --------------------------------------------------------------------------------------------- */ diff --git a/src/tty/Makefile.am b/src/tty/Makefile.am index 6f2ed5fa8..5fbe5b4d5 100644 --- a/src/tty/Makefile.am +++ b/src/tty/Makefile.am @@ -14,7 +14,7 @@ endif TTY_SRC = \ color-internal.c color-internal.h\ color.c color.h \ - key.c key.h key_define.h keyxdef.c \ + key.c key.h key-gsource.c key-internal.h key-define.h keyxdef.c \ mouse.c mouse.h \ tty.c tty.h tty-internal.h \ win.c win.h \ diff --git a/src/tty/key_define.h b/src/tty/key-define.h similarity index 100% rename from src/tty/key_define.h rename to src/tty/key-define.h diff --git a/src/tty/key-gsource.c b/src/tty/key-gsource.c new file mode 100644 index 000000000..acf253c40 --- /dev/null +++ b/src/tty/key-gsource.c @@ -0,0 +1,118 @@ +/* Keyboard support routines. + Handle keyboard via GMainLoop. + + Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, + 2005, 2006, 2007, 2009 Free Software Foundation, Inc. + + Written by: 1994, 1995 Miguel de Icaza. + 1994, 1995 Janne Kukonlehto. + 1995 Jakub Jelinek. + 1997 Norbert Warmuth + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/** \file key.c + * \brief Source: keyboard support routines + */ + +#include + + +#include "../../src/global.h" +#include "../../src/tty/key-internal.h" +#include "../../src/event/event.h" + +/*** global variables **************************************************/ + +tty_key_event_t tty_key_event; + +/*** file scope macro definitions **************************************/ + +/* The maximum sequence length (32 + null terminator) */ +#define SEQ_BUFFER_LEN 33 + +/*** file scope type declarations **************************************/ + +/*** file scope variables **********************************************/ + +static GIOChannel *tty_key_channel_key; + +/*** file scope functions **********************************************/ + +/* --------------------------------------------------------------------------------------------- */ +static gboolean +tty_key_gsource_keyboard_callback(GIOChannel *source, GIOCondition condition, gpointer data) +{ + tty_key_event_t *tty_key_event; + int seq_buffer [SEQ_BUFFER_LEN]; + int seq_count=0; + + gchar buf; + gsize bytes_read; + + while (g_io_channel_read_chars (source, &buf, 1 , &bytes_read, NULL) == G_IO_STATUS_NORMAL) + { + seq_buffer [seq_count++] = (int) buf; + } + /* + TODO: + 1) parse seq_buffer + 2) handle ESC, begavior + 3) handle mouse + */ + + tty_key_event.key = 0; + mcevent_raise("keyboard.press", (gpointer) &tty_key_event); + return TRUE; +} + +/* --------------------------------------------------------------------------------------------- */ +static void +tty_key_gsource_keyboard_init(void) +{ +#ifdef __CYGWIN__ + tty_key_channel_key = g_io_channel_win32_new (input_fd); +#else + tty_key_channel_key = g_io_channel_unix_new (input_fd); +#endif + + g_io_channel_set_encoding (tty_key_channel_key, NULL, NULL); + g_io_channel_set_buffered (tty_key_channel_key, FALSE); + g_io_channel_set_flags (tty_key_channel_key, G_IO_FLAG_NONBLOCK, NULL); + + g_io_add_watch (tty_key_channel_key, G_IO_IN /*|G_IO_HUP|G_IO_PRI|G_IO_ERR|G_IO_NVAL*/ , tty_key_gsource_keyboard_callback, NULL); + +} +/* --------------------------------------------------------------------------------------------- */ + +/*** public functions **************************************************/ + +/* --------------------------------------------------------------------------------------------- */ + +void +tty_key_gsource_init(void) +{ + tty_key_gsource_keyboard_init(); +} + +/* --------------------------------------------------------------------------------------------- */ + +void +tty_key_gsource_deinit(void) +{ + +} + +/* --------------------------------------------------------------------------------------------- */ diff --git a/src/tty/key-internal.h b/src/tty/key-internal.h new file mode 100644 index 000000000..599b95109 --- /dev/null +++ b/src/tty/key-internal.h @@ -0,0 +1,25 @@ + +/** \file key-internal.h + * \brief Header: keyboard support routines. Internal functions + */ + +#ifndef MC_KEY_INTERNAL_H +#define MC_KEY_INTERNAL_H + +/*** typedefs(not structures) and defined constants ********************/ + +/*** enums *************************************************************/ + +/*** structures declarations (and typedefs of structures)***************/ + +/*** global variables defined in .c file *******************************/ + +extern int input_fd; + +/*** declarations of public functions **********************************/ + + +void tty_key_gsource_init(void); +void tty_key_gsource_deinit(void); + +#endif /* MC_KEY_INTERNAL_H */ diff --git a/src/tty/key-old.c b/src/tty/key-old.c new file mode 100644 index 000000000..af89c7333 --- /dev/null +++ b/src/tty/key-old.c @@ -0,0 +1,1480 @@ +/* Keyboard support routines. + + Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004, + 2005, 2006, 2007, 2009 Free Software Foundation, Inc. + + Written by: 1994, 1995 Miguel de Icaza. + 1994, 1995 Janne Kukonlehto. + 1995 Jakub Jelinek. + 1997 Norbert Warmuth + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/** \file key.c + * \brief Source: keyboard support routines + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../src/global.h" + +#include "../../src/tty/tty.h" +#include "../../src/tty/tty-internal.h" /* mouse_enabled */ +#include "../../src/tty/mouse.h" +#include "../../src/tty/key.h" +#include "../../src/tty/key_define.h" +#include "../../src/tty/win.h" /* xterm_flag */ + +#include "../../src/main.h" +#include "../../src/layout.h" /* winch_flag, mc_refresh() */ +#include "../../src/cons.saver.h" +#include "../../src/strutil.h" /* str_casecmp */ + +#ifdef USE_VFS +#include "../../vfs/gc.h" +#endif + +#ifdef HAVE_TEXTMODE_X11_SUPPORT +#include "../src/tty/x11conn.h" +#endif + +#ifdef __linux__ +#if defined(__GLIBC__) && (__GLIBC__ < 2) +# include /* TIOCLINUX */ +#elif defined HAVE_TERMIOS_H +# include +#endif +#include +#endif /* __linux__ */ + +#ifdef __CYGWIN__ +#include +#include +#endif /* __CYGWIN__ */ + +#ifdef __QNXNTO__ +#include +#include +#include +#endif /* __QNXNTO__ */ + +/*** global variables **************************************************/ + +/* If true, use + and \ keys normally and select/unselect do if M-+ / M-\. + and M-- and keypad + / - */ +int alternate_plus_minus = 0; + +int mou_auto_repeat = 100; +int double_click_speed = 250; +int old_esc_mode = 0; +int use_8th_bit_as_meta = 0; + +/* This table is a mapping between names and the constants we use + * We use this to allow users to define alternate definitions for + * certain keys that may be missing from the terminal database + */ +key_code_name_t key_name_conv_tab [] = { +/* KEY_F(0) is not here, since we are mapping it to f10, so there is no reason + to define f0 as well. Also, it makes Learn keys a bunch of problems :( */ + { KEY_F(1), "f1", N_("Function key 1") }, + { KEY_F(2), "f2", N_("Function key 2") }, + { KEY_F(3), "f3", N_("Function key 3") }, + { KEY_F(4), "f4", N_("Function key 4") }, + { KEY_F(5), "f5", N_("Function key 5") }, + { KEY_F(6), "f6", N_("Function key 6") }, + { KEY_F(7), "f7", N_("Function key 7") }, + { KEY_F(8), "f8", N_("Function key 8") }, + { KEY_F(9), "f9", N_("Function key 9") }, + { KEY_F(10), "f10", N_("Function key 10") }, + { KEY_F(11), "f11", N_("Function key 11") }, + { KEY_F(12), "f12", N_("Function key 12") }, + { KEY_F(13), "f13", N_("Function key 13") }, + { KEY_F(14), "f14", N_("Function key 14") }, + { KEY_F(15), "f15", N_("Function key 15") }, + { KEY_F(16), "f16", N_("Function key 16") }, + { KEY_F(17), "f17", N_("Function key 17") }, + { KEY_F(18), "f18", N_("Function key 18") }, + { KEY_F(19), "f19", N_("Function key 19") }, + { KEY_F(20), "f20", N_("Function key 20") }, + { KEY_BACKSPACE, "bs", N_("Backspace key") }, + { KEY_END, "end", N_("End key") }, + { KEY_UP, "up", N_("Up arrow key") }, + { KEY_DOWN, "down", N_("Down arrow key") }, + { KEY_LEFT, "left", N_("Left arrow key") }, + { KEY_RIGHT, "right", N_("Right arrow key") }, + { KEY_HOME, "home", N_("Home key") }, + { KEY_NPAGE, "pgdn", N_("Page Down key") }, + { KEY_PPAGE, "pgup", N_("Page Up key") }, + { KEY_IC, "ins", N_("Insert key") }, + { KEY_DC, "delete", N_("Delete key") }, + { ALT('\t'), "complete", N_("Completion/M-tab") }, + { KEY_KP_ADD, "kpplus", N_("+ on keypad") }, + { KEY_KP_SUBTRACT,"kpminus", N_("- on keypad") }, + { KEY_KP_MULTIPLY,"kpasterix", N_("* on keypad") }, + +/* From here on, these won't be shown in Learn keys (no space) */ + { KEY_LEFT, "kpleft", N_("Left arrow keypad") }, + { KEY_RIGHT, "kpright", N_("Right arrow keypad") }, + { KEY_UP, "kpup", N_("Up arrow keypad") }, + { KEY_DOWN, "kpdown", N_("Down arrow keypad") }, + { KEY_HOME, "kphome", N_("Home on keypad") }, + { KEY_END, "kpend", N_("End on keypad") }, + { KEY_NPAGE, "kpnpage", N_("Page Down keypad") }, + { KEY_PPAGE, "kpppage", N_("Page Up keypad") }, + { KEY_IC, "kpinsert", N_("Insert on keypad") }, + { KEY_DC, "kpdelete", N_("Delete on keypad") }, + { (int) '\n', "kpenter", N_("Enter on keypad") }, + { (int) '\n', "enter", N_("Enter on keypad") }, + { (int) '\t', "tab", N_("Tab on keypad") }, + { (int) ' ', "space", N_("Space on keypad") }, + { (int) '/', "kpslash", N_("Slash on keypad") }, + { (int) '#', "kpnumlock", N_("NumLock on keypad") }, + +/* Alternative label */ + { KEY_BACKSPACE, "backspace", N_("Backspace key") }, + { KEY_IC, "insert", N_("Insert key") }, + { KEY_KP_ADD, "plus", N_("+ on keypad") }, + { KEY_KP_SUBTRACT,"minus", N_("- on keypad") }, + { KEY_KP_MULTIPLY,"asterix", N_("* on keypad") }, + +/* meta keys */ + { KEY_M_CTRL, "control", N_("Ctrl") }, + { KEY_M_CTRL, "ctrl", N_("Ctrl") }, + { KEY_M_ALT, "alt", N_("Alt") }, + { KEY_M_ALT, "ralt", N_("Alt") }, + { KEY_M_ALT, "meta", N_("Alt") }, + { KEY_M_SHIFT, "shift", N_("Shift") }, + + { 0, 0, 0 } +}; + + +/*** file scope macro definitions **************************************/ + +#define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *) NULL)) +#define DIF_TIME(t1, t2) ((t2.tv_sec - t1.tv_sec) * 1000 + (t2.tv_usec - t1.tv_usec)/1000) + +/* The maximum sequence length (32 + null terminator) */ +#define SEQ_BUFFER_LEN 33 + +/*** file scope type declarations **************************************/ + +/* Linux console keyboard modifiers */ +typedef enum { + SHIFT_PRESSED = (1 << 0), + ALTR_PRESSED = (1 << 1), + CONTROL_PRESSED = (1 << 2), + ALTL_PRESSED = (1 << 3) +} mod_pressed_t; + +typedef struct key_def { + char ch; /* Holds the matching char code */ + int code; /* The code returned, valid if child == NULL */ + struct key_def *next; + struct key_def *child; /* sequence continuation */ + int action; /* optional action to be done. Now used only + to mark that we are just after the first + Escape */ +} key_def; + +/* File descriptor monitoring add/remove routines */ +typedef struct SelectList { + int fd; + select_fn callback; + void *info; + struct SelectList *next; +} SelectList; + +#ifdef __QNXNTO__ +typedef int (*ph_dv_f) (void *, void *); +typedef int (*ph_ov_f) (void *); +typedef int (*ph_pqc_f) (unsigned short, PhCursorInfo_t *); +#endif + +/*** file scope variables **********************************************/ + + +/* timeout for old_esc_mode in usec */ +static int keyboard_key_timeout = 1000000; /* settable via env */ + +/* This holds all the key definitions */ +static key_def *keys = NULL; + +static int input_fd; +static int disabled_channels = 0; /* Disable channels checking */ + +static SelectList *select_list = NULL; + +static int seq_buffer [SEQ_BUFFER_LEN]; +static int *seq_append = NULL; + +static int *pending_keys = NULL; + +#ifdef __QNXNTO__ +ph_dv_f ph_attach; +ph_ov_f ph_input_group; +ph_pqc_f ph_query_cursor; +#endif + +#ifdef HAVE_TEXTMODE_X11_SUPPORT +static Display *x11_display; +static Window x11_window; +#endif /* HAVE_TEXTMODE_X11_SUPPORT */ + +/*** file scope functions **********************************************/ + +static int +add_selects (fd_set *select_set) +{ + int top_fd = 0; + + if (disabled_channels == 0) { + SelectList *p; + + for (p = select_list; p != NULL; p = p->next) { + FD_SET (p->fd, select_set); + if (p->fd > top_fd) + top_fd = p->fd; + } + } + + return top_fd; +} + +static void +check_selects (fd_set *select_set) +{ + if (disabled_channels == 0) { + gboolean retry; + + do { + SelectList *p; + + retry = FALSE; + for (p = select_list; p; p = p->next) + if (FD_ISSET (p->fd, select_set)) { + FD_CLR (p->fd, select_set); + (*p->callback)(p->fd, p->info); + retry = TRUE; + break; + } + } while (retry); + } +} + +/* If set timeout is set, then we wait 0.1 seconds, else, we block */ +static void +try_channels (int set_timeout) +{ + struct timeval timeout; + static fd_set select_set; + struct timeval *timeptr; + int v; + int maxfdp; + + while (1) { + FD_ZERO (&select_set); + FD_SET (input_fd, &select_set); /* Add stdin */ + maxfdp = max (add_selects (&select_set), input_fd); + + if (set_timeout) { + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + timeptr = &timeout; + } else + timeptr = 0; + + v = select (maxfdp + 1, &select_set, NULL, NULL, timeptr); + if (v > 0) { + check_selects (&select_set); + if (FD_ISSET (input_fd, &select_set)) + return; + } + } +} + +static key_def * +create_sequence (const char *seq, int code, int action) +{ + key_def *base, *p, *attach; + + for (base = attach = NULL; *seq; seq++) { + p = g_new (key_def, 1); + if (base == NULL) + base = p; + if (attach != NULL) + attach->child = p; + + p->ch = *seq; + p->code = code; + p->child = p->next = NULL; + if (seq[1] == '\0') + p->action = action; + else + p->action = MCKEY_NOACTION; + attach = p; + } + return base; +} + +static void +define_sequences (const key_define_t *kd) +{ + int i; + + for (i = 0; kd[i].code != 0; i++) + define_sequence (kd[i].code, kd[i].seq, kd[i].action); +} + +static void +init_key_x11 (void) +{ +#ifdef HAVE_TEXTMODE_X11_SUPPORT + if (getenv ("DISPLAY") != NULL) { + x11_display = mc_XOpenDisplay (0); + + if (x11_display != NULL) + x11_window = DefaultRootWindow (x11_display); + } +#endif /* HAVE_TEXTMODE_X11_SUPPORT */ +} + +/* Workaround for System V Curses vt100 bug */ +static int +getch_with_delay (void) +{ + int c; + + /* This routine could be used on systems without mouse support, + so we need to do the select check :-( */ + while (1) { + if (pending_keys == NULL) + try_channels (0); + + /* Try to get a character */ + c = get_key_code (0); + if (c != -1) + break; + /* Failed -> wait 0.1 secs and try again */ + try_channels (1); + } + /* Success -> return the character */ + return c; +} + +static void +xmouse_get_event (Gpm_Event *ev) +{ + int btn; + static struct timeval tv1 = { 0, 0 }; /* Force first click as single */ + static struct timeval tv2; + static int clicks = 0; + static int last_btn = 0; + + /* Decode Xterm mouse information to a GPM style event */ + + /* Variable btn has following meaning: */ + /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */ + btn = tty_lowlevel_getch () - 32; + + /* There seems to be no way of knowing which button was released */ + /* So we assume all the buttons were released */ + + if (btn == 3) { + if (last_btn) { + ev->type = GPM_UP | (GPM_SINGLE << clicks); + ev->buttons = 0; + last_btn = 0; + GET_TIME (tv1); + clicks = 0; + } else { + /* Bogus event, maybe mouse wheel */ + ev->type = 0; + } + } else { + if (btn >= 32 && btn <= 34) { + btn -= 32; + ev->type = GPM_DRAG; + } else + ev->type = GPM_DOWN; + + GET_TIME (tv2); + if (tv1.tv_sec && (DIF_TIME (tv1,tv2) < double_click_speed)) { + clicks++; + clicks %= 3; + } else + clicks = 0; + + switch (btn) { + case 0: + ev->buttons = GPM_B_LEFT; + break; + case 1: + ev->buttons = GPM_B_MIDDLE; + break; + case 2: + ev->buttons = GPM_B_RIGHT; + break; + case 64: + ev->buttons = GPM_B_UP; + clicks = 0; + break; + case 65: + ev->buttons = GPM_B_DOWN; + clicks = 0; + break; + default: + /* Nothing */ + ev->type = 0; + ev->buttons = 0; + break; + } + last_btn = ev->buttons; + } + /* Coordinates are 33-based */ + /* Transform them to 1-based */ + ev->x = tty_lowlevel_getch () - 32; + ev->y = tty_lowlevel_getch () - 32; +} + +/* + * Get modifier state (shift, alt, ctrl) for the last key pressed. + * We are assuming that the state didn't change since the key press. + * This is only correct if get_modifier() is called very fast after + * the input was received, so that the user didn't release the + * modifier keys yet. + */ +static int +get_modifier (void) +{ + int result = 0; +#ifdef __QNXNTO__ + int mod_status, shift_ext_status; + static int in_photon = 0; + static int ph_ig = 0; + PhCursorInfo_t cursor_info; +#endif /* __QNXNTO__ */ + +#ifdef HAVE_TEXTMODE_X11_SUPPORT + if (x11_window != 0) { + Window root, child; + int root_x, root_y; + int win_x, win_y; + unsigned int mask; + + mc_XQueryPointer (x11_display, x11_window, &root, &child, &root_x, + &root_y, &win_x, &win_y, &mask); + + if (mask & ShiftMask) + result |= KEY_M_SHIFT; + if (mask & ControlMask) + result |= KEY_M_CTRL; + return result; + } +#endif /* HAVE_TEXTMODE_X11_SUPPORT */ +#ifdef __QNXNTO__ + + if (in_photon == 0) { + /* First time here, let's load Photon library and attach + to Photon */ + in_photon = -1; + if (getenv ("PHOTON2_PATH") != NULL) { + /* QNX 6.x has no support for RTLD_LAZY */ + void *ph_handle = dlopen ("/usr/lib/libph.so", RTLD_NOW); + if (ph_handle != NULL) { + ph_attach = (ph_dv_f) dlsym (ph_handle, "PhAttach"); + ph_input_group = + (ph_ov_f) dlsym (ph_handle, "PhInputGroup"); + ph_query_cursor = + (ph_pqc_f) dlsym (ph_handle, "PhQueryCursor"); + if ((ph_attach != NULL) && (ph_input_group != NULL) + && (ph_query_cursor != NULL)) { + if ((*ph_attach) (0, 0)) { /* Attached */ + ph_ig = (*ph_input_group) (0); + in_photon = 1; + } + } + } + } + } + /* We do not have Photon running. Assume we are in text + console or xterm */ + if (in_photon == -1) { + if (devctl + (fileno (stdin), DCMD_CHR_LINESTATUS, &mod_status, + sizeof (int), NULL) == -1) + return 0; + shift_ext_status = mod_status & 0xffffff00UL; + mod_status &= 0x7f; + if (mod_status & _LINESTATUS_CON_ALT) + result |= KEY_M_ALT; + if (mod_status & _LINESTATUS_CON_CTRL) + result |= KEY_M_CTRL; + if ((mod_status & _LINESTATUS_CON_SHIFT) + || (shift_ext_status & 0x00000800UL)) + result |= KEY_M_SHIFT; + } else { + (*ph_query_cursor) (ph_ig, &cursor_info); + if (cursor_info.key_mods & 0x04) + result |= KEY_M_ALT; + if (cursor_info.key_mods & 0x02) + result |= KEY_M_CTRL; + if (cursor_info.key_mods & 0x01) + result |= KEY_M_SHIFT; + } +#endif /* __QNXNTO__ */ + +#if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX) + { + unsigned char modifiers = 6; + + if (ioctl (0, TIOCLINUX, &modifiers) < 0) + return 0; + + /* Translate Linux modifiers into mc modifiers */ + if (modifiers & SHIFT_PRESSED) + result |= KEY_M_SHIFT; + if (modifiers & (ALTL_PRESSED | ALTR_PRESSED)) + result |= KEY_M_ALT; + if (modifiers & CONTROL_PRESSED) + result |= KEY_M_CTRL; + } +#endif /* !__linux__ */ + return result; +} + +static gboolean +push_char (int c) +{ + gboolean ret = FALSE; + + if (seq_append == NULL) + seq_append = seq_buffer; + + if (seq_append != &(seq_buffer [SEQ_BUFFER_LEN - 2])) { + *(seq_append++) = c; + *seq_append = 0; + ret = TRUE; + } + + return ret; +} + +/* Apply corrections for the keycode generated in get_key_code() */ +static int +correct_key_code (int code) +{ + unsigned int c = code & ~KEY_M_MASK; /* code without modifier */ + unsigned int mod = code & KEY_M_MASK; /* modifier */ + #ifdef __QNXNTO__ + unsigned int qmod; /* bunch of the QNX console + modifiers needs unchanged */ + #endif /* __QNXNTO__ */ + + /* + * Add key modifiers directly from X11 or OS. + * Ordinary characters only get modifiers from sequences. + */ + if (c < 32 || c >= 256) { + mod |= get_modifier (); + } + + /* This is needed if the newline is reported as carriage return */ + if (c == '\r') + c = '\n'; + + /* This is reported to be useful on AIX */ + if (c == KEY_SCANCEL) + c = '\t'; + + /* Convert Shift+Tab and Ctrl+Tab to Back Tab */ + if ((c == '\t') && (mod & (KEY_M_SHIFT | KEY_M_CTRL))) { + c = KEY_BTAB; + mod = 0; + } + + /* F0 is the same as F10 for out purposes */ + if (c == KEY_F (0)) + c = KEY_F (10); + + /* + * We are not interested if Ctrl was pressed when entering control + * characters, so assume that it was. When checking for such keys, + * XCTRL macro should be used. In some cases, we are interested, + * e.g. to distinguish Ctrl-Enter from Enter. + */ + if (c < 32 && c != ESC_CHAR && c != '\t' && c != '\n') { + mod |= KEY_M_CTRL; + } + +#ifdef __QNXNTO__ + qmod = get_modifier (); + + if ((c == 127) && (mod == 0)) /* Add Ctrl/Alt/Shift-BackSpace */ + { + mod |= get_modifier(); + c = KEY_BACKSPACE; + } + + if ((c == '0') && (mod == 0)) /* Add Shift-Insert on key pad */ + { + if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT) + { + mod = KEY_M_SHIFT; + c = KEY_IC; + } + } + + if ((c == '.') && (mod == 0)) /* Add Shift-Del on key pad */ + { + if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT) + { + mod = KEY_M_SHIFT; + c = KEY_DC; + } + } +#endif /* __QNXNTO__ */ + + /* Unrecognized 0177 is delete (preserve Ctrl) */ + if (c == 0177) { + c = KEY_BACKSPACE; + } + + /* Unrecognized Ctrl-d is delete */ + if (c == (31 & 'd')) { + c = KEY_DC; + mod &= ~KEY_M_CTRL; + } + + /* Unrecognized Ctrl-h is backspace */ + if (c == (31 & 'h')) { + c = KEY_BACKSPACE; + mod &= ~KEY_M_CTRL; + } + + /* Shift+BackSpace is backspace */ + if (c == KEY_BACKSPACE && (mod & KEY_M_SHIFT)) { + mod &= ~KEY_M_SHIFT; + } + + /* Convert Shift+Fn to F(n+10) */ + if (c >= KEY_F (1) && c <= KEY_F (10) && (mod & KEY_M_SHIFT)) { + c += 10; + } + + /* Remove Shift information from function keys */ + if (c >= KEY_F (1) && c <= KEY_F (20)) { + mod &= ~KEY_M_SHIFT; + } + + if (!alternate_plus_minus) + switch (c) { + case KEY_KP_ADD: + c = '+'; + break; + case KEY_KP_SUBTRACT: + c = '-'; + break; + case KEY_KP_MULTIPLY: + c = '*'; + break; + } + + return (mod | c); +} + +static int +xgetch_second (void) +{ + fd_set Read_FD_Set; + int c; + struct timeval timeout; + + timeout.tv_sec = keyboard_key_timeout / 1000000; + timeout.tv_usec = keyboard_key_timeout % 1000000; + tty_nodelay (TRUE); + FD_ZERO (&Read_FD_Set); + FD_SET (input_fd, &Read_FD_Set); + select (input_fd + 1, &Read_FD_Set, NULL, NULL, &timeout); + c = tty_lowlevel_getch (); + tty_nodelay (FALSE); + return c; +} + +static void +learn_store_key (char *buffer, char **p, int c) +{ + if (*p - buffer > 253) + return; + if (c == ESC_CHAR) { + *(*p)++ = '\\'; + *(*p)++ = 'e'; + } else if (c < ' ') { + *(*p)++ = '^'; + *(*p)++ = c + 'a' - 1; + } else if (c == '^') { + *(*p)++ = '^'; + *(*p)++ = '^'; + } else + *(*p)++ = (char) c; +} + +static void +k_dispose (key_def *k) +{ + if (k != NULL) { + k_dispose (k->child); + k_dispose (k->next); + g_free (k); + } +} + +static void +s_dispose (SelectList *sel) +{ + if (sel != NULL) { + s_dispose (sel->next); + g_free (sel); + } +} + +/*** public functions **************************************************/ + +/* This has to be called before init_slang or whatever routine + calls any define_sequence */ +void +init_key (void) +{ + const char *term = getenv ("TERM"); + const char *kt = getenv ("KEYBOARD_KEY_TIMEOUT_US"); + if (kt != NULL) + keyboard_key_timeout = atoi (kt); + + /* This has to be the first define_sequence */ + /* So, we can assume that the first keys member has ESC */ + define_sequences (mc_default_keys); + + /* Terminfo on irix does not have some keys */ + if (xterm_flag + || (term != NULL + && (strncmp (term, "iris-ansi", 9) == 0 + || strncmp (term, "xterm", 5) == 0 + || strncmp (term, "rxvt", 4) == 0 + || strcmp (term, "screen") == 0))) + define_sequences (xterm_key_defines); + + /* load some additional keys (e.g. direct Alt-? support) */ + load_xtra_key_defines (); + +#ifdef __QNX__ + if ((term != NULL) && (strncmp (term, "qnx", 3) == 0)) { + /* Modify the default value of use_8th_bit_as_meta: we would + * like to provide a working mc for a newbie who knows nothing + * about [Options|Display bits|Full 8 bits input]... + * + * Don't use 'meta'-bit, when we are dealing with a + * 'qnx*'-type terminal: clear the default value! + * These terminal types use 0xFF as an escape character, + * so use_8th_bit_as_meta==1 must not be enabled! + * + * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff + * is not used now (doesn't even depend on use_8th_bit_as_meta + * as in mc-3.1.2)...GREAT!...no additional code is required!] + */ + use_8th_bit_as_meta = 0; + } +#endif /* __QNX__ */ + + init_key_x11 (); + + /* Load the qansi-m key definitions + if we are running under the qansi-m terminal */ + if (term != NULL && (strncmp (term, "qansi-m", 7) == 0)) + define_sequences (qansi_key_defines); +} + +/* This has to be called after SLang_init_tty/slint_init */ +void +init_key_input_fd (void) +{ +#ifdef HAVE_SLANG + input_fd = SLang_TT_Read_FD; +#endif +} + +void +done_key (void) +{ + k_dispose (keys); + s_dispose (select_list); + +#ifdef HAVE_TEXTMODE_X11_SUPPORT + if (x11_display) + mc_XCloseDisplay (x11_display); +#endif +} + +void +add_select_channel (int fd, select_fn callback, void *info) +{ + SelectList *new; + + new = g_new (SelectList, 1); + new->fd = fd; + new->callback = callback; + new->info = info; + new->next = select_list; + select_list = new; +} + +void +delete_select_channel (int fd) +{ + SelectList *p = select_list; + SelectList *p_prev = NULL; + SelectList *p_next; + + while (p != NULL) + if (p->fd == fd) { + p_next = p->next; + + if (p_prev != NULL) + p_prev->next = p_next; + else + select_list = p_next; + + g_free (p); + p = p_next; + } else { + p_prev = p; + p = p->next; + } +} + +void +channels_up (void) +{ + if (disabled_channels == 0) + fputs ("Error: channels_up called with disabled_channels = 0\n", + stderr); + disabled_channels--; +} + +void +channels_down (void) +{ + disabled_channels++; +} + +/* + * Common handler for standard movement keys in a text area. Provided + * functions are called with the "data" argument. backfn and forfn also + * get an argument indicating how many lines to scroll. Return MSG_HANDLED + * if the key was handled, MSG_NOT_HANDLED otherwise. + */ +cb_ret_t +check_movement_keys (int key, int page_size, void *data, move_fn backfn, + move_fn forfn, move_fn topfn, move_fn bottomfn) +{ + switch (key) { + case KEY_UP: + case XCTRL ('p'): + (*backfn) (data, 1); + break; + + case KEY_DOWN: + case XCTRL ('n'): + (*forfn) (data, 1); + break; + + case KEY_PPAGE: + case ALT ('v'): + (*backfn) (data, page_size - 1); + break; + + case KEY_NPAGE: + case XCTRL ('v'): + (*forfn) (data, page_size - 1); + break; + + case KEY_HOME: + case KEY_M_CTRL | KEY_HOME: + case KEY_M_CTRL | KEY_PPAGE: + case KEY_A1: + case ALT ('<'): + (*topfn) (data, 0); + break; + + case KEY_END: + case KEY_M_CTRL | KEY_END: + case KEY_M_CTRL | KEY_NPAGE: + case KEY_C1: + case ALT ('>'): + (*bottomfn) (data, 0); + break; + + case 'b': + case KEY_BACKSPACE: + (*backfn) (data, page_size - 1); + break; + + case ' ': + (*forfn) (data, page_size - 1); + break; + + case 'u': + (*backfn) (data, page_size / 2); + break; + + case 'd': + (*forfn) (data, page_size / 2); + break; + + case 'g': + (*topfn) (data, 0); + break; + + case 'G': + (*bottomfn) (data, 0); + break; + + default: + return MSG_NOT_HANDLED; + } + return MSG_HANDLED; +} + +int +lookup_keyname (char *keyname) +{ + int i; + + if (keyname[0] == '\0') + return 0; + if (keyname[1] == '\0') + return (int) keyname[0]; + + for (i = 0; key_name_conv_tab [i].code; i++) + if (str_casecmp (key_name_conv_tab [i].name, keyname) == 0) + return key_name_conv_tab [i].code; + + return 0; +} + +/* Return the code associated with the symbolic name keyname */ +int +lookup_key (char *keyname) +{ + int k = -1; + char **keys; + guint keys_count = -1; + int key = 0; + int i = 0; + + if (keyname == NULL) + return 0; + + keys = g_strsplit (keyname, " ", -1); + keys_count = g_strv_length (keys); + for (i = keys_count - 1; i >= 0; i--) { + if (keys[i] !=NULL && keys[i][0] != 0) { + key = lookup_keyname (keys[i]); + if (key & KEY_M_CTRL) { + if (k < 256) + k = XCTRL(k); + else + k |= key; + } else { + if (k == -1) + k = key; + else + k |= key; + } + } + } + if (k == -1) + return 0; + + return k; +} + +/* + * Return TRUE on success, FALSE on error. + * An error happens if SEQ is a beginning of an existing longer sequence. + */ +gboolean +define_sequence (int code, const char *seq, int action) +{ + key_def *base; + + if (strlen (seq) > SEQ_BUFFER_LEN - 1) + return FALSE; + + for (base = keys; (base != NULL) && (*seq != '\0'); ) + if (*seq == base->ch) { + if (base->child == 0) { + if (*(seq + 1) != '\0') + base->child = create_sequence (seq + 1, code, action); + else { + /* The sequence matches an existing one. */ + base->code = code; + base->action = action; + } + return TRUE; + } + + base = base->child; + seq++; + } else { + if (base->next) + base = base->next; + else { + base->next = create_sequence (seq, code, action); + return TRUE; + } + } + + if (*seq == '\0') { + /* Attempt to redefine a sequence with a shorter sequence. */ + return FALSE; + } + + keys = create_sequence (seq, code, action); + return TRUE; +} + +/* + * Check if we are idle, i.e. there are no pending keyboard or mouse + * events. Return 1 is idle, 0 is there are pending events. + */ +gboolean +is_idle (void) +{ + int maxfdp; + fd_set select_set; + struct timeval timeout; + + FD_ZERO (&select_set); + FD_SET (input_fd, &select_set); + maxfdp = input_fd; +#ifdef HAVE_LIBGPM + if (mouse_enabled && (use_mouse_p == MOUSE_GPM) && (gpm_fd > 0)) { + FD_SET (gpm_fd, &select_set); + maxfdp = max (maxfdp, gpm_fd); + } +#endif + timeout.tv_sec = 0; + timeout.tv_usec = 0; + return (select (maxfdp + 1, &select_set, 0, 0, &timeout) <= 0); +} + +int +get_key_code (int no_delay) +{ + int c; + static key_def *this = NULL, *parent; + static struct timeval esctime = { -1, -1 }; + static int lastnodelay = -1; + + if (no_delay != lastnodelay) { + this = NULL; + lastnodelay = no_delay; + } + + pend_send: + if (pending_keys != NULL) { + int d = *pending_keys++; + check_pend: + if (*pending_keys == 0) { + pending_keys = NULL; + seq_append = NULL; + } + if ((d == ESC_CHAR) && (pending_keys != NULL)) { + d = ALT (*pending_keys++); + goto check_pend; + } + if ((d > 127 && d < 256) && use_8th_bit_as_meta) + d = ALT(d & 0x7f); + this = NULL; + return correct_key_code (d); + } + + nodelay_try_again: + if (no_delay) + tty_nodelay (TRUE); + + c = tty_lowlevel_getch (); +#if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE) + if (c == KEY_RESIZE) + goto nodelay_try_again; +#endif + if (no_delay) { + tty_nodelay (FALSE); + if (c == -1) { + if (this != NULL && parent != NULL && + parent->action == MCKEY_ESCAPE && old_esc_mode) { + struct timeval current, timeout; + + if (esctime.tv_sec == -1) + return -1; + GET_TIME (current); + timeout.tv_sec = keyboard_key_timeout / 1000000 + esctime.tv_sec; + timeout.tv_usec = keyboard_key_timeout % 1000000 + esctime.tv_usec; + if (timeout.tv_usec > 1000000) { + timeout.tv_usec -= 1000000; + timeout.tv_sec++; + } + if (current.tv_sec < timeout.tv_sec) + return -1; + if (current.tv_sec == timeout.tv_sec && + current.tv_usec < timeout.tv_usec) + return -1; + this = NULL; + pending_keys = seq_append = NULL; + return ESC_CHAR; + } + return -1; + } + } else if (c == -1) { + /* Maybe we got an incomplete match. + This we do only in delay mode, since otherwise + tty_lowlevel_getch can return -1 at any time. */ + if (seq_append != NULL) { + pending_keys = seq_buffer; + goto pend_send; + } + this = NULL; + return -1; + } + + /* Search the key on the root */ + if (!no_delay || this == NULL) { + this = keys; + parent = NULL; + + if ((c > 127 && c < 256) && use_8th_bit_as_meta) { + c &= 0x7f; + + /* The first sequence defined starts with esc */ + parent = keys; + this = keys->child; + } + } + while (this != NULL) { + if (c == this->ch) { + if (this->child) { + if (!push_char (c)) { + pending_keys = seq_buffer; + goto pend_send; + } + parent = this; + this = this->child; + if (parent->action == MCKEY_ESCAPE && old_esc_mode) { + if (no_delay) { + GET_TIME (esctime); + if (this == NULL) { + /* Shouldn't happen */ + fputs ("Internal error\n", stderr); + exit (1); + } + goto nodelay_try_again; + } + esctime.tv_sec = -1; + c = xgetch_second (); + if (c == -1) { + pending_keys = seq_append = NULL; + this = NULL; + return ESC_CHAR; + } + } else { + if (no_delay) + goto nodelay_try_again; + c = tty_lowlevel_getch (); + } + } else { + /* We got a complete match, return and reset search */ + int code; + + pending_keys = seq_append = NULL; + code = this->code; + this = NULL; + return correct_key_code (code); + } + } else { + if (this->next != NULL) + this = this->next; + else { + if ((parent != NULL) && (parent->action == MCKEY_ESCAPE)) { + /* Convert escape-digits to F-keys */ + if (g_ascii_isdigit(c)) + c = KEY_F (c - '0'); + else if (c == ' ') + c = ESC_CHAR; + else + c = ALT (c); + + pending_keys = seq_append = NULL; + this = NULL; + return correct_key_code (c); + } + /* Did not find a match or {c} was changed in the if above, + so we have to return everything we had skipped + */ + push_char (c); + pending_keys = seq_buffer; + goto pend_send; + } + } + } + this = NULL; + return correct_key_code (c); +} + +/* Returns a character read from stdin with appropriate interpretation */ +/* Also takes care of generated mouse events */ +/* Returns EV_MOUSE if it is a mouse event */ +/* Returns EV_NONE if non-blocking or interrupt set and nothing was done */ +int +tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block) +{ + int c; + static int flag = 0; /* Return value from select */ +#ifdef HAVE_LIBGPM + static struct Gpm_Event ev; /* Mouse event */ +#endif + struct timeval timeout; + struct timeval *time_addr = NULL; + static int dirty = 3; + + if ((dirty == 3) || is_idle ()) { + mc_refresh (); + dirty = 1; + } else + dirty++; + + vfs_timeout_handler (); + + /* Ok, we use (event->x < 0) to signal that the event does not contain + a suitable position for the mouse, so we can't use show_mouse_pointer + on it. + */ + if (event->x > 0) { + show_mouse_pointer (event->x, event->y); + if (!redo_event) + event->x = -1; + } + + /* Repeat if using mouse */ + while (pending_keys == NULL) { + int maxfdp; + fd_set select_set; + + FD_ZERO (&select_set); + FD_SET (input_fd, &select_set); + maxfdp = max (add_selects (&select_set), input_fd); + +#ifdef HAVE_LIBGPM + if (mouse_enabled && (use_mouse_p == MOUSE_GPM)) { + if (gpm_fd < 0) { + /* Connection to gpm broken, possibly gpm has died */ + mouse_enabled = FALSE; + use_mouse_p = MOUSE_NONE; + break; + } + + FD_SET (gpm_fd, &select_set); + maxfdp = max (maxfdp, gpm_fd); + } +#endif + + if (redo_event) { + timeout.tv_usec = mou_auto_repeat * 1000; + timeout.tv_sec = 0; + + time_addr = &timeout; + } else { + int seconds; + + seconds = vfs_timeouts (); + time_addr = NULL; + + if (seconds != 0) { + /* the timeout could be improved and actually be + * the number of seconds until the next vfs entry + * timeouts in the stamp list. + */ + + timeout.tv_sec = seconds; + timeout.tv_usec = 0; + time_addr = &timeout; + } + } + + if (!block || winch_flag) { + time_addr = &timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + } + + tty_enable_interrupt_key (); + flag = select (maxfdp + 1, &select_set, NULL, NULL, time_addr); + tty_disable_interrupt_key (); + + /* select timed out: it could be for any of the following reasons: + * redo_event -> it was because of the MOU_REPEAT handler + * !block -> we did not block in the select call + * else -> 10 second timeout to check the vfs status. + */ + if (flag == 0) { + if (redo_event) + return EV_MOUSE; + if (!block || winch_flag) + return EV_NONE; + vfs_timeout_handler (); + } + if (flag == -1 && errno == EINTR) + return EV_NONE; + + check_selects (&select_set); + + if (FD_ISSET (input_fd, &select_set)) + break; +#ifdef HAVE_LIBGPM + if (mouse_enabled && use_mouse_p == MOUSE_GPM + && gpm_fd > 0 && FD_ISSET (gpm_fd, &select_set)) { + Gpm_GetEvent (&ev); + Gpm_FitEvent (&ev); + *event = ev; + return EV_MOUSE; + } +#endif /* !HAVE_LIBGPM */ + } + +#ifndef HAVE_SLANG + flag = is_wintouched (stdscr); + untouchwin (stdscr); +#endif /* !HAVE_SLANG */ + c = block ? getch_with_delay () : get_key_code (1); + +#ifndef HAVE_SLANG + if (flag > 0) + tty_touch_screen (); +#endif /* !HAVE_SLANG */ + + if (mouse_enabled && (c == MCKEY_MOUSE +#ifdef KEY_MOUSE + || c == KEY_MOUSE +#endif /* KEY_MOUSE */ + )) { + /* Mouse event */ + xmouse_get_event (event); + return (event->type != 0) ? EV_MOUSE : EV_NONE; + } + + return c; +} + +/* Returns a key press, mouse events are discarded */ +int +tty_getch (void) +{ + Gpm_Event ev; + int key; + + ev.x = -1; + while ((key = tty_get_event (&ev, FALSE, TRUE)) == EV_NONE) + ; + return key; +} + +char * +learn_key (void) +{ +/* LEARN_TIMEOUT in usec */ +#define LEARN_TIMEOUT 200000 + + fd_set Read_FD_Set; + struct timeval endtime; + struct timeval timeout; + int c; + char buffer [256]; + char *p = buffer; + + tty_keypad (FALSE); /* disable intepreting keys by ncurses */ + c = tty_lowlevel_getch (); + while (c == -1) + c = tty_lowlevel_getch (); /* Sanity check, should be unnecessary */ + learn_store_key (buffer, &p, c); + GET_TIME (endtime); + endtime.tv_usec += LEARN_TIMEOUT; + if (endtime.tv_usec > 1000000) { + endtime.tv_usec -= 1000000; + endtime.tv_sec++; + } + tty_nodelay (TRUE); + for (;;) { + while ((c = tty_lowlevel_getch ()) == -1) { + GET_TIME (timeout); + timeout.tv_usec = endtime.tv_usec - timeout.tv_usec; + if (timeout.tv_usec < 0) + timeout.tv_sec++; + timeout.tv_sec = endtime.tv_sec - timeout.tv_sec; + if (timeout.tv_sec >= 0 && timeout.tv_usec > 0) { + FD_ZERO (&Read_FD_Set); + FD_SET (input_fd, &Read_FD_Set); + select (input_fd + 1, &Read_FD_Set, NULL, NULL, &timeout); + } else + break; + } + if (c == -1) + break; + learn_store_key (buffer, &p, c); + } + tty_keypad (TRUE); + tty_nodelay (FALSE); + *p = '\0'; + return g_strdup (buffer); +#undef LEARN_TIMEOUT +} + +/* xterm and linux console only: set keypad to numeric or application + mode. Only in application keypad mode it's possible to distinguish + the '+' key and the '+' on the keypad ('*' and '-' ditto)*/ +void +numeric_keypad_mode (void) +{ + if (console_flag || xterm_flag) { + fputs ("\033>", stdout); + fflush (stdout); + } +} + +void +application_keypad_mode (void) +{ + if (console_flag || xterm_flag) { + fputs ("\033=", stdout); + fflush (stdout); + } +} diff --git a/src/tty/key.c b/src/tty/key.c index af89c7333..07958336b 100644 --- a/src/tty/key.c +++ b/src/tty/key.c @@ -43,13 +43,14 @@ #include "../../src/tty/tty-internal.h" /* mouse_enabled */ #include "../../src/tty/mouse.h" #include "../../src/tty/key.h" -#include "../../src/tty/key_define.h" +#include "../../src/tty/key-define.h" #include "../../src/tty/win.h" /* xterm_flag */ #include "../../src/main.h" #include "../../src/layout.h" /* winch_flag, mc_refresh() */ #include "../../src/cons.saver.h" #include "../../src/strutil.h" /* str_casecmp */ +#include "../../src/event/event.h" #ifdef USE_VFS #include "../../vfs/gc.h" @@ -81,6 +82,9 @@ /*** global variables **************************************************/ +int input_fd; + + /* If true, use + and \ keys normally and select/unselect do if M-+ / M-\. and M-- and keypad + / - */ int alternate_plus_minus = 0; @@ -221,7 +225,6 @@ static int keyboard_key_timeout = 1000000; /* settable via env */ /* This holds all the key definitions */ static key_def *keys = NULL; -static int input_fd; static int disabled_channels = 0; /* Disable channels checking */ static SelectList *select_list = NULL; @@ -759,6 +762,7 @@ s_dispose (SelectList *sel) } } + /*** public functions **************************************************/ /* This has to be called before init_slang or whatever routine @@ -771,6 +775,8 @@ init_key (void) if (kt != NULL) keyboard_key_timeout = atoi (kt); + tty_key_gsource_init(); + /* This has to be the first define_sequence */ /* So, we can assume that the first keys member has ESC */ define_sequences (mc_default_keys); @@ -833,6 +839,7 @@ done_key (void) if (x11_display) mc_XCloseDisplay (x11_display); #endif + tty_key_gsource_deinit(); } void @@ -1257,6 +1264,14 @@ get_key_code (int no_delay) /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */ int tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block) +{ + sleep(1); +mc_log("tty_get_event\n"); + return EV_MOUSE; +} + +int +tty_get_event_NONUSED (struct Gpm_Event *event, gboolean redo_event, gboolean block) { int c; static int flag = 0; /* Return value from select */ @@ -1402,6 +1417,8 @@ tty_getch (void) Gpm_Event ev; int key; +mc_log("tty_getch\n"); + ev.x = -1; while ((key = tty_get_event (&ev, FALSE, TRUE)) == EV_NONE) ; diff --git a/src/tty/key.h b/src/tty/key.h index 2090f9abc..cd218d0d8 100644 --- a/src/tty/key.h +++ b/src/tty/key.h @@ -11,9 +11,14 @@ #include "../../src/tty/tty.h" /* KEY_F macro */ +typedef struct tty_key_event_struct { + int key; +} tty_key_event_t; + + gboolean define_sequence (int code, const char *seq, int action); -void init_key (void); +void tty_key_init (void); void init_key_input_fd (void); void done_key (void); diff --git a/src/tty/keyxdef.c b/src/tty/keyxdef.c index 32b825b3b..9447c9781 100644 --- a/src/tty/keyxdef.c +++ b/src/tty/keyxdef.c @@ -415,7 +415,7 @@ void load_qnx_key_defines (void) #endif /* HAVE_QNX_KEYS */ -/* called from key.c/init_key() */ +/* called from key.c/tty_key_init() */ void load_xtra_key_defines (void) { #ifdef HAVE_QNX_KEYS diff --git a/src/tty/tty-slang.c b/src/tty/tty-slang.c index 831113c1b..19addeb34 100644 --- a/src/tty/tty-slang.c +++ b/src/tty/tty-slang.c @@ -246,7 +246,7 @@ tty_init (gboolean slow, gboolean ugly_lines) tty_start_interrupt_key (); - /* It's the small part from the previous init_key() */ + /* It's the small part from the previous tty_key_init() */ init_key_input_fd (); SLsmg_init_smg ();