diff options
-rw-r--r-- | src/fe-text/gui-readline.c | 107 |
1 files changed, 103 insertions, 4 deletions
diff --git a/src/fe-text/gui-readline.c b/src/fe-text/gui-readline.c index 6d021c9c..f57e5600 100644 --- a/src/fe-text/gui-readline.c +++ b/src/fe-text/gui-readline.c @@ -37,6 +37,8 @@ #include <signal.h> +#define PASTE_MAX_KEYCOUNT 100 + typedef void (*ENTRY_REDIRECT_KEY_FUNC) (int key, void *data, SERVER_REC *server, WI_ITEM_REC *item); typedef void (*ENTRY_REDIRECT_ENTRY_FUNC) (const char *line, void *data, SERVER_REC *server, WI_ITEM_REC *item); @@ -51,7 +53,12 @@ static ENTRY_REDIRECT_REC *redir; static int escape_next_key; static int readtag; -static time_t idle_time; +static GTimeVal last_keypress; +static int paste_detect_time, paste_detect_keycount; +static int paste_state, paste_start_key; +static char *paste_entry, *prev_entry; +static int paste_entry_pos, prev_entry_pos; +static unichar prev_key, paste_keys[PASTE_MAX_KEYCOUNT]; static void sig_input(void); @@ -134,10 +141,68 @@ static void window_next_page(void) gui_window_scroll(active_win, get_scroll_count()); } +#define IS_PASTE_SKIP_KEY(c) \ + ((c) == '\r' || (c) == '\n') + +static int check_pasting(unichar key, int diff) +{ + int i; + + if (paste_state == 0) { + /* two keys hit together quick. possibly pasting */ + if (diff > paste_detect_time) + return FALSE; + + g_free(paste_entry); + paste_entry = g_strdup(prev_entry); + paste_entry_pos = prev_entry_pos; + + paste_state++; + paste_start_key = IS_PASTE_SKIP_KEY(prev_key) ? 1 : 0; + paste_keys[0] = prev_key; + } else if (paste_state > 0 && diff > paste_detect_time) { + /* reset paste state */ + paste_state = 0; + return FALSE; + } + + /* continuing quick hits */ + if (paste_state == paste_detect_keycount) { + /* pasting.. */ + if (IS_PASTE_SKIP_KEY(key)) { + /* handle CR/LF the normal way */ + return FALSE; + } + gui_entry_insert_char(active_entry, key); + return TRUE; + } + + if (IS_PASTE_SKIP_KEY(key)) { + /* we might be pasting, but we can't go back from executed + commands.. */ + paste_start_key = ++paste_state; + return FALSE; + } + + paste_keys[paste_state++] = key; + if (paste_state == paste_detect_keycount) { + /* ok, we started pasting. */ + gui_entry_set_text(active_entry, paste_entry); + gui_entry_set_pos(active_entry, paste_entry_pos); + for (i = paste_start_key; i < paste_detect_keycount; i++) + gui_entry_insert_char(active_entry, paste_keys[i]); + return TRUE; + } + + return FALSE; +} + static void sig_gui_key_pressed(gpointer keyp) { + GTimeVal now; unichar key; char str[20]; + int diff; key = GPOINTER_TO_INT(keyp); @@ -146,7 +211,13 @@ static void sig_gui_key_pressed(gpointer keyp) return; } - idle_time = time(NULL); + g_get_current_time(&now); + diff = (now.tv_sec - last_keypress.tv_sec) * 1000 + + (now.tv_usec - last_keypress.tv_usec)/1000; + last_keypress = now; + + if (check_pasting(key, diff)) + return; if (key < 32) { /* control key */ @@ -177,6 +248,11 @@ static void sig_gui_key_pressed(gpointer keyp) str[2] = '\0'; } + g_free(prev_entry); + prev_entry = gui_entry_get_text(active_entry); + prev_entry_pos = gui_entry_get_pos(active_entry); + prev_key = key; + if (escape_next_key || !key_pressed(keyboard, str)) { /* key wasn't used for anything, print it */ escape_next_key = FALSE; @@ -385,7 +461,7 @@ static void sig_input(void) time_t get_idle_time(void) { - return idle_time; + return last_keypress.tv_sec; } static void key_scroll_backward(void) @@ -637,6 +713,21 @@ static void sig_gui_entry_redirect(SIGNAL_FUNC func, const char *entry, gui_entry_set_prompt(active_entry, entry); } +static void setup_changed(void) +{ + paste_detect_time = settings_get_time("paste_detect_time"); + if (paste_detect_time == 0) + paste_state = -1; + else if (paste_state == -1) + paste_state = 0; + + paste_detect_keycount = settings_get_int("paste_detect_keycount"); + if (paste_detect_keycount < 2) + paste_detect_keycount = 2; + else if (paste_detect_keycount > PASTE_MAX_KEYCOUNT) + paste_detect_keycount = PASTE_MAX_KEYCOUNT; +} + void gui_readline_init(void) { static char changekeys[] = "1234567890qwertyuio"; @@ -645,10 +736,16 @@ void gui_readline_init(void) escape_next_key = FALSE; redir = NULL; - idle_time = time(NULL); + paste_state = 0; + paste_entry = NULL; + paste_entry_pos = 0; + g_get_current_time(&last_keypress); input_listen_init(STDIN_FILENO); settings_add_str("history", "scroll_page_count", "/2"); + settings_add_time("misc", "paste_detect_time", "10msecs"); + settings_add_int("misc", "paste_detect_keycount", 5); + setup_changed(); keyboard = keyboard_create(NULL); key_configure_freeze(); @@ -774,6 +871,7 @@ void gui_readline_init(void) signal_add("window changed automatic", (SIGNAL_FUNC) sig_window_auto_changed); signal_add("gui entry redirect", (SIGNAL_FUNC) sig_gui_entry_redirect); signal_add("gui key pressed", (SIGNAL_FUNC) sig_gui_key_pressed); + signal_add("setup changed", (SIGNAL_FUNC) setup_changed); } void gui_readline_deinit(void) @@ -838,4 +936,5 @@ void gui_readline_deinit(void) signal_remove("window changed automatic", (SIGNAL_FUNC) sig_window_auto_changed); signal_remove("gui entry redirect", (SIGNAL_FUNC) sig_gui_entry_redirect); signal_remove("gui key pressed", (SIGNAL_FUNC) sig_gui_key_pressed); + signal_remove("setup changed", (SIGNAL_FUNC) setup_changed); } |