changeset 15778:c2c2a854f5b3

Change a bit how the keystrokes are processed. When a lot of keystrokes come in at the same time, the shortest key-combination is processed first. This should make typing fast over a very slow connection work properly.
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Wed, 07 Mar 2007 12:58:34 +0000
parents 909e59dae123
children 20e934a1a47e
files console/libgnt/gntbindable.c console/libgnt/gntkeys.c console/libgnt/gntkeys.h console/libgnt/gntmain.c console/libgnt/gntwm.c console/libgnt/gntwm.h
diffstat 6 files changed, 145 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/console/libgnt/gntbindable.c	Tue Mar 06 07:17:27 2007 +0000
+++ b/console/libgnt/gntbindable.c	Wed Mar 07 12:58:34 2007 +0000
@@ -155,6 +155,7 @@
 
 	if (name == NULL || *name == '\0') {
 		g_hash_table_remove(klass->bindings, (char*)trigger);
+		gnt_keys_del_combination(trigger);
 		return;
 	}
 
@@ -171,6 +172,7 @@
 	param->action = action;
 	param->list = list;
 	g_hash_table_replace(klass->bindings, g_strdup(trigger), param);
+	gnt_keys_add_combination(trigger);
 }
 
 void gnt_bindable_register_binding(GntBindableClass *klass, const char *name,
--- a/console/libgnt/gntkeys.c	Tue Mar 06 07:17:27 2007 +0000
+++ b/console/libgnt/gntkeys.c	Wed Mar 07 12:58:34 2007 +0000
@@ -1,5 +1,6 @@
 #include "gntkeys.h"
 
+#include <glib.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -8,7 +9,6 @@
 char *gnt_key_cleft;
 char *gnt_key_cright;
 
-
 static const char *term;
 
 void gnt_init_keys()
@@ -48,3 +48,101 @@
 	}
 }
 
+/**
+ * The key-bindings will be saved in a tree. When a keystroke happens, GNT will
+ * find the longest sequence that matches a binding and return the length.
+ */
+#define SIZE 256
+
+#define HAS_CHILD     1 << 0
+struct _node
+{
+	struct _node *next[SIZE];
+	int ref;
+	int flags;
+};
+
+static struct _node root = {.ref = 1, .flags = HAS_CHILD};
+
+static void add_path(struct _node *node, const char *path)
+{
+	struct _node *n = NULL;
+	if (!path || !*path)
+		return;
+	while (*path && node->next[*path]) {
+		node = node->next[*path];
+		node->ref++;
+		path++;
+	}
+	if (!*path)
+		return;
+	n = g_new0(struct _node, 1);
+	n->ref = 1;
+	node->next[*path++] = n;
+	node->flags |= HAS_CHILD;
+	add_path(n, path);
+}
+
+void gnt_keys_add_combination(const char *path)
+{
+	add_path(&root, path);
+}
+
+static void del_path(struct _node *node, const char *path)
+{
+	struct _node *next = NULL;
+
+	if (!*path)
+		return;
+	next = node->next[*path];
+	if (!next)
+		return;
+	del_path(next, path + 1);
+	next->ref--;
+	if (next->ref == 0) {
+		node->next[*path] = NULL;
+		g_free(next);
+	}
+}
+
+void gnt_keys_del_combination(const char *path)
+{
+	del_path(&root, path);
+}
+
+int gnt_keys_find_combination(const char *path)
+{
+	int depth = 0;
+	struct _node *n = &root;
+
+	while (*path && n->next[*path] && (n->flags & HAS_CHILD)) {
+		n = n->next[*path++];
+		depth++;
+	}
+
+	if (n->flags & HAS_CHILD)
+		depth = 0;
+	return depth;
+}
+
+static void
+print_path(struct _node *node, int depth)
+{
+	int i;
+	for (i = 0; i < SIZE; i++) {
+		if (node->next[i]) {
+			g_printerr("%*c (%d:%d)\n", depth, i, node->next[i]->ref,
+						node->next[i]->flags);
+			print_path(node->next[i], depth + 1);
+		}
+	}
+}
+
+/* this is purely for debugging purposes. */
+void gnt_keys_print_combinations()
+{
+	g_printerr("--------\n");
+	print_path(&root, 1);
+	g_printerr("--------\n");
+}
+
--- a/console/libgnt/gntkeys.h	Tue Mar 06 07:17:27 2007 +0000
+++ b/console/libgnt/gntkeys.h	Wed Mar 07 12:58:34 2007 +0000
@@ -82,6 +82,10 @@
 void gnt_init_keys();
 void gnt_keys_refine(char *text);
 
+void gnt_keys_add_combination(const char *path);
+void gnt_keys_del_combination(const char *path);
+int gnt_keys_find_combination(const char *path);
+
 
 /* A lot of commonly used variable names are defined in <term.h>. 
  * #undef them to make life easier for everyone. */
