diff finch/libgnt/gntkeys.c @ 15817:0e3a8505ebbe

renamed gaim-text to finch
author Sean Egan <seanegan@gmail.com>
date Sun, 18 Mar 2007 19:38:15 +0000
parents
children 2c81ebc7bf0b
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/finch/libgnt/gntkeys.c	Sun Mar 18 19:38:15 2007 +0000
@@ -0,0 +1,243 @@
+#include "gntkeys.h"
+
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+
+char *gnt_key_cup;
+char *gnt_key_cdown;
+char *gnt_key_cleft;
+char *gnt_key_cright;
+
+static const char *term;
+static GHashTable *specials;
+
+void gnt_init_keys()
+{
+	const char *controls[] = {"", "c-", "ctrl-", "ctr-", "ctl-", NULL};
+	const char *alts[] = {"", "alt-", "a-", "m-", "meta-", NULL};
+	int c, a, ch;
+	char key[32];
+
+	if (term == NULL) {
+		term = getenv("TERM");
+		if (!term)
+			term = "";  /* Just in case */
+	}
+
+	if (strcmp(term, "xterm") == 0 || strcmp(term, "rxvt") == 0) {
+		gnt_key_cup    = "\033" "[1;5A";
+		gnt_key_cdown  = "\033" "[1;5B";
+		gnt_key_cright = "\033" "[1;5C";
+		gnt_key_cleft  = "\033" "[1;5D";
+	} else if (strcmp(term, "screen") == 0 || strcmp(term, "rxvt-unicode") == 0) {
+		gnt_key_cup    = "\033" "Oa";
+		gnt_key_cdown  = "\033" "Ob";
+		gnt_key_cright = "\033" "Oc";
+		gnt_key_cleft  = "\033" "Od";
+	}
+
+	specials = g_hash_table_new(g_str_hash, g_str_equal);
+
+#define INSERT_KEY(k, code) do { \
+		g_hash_table_insert(specials, g_strdup(k), g_strdup(code)); \
+		gnt_keys_add_combination(code); \
+	} while (0)
+
+	INSERT_KEY("home",     GNT_KEY_HOME);
+	INSERT_KEY("end",      GNT_KEY_END);
+	INSERT_KEY("pageup",   GNT_KEY_PGUP);
+	INSERT_KEY("pagedown", GNT_KEY_PGDOWN);
+	INSERT_KEY("insert",   GNT_KEY_INS);
+	INSERT_KEY("delete",   GNT_KEY_DEL);
+
+	INSERT_KEY("left",   GNT_KEY_LEFT);
+	INSERT_KEY("right",  GNT_KEY_RIGHT);
+	INSERT_KEY("up",     GNT_KEY_UP);
+	INSERT_KEY("down",   GNT_KEY_DOWN);
+
+	INSERT_KEY("tab",    "\t");
+	INSERT_KEY("menu",   GNT_KEY_POPUP);
+
+	INSERT_KEY("f1",   GNT_KEY_F1);
+	INSERT_KEY("f2",   GNT_KEY_F2);
+	INSERT_KEY("f3",   GNT_KEY_F3);
+	INSERT_KEY("f4",   GNT_KEY_F4);
+	INSERT_KEY("f5",   GNT_KEY_F5);
+	INSERT_KEY("f6",   GNT_KEY_F6);
+	INSERT_KEY("f7",   GNT_KEY_F7);
+	INSERT_KEY("f8",   GNT_KEY_F8);
+	INSERT_KEY("f9",   GNT_KEY_F9);
+	INSERT_KEY("f10",  GNT_KEY_F10);
+	INSERT_KEY("f11",  GNT_KEY_F11);
+	INSERT_KEY("f12",  GNT_KEY_F12);
+
+#define REM_LENGTH  (sizeof(key) - (cur - key))
+#define INSERT_COMB(k, code) do { \
+		snprintf(key, sizeof(key), "%s%s%s", controls[c], alts[a], k);  \
+		INSERT_KEY(key, code);  \
+	} while (0);
+
+	/* Lower-case alphabets */
+	for (a = 0, c = 0; controls[c]; c++, a = 0) {
+		if (c) {
+			INSERT_COMB("up",    gnt_key_cup);
+			INSERT_COMB("down",  gnt_key_cdown);
+			INSERT_COMB("left",  gnt_key_cleft);
+			INSERT_COMB("right", gnt_key_cright);
+		}
+
+		for (a = 0; alts[a]; a++) {
+			for (ch = 0; ch < 26; ch++) {
+				char str[2] = {'a' + ch, 0}, code[4] = "\0\0\0\0";
+				int ind = 0;
+				if (a)
+					code[ind++] = '\033';
+				code[ind] = (c ? 1 : 'a') + ch;
+				INSERT_COMB(str, code);
+			}
+		}
+	}
+	c = 0;
+	for (a = 0; alts[a]; a++) {
+		/* Upper-case alphabets */
+		for (ch = 0; ch < 26; ch++) {
+			char str[2] = {'A' + ch, 0}, code[] = {'\033', 'A' + ch, 0};
+			INSERT_COMB(str, code);
+		}
+		/* Digits */
+		for (ch = 0; ch < 10; ch++) {
+			char str[2] = {'0' + ch, 0}, code[] = {'\033', '0' + ch, 0};
+			INSERT_COMB(str, code);
+		}
+	}
+}
+
+void gnt_keys_refine(char *text)
+{
+	if (*text == 27 && *(text + 1) == '[' &&
+			(*(text + 2) >= 'A' && *(text + 2) <= 'D')) {
+		/* Apparently this is necessary for urxvt and screen and xterm */
+		if (strcmp(term, "screen") == 0 || strcmp(term, "rxvt-unicode") == 0 ||
+				strcmp(term, "xterm") == 0)
+			*(text + 1) = 'O';
+	} else if (*(unsigned char*)text == 195) {
+		if (*(text + 2) == 0 && strcmp(term, "xterm") == 0) {
+			*(text) = 27;
+			*(text + 1) -= 64;  /* Say wha? */
+		}
+	}
+}
+
+const char *gnt_key_translate(const char *name)
+{
+	return g_hash_table_lookup(specials, name);
+}
+
+/**
+ * The key-bindings will be saved in a tree. When a keystroke happens, GNT will
+ * find the sequence that matches a binding and return the length.
+ * A sequence should not be a prefix of another sequence. If it is, then only
+ * the shortest one will be processed. If we want to change that, we will need
+ * to allow getting the k-th prefix that matches the input, and pay attention
+ * to the return value of gnt_wm_process_input in gntmain.c.
+ */
+#define SIZE 256
+
+#define IS_END         1 << 0
+struct _node
+{
+	struct _node *next[SIZE];
+	int ref;
+	int flags;
+};
+
+static struct _node root = {.ref = 1, .flags = 0};
+
+static void add_path(struct _node *node, const char *path)
+{
+	struct _node *n = NULL;
+	if (!path || !*path) {
+		node->flags |= IS_END;
+		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;
+	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;
+
+	root.flags &= ~IS_END;
+	while (*path && n->next[*path] && !(n->flags & IS_END)) {
+		if (g_utf8_find_next_char(path, NULL) - path > 1)
+			return 0;
+		n = n->next[*path++];
+		depth++;
+	}
+
+	if (!(n->flags & IS_END))
+		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 * 4, 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(void);
+void gnt_keys_print_combinations()
+{
+	g_printerr("--------\n");
+	print_path(&root, 1);
+	g_printerr("--------\n");
+}
+