summaryrefslogtreecommitdiff
path: root/src/fe-text/gui-readline.c
diff options
context:
space:
mode:
authorTimo Sirainen <cras@irssi.org>2003-11-16 19:37:31 +0000
committercras <cras@dbcabf3a-b0e7-0310-adc4-f8d773084564>2003-11-16 19:37:31 +0000
commitd79cc02a10a0426c9dedd783b634ad7d311f5741 (patch)
tree16343ae3d8b76fb73ee300638678020f101aa422 /src/fe-text/gui-readline.c
parentc8b792e92be6a8d8da472fc1c267899c821c93b8 (diff)
downloadirssi-d79cc02a10a0426c9dedd783b634ad7d311f5741.zip
Added pasting detection. All keys except CR and LF are pasted as-is into
prompt in pasting mode. /SET paste_detect_time controls how closely each others characters must occur for it to be considered pasting. Pasting mode goes on after /SET paste_detect_keycount characters have been received and detected as pasting. The first paste_detect_keycount characters can also contain some command characters. They are executed, but their action in entry line is reverted once pasting is detected. Of course, if any such character was followed by CR/LF, it was already sent to channel/query and is unreversable. What this means in practise is that even if you have TABs (assuming TAB is completion key) in the first few pasted characters, they get pasted as TABs as long as they weren't immediately followed by CR/LF. git-svn-id: http://svn.irssi.org/repos/irssi/trunk@3153 dbcabf3a-b0e7-0310-adc4-f8d773084564
Diffstat (limited to 'src/fe-text/gui-readline.c')
-rw-r--r--src/fe-text/gui-readline.c107
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);
}