--- a/console/libgnt/gntmain.c	Tue Mar 06 07:17:27 2007 +0000
+++ b/console/libgnt/gntmain.c	Wed Mar 07 12:58:34 2007 +0000
@@ -181,6 +181,8 @@
 {
 	char keys[256];
 	int rd = read(STDIN_FILENO, keys, sizeof(keys) - 1);
+	int processed;
+	char *k;
 	if (rd < 0)
 	{
 		int ch = getch(); /* This should return ERR, but let's see what it really returns */
@@ -192,6 +194,7 @@
 	else if (rd == 0)
 	{
 		endwin();
+		return;
 		printf("EOF\n");
 		raise(SIGABRT);
 	}
@@ -201,8 +204,19 @@
 
 	if (mouse_enabled && detect_mouse_action(keys))
 		return TRUE;
-	
-	gnt_wm_process_input(wm, keys);
+
+	processed = 0;
+	k = keys;
+	while (rd) {
+		char back;
+		int p = MAX(1, gnt_keys_find_combination(k));
+		back = k[p];
+		k[p] = '\0';
+		gnt_wm_process_input(wm, k);
+		k[p] = back;
+		rd -= p;
+		k += p;
+	}
 
 	return TRUE;
 }
--- a/console/libgnt/gntwm.c	Tue Mar 06 07:17:27 2007 +0000
+++ b/console/libgnt/gntwm.c	Wed Mar 07 12:58:34 2007 +0000
@@ -875,6 +875,8 @@
 static void
 gnt_wm_class_init(GntWMClass *klass)
 {
+	int i;
+
 	klass->new_window = gnt_wm_new_window_real;
 	klass->decorate_window = NULL;
 	klass->close_window = NULL;
@@ -1004,6 +1006,14 @@
 				"\033" GNT_KEY_CTRL_K, NULL);
 
 	gnt_style_read_actions(G_OBJECT_CLASS_TYPE(klass), GNT_BINDABLE_CLASS(klass));
+
+	/* Make sure Alt+x are detected properly. */
+	for (i = '0'; i <= '9'; i++) {
+		char str[] = "\033X";
+		str[1] = i;
+		gnt_keys_add_combination(str);
+	}
+
 	GNTDEBUG;
 }
 
@@ -1209,14 +1219,16 @@
 	return time(NULL) - last_active_time;
 }
 
-void gnt_wm_process_input(GntWM *wm, const char *keys)
+gboolean gnt_wm_process_input(GntWM *wm, const char *keys)
 {
+	gboolean ret = FALSE;
+
 	keys = gnt_bindable_remap_keys(GNT_BINDABLE(wm), keys);
 
 	idle_update = TRUE;
 
 	if (gnt_bindable_perform_action_key(GNT_BINDABLE(wm), keys))
-		return;
+		return TRUE;
 
 	/* Do some manual checking */
 	if (wm->ordered && wm->mode != GNT_KP_MODE_NORMAL) {
@@ -1247,7 +1259,7 @@
 			if (ox != x || oy != y) {
 				gnt_screen_move_widget(widget, x, y);
 				window_reverse(widget, TRUE, wm);
-				return;
+				return TRUE;
 			}
 		} else if (wm->mode == GNT_KP_MODE_RESIZE) {
 			if (strcmp(keys, GNT_KEY_LEFT) == 0) {
@@ -1264,14 +1276,14 @@
 			if (oh != h || ow != w) {
 				gnt_screen_resize_widget(widget, w, h);
 				window_reverse(widget, TRUE, wm);
-				return;
+				return TRUE;
 			}
 		}
 		if (strcmp(keys, "\r") == 0 || strcmp(keys, "\033") == 0) {
 			window_reverse(widget, FALSE, wm);
 			wm->mode = GNT_KP_MODE_NORMAL;
 		}
-		return;
+		return TRUE;
 	}
 
 	wm->event_stack = TRUE;
@@ -1281,7 +1293,7 @@
 		if (wm->_list.window) {
 			gnt_widget_destroy(wm->_list.window);
 			wm->event_stack = FALSE;
-			return;
+			return TRUE;
 		}
 	} else if (keys[0] == '\033' && isdigit(keys[1]) && keys[2] == '\0') {
 		/* Alt+x for quick switch */
@@ -1294,16 +1306,17 @@
 		list = g_list_append(list, GINT_TO_POINTER(n - 1));
 		switch_window_n(GNT_BINDABLE(wm), list);
 		g_list_free(list);
-		return;
+		return TRUE;
 	}
 
 	if (wm->menu)
-		gnt_widget_key_pressed(GNT_WIDGET(wm->menu), keys);
+		ret = gnt_widget_key_pressed(GNT_WIDGET(wm->menu), keys);
 	else if (wm->_list.window)
-		gnt_widget_key_pressed(wm->_list.window, keys);
+		ret = gnt_widget_key_pressed(wm->_list.window, keys);
 	else if (wm->ordered)
-		gnt_widget_key_pressed(GNT_WIDGET(wm->ordered->data), keys);
+		ret = gnt_widget_key_pressed(GNT_WIDGET(wm->ordered->data), keys);
 	wm->event_stack = FALSE;
+	return ret;
 }
 
 static void
--- a/console/libgnt/gntwm.h	Tue Mar 06 07:17:27 2007 +0000
+++ b/console/libgnt/gntwm.h	Wed Mar 07 12:58:34 2007 +0000
@@ -151,7 +151,7 @@
 
 void gnt_wm_window_close(GntWM *wm, GntWidget *widget);
 
-void gnt_wm_process_input(GntWM *wm, const char *string);
+gboolean gnt_wm_process_input(GntWM *wm, const char *string);
 
 gboolean gnt_wm_process_click(GntWM *wm, GntMouseEvent event, int x, int y, GntWidget *widget);