Mercurial > pidgin.yaz
annotate finch/libgnt/gntkeys.c @ 18035:c168d1ae2012
A patch from Norbert Buchmuller:
"There's a 'setstatus' command implemented in 'gaim-remote', but there's
no 'getstatus'. For some tasks (eg. setting status to 'offline' on
hibernation and restoring it on resume) it would be useful if such
command existed."
I'm not sure if we're considering this API or not.
committer: Richard Laager <rlaager@wiktel.com>
author | Norbert Buchmuller <norbi@nix.hu> |
---|---|
date | Sun, 03 Jun 2007 19:34:16 +0000 |
parents | ca463cecd432 |
children | d8b9bea550bc 05d7fe2320a9 |
rev | line source |
---|---|
15818 | 1 #include "gntkeys.h" |
2 | |
3 #include <glib.h> | |
4 #include <stdlib.h> | |
5 #include <string.h> | |
6 | |
7 char *gnt_key_cup; | |
8 char *gnt_key_cdown; | |
9 char *gnt_key_cleft; | |
10 char *gnt_key_cright; | |
11 | |
12 static const char *term; | |
13 static GHashTable *specials; | |
14 | |
15 void gnt_init_keys() | |
16 { | |
17 const char *controls[] = {"", "c-", "ctrl-", "ctr-", "ctl-", NULL}; | |
18 const char *alts[] = {"", "alt-", "a-", "m-", "meta-", NULL}; | |
19 int c, a, ch; | |
20 char key[32]; | |
21 | |
22 if (term == NULL) { | |
23 term = getenv("TERM"); | |
24 if (!term) | |
25 term = ""; /* Just in case */ | |
26 } | |
27 | |
28 if (strcmp(term, "xterm") == 0 || strcmp(term, "rxvt") == 0) { | |
29 gnt_key_cup = "\033" "[1;5A"; | |
30 gnt_key_cdown = "\033" "[1;5B"; | |
31 gnt_key_cright = "\033" "[1;5C"; | |
32 gnt_key_cleft = "\033" "[1;5D"; | |
33 } else if (strcmp(term, "screen") == 0 || strcmp(term, "rxvt-unicode") == 0) { | |
34 gnt_key_cup = "\033" "Oa"; | |
35 gnt_key_cdown = "\033" "Ob"; | |
36 gnt_key_cright = "\033" "Oc"; | |
37 gnt_key_cleft = "\033" "Od"; | |
38 } | |
39 | |
40 specials = g_hash_table_new(g_str_hash, g_str_equal); | |
41 | |
42 #define INSERT_KEY(k, code) do { \ | |
43 g_hash_table_insert(specials, g_strdup(k), g_strdup(code)); \ | |
44 gnt_keys_add_combination(code); \ | |
45 } while (0) | |
46 | |
47 INSERT_KEY("home", GNT_KEY_HOME); | |
48 INSERT_KEY("end", GNT_KEY_END); | |
49 INSERT_KEY("pageup", GNT_KEY_PGUP); | |
50 INSERT_KEY("pagedown", GNT_KEY_PGDOWN); | |
51 INSERT_KEY("insert", GNT_KEY_INS); | |
52 INSERT_KEY("delete", GNT_KEY_DEL); | |
53 | |
54 INSERT_KEY("left", GNT_KEY_LEFT); | |
55 INSERT_KEY("right", GNT_KEY_RIGHT); | |
56 INSERT_KEY("up", GNT_KEY_UP); | |
57 INSERT_KEY("down", GNT_KEY_DOWN); | |
58 | |
59 INSERT_KEY("tab", "\t"); | |
60 INSERT_KEY("menu", GNT_KEY_POPUP); | |
61 | |
62 INSERT_KEY("f1", GNT_KEY_F1); | |
63 INSERT_KEY("f2", GNT_KEY_F2); | |
64 INSERT_KEY("f3", GNT_KEY_F3); | |
65 INSERT_KEY("f4", GNT_KEY_F4); | |
66 INSERT_KEY("f5", GNT_KEY_F5); | |
67 INSERT_KEY("f6", GNT_KEY_F6); | |
68 INSERT_KEY("f7", GNT_KEY_F7); | |
69 INSERT_KEY("f8", GNT_KEY_F8); | |
70 INSERT_KEY("f9", GNT_KEY_F9); | |
71 INSERT_KEY("f10", GNT_KEY_F10); | |
72 INSERT_KEY("f11", GNT_KEY_F11); | |
73 INSERT_KEY("f12", GNT_KEY_F12); | |
74 | |
75 #define REM_LENGTH (sizeof(key) - (cur - key)) | |
76 #define INSERT_COMB(k, code) do { \ | |
77 snprintf(key, sizeof(key), "%s%s%s", controls[c], alts[a], k); \ | |
78 INSERT_KEY(key, code); \ | |
79 } while (0); | |
80 | |
81 /* Lower-case alphabets */ | |
82 for (a = 0, c = 0; controls[c]; c++, a = 0) { | |
83 if (c) { | |
84 INSERT_COMB("up", gnt_key_cup); | |
85 INSERT_COMB("down", gnt_key_cdown); | |
86 INSERT_COMB("left", gnt_key_cleft); | |
87 INSERT_COMB("right", gnt_key_cright); | |
88 } | |
89 | |
90 for (a = 0; alts[a]; a++) { | |
91 for (ch = 0; ch < 26; ch++) { | |
92 char str[2] = {'a' + ch, 0}, code[4] = "\0\0\0\0"; | |
93 int ind = 0; | |
94 if (a) | |
95 code[ind++] = '\033'; | |
96 code[ind] = (c ? 1 : 'a') + ch; | |
97 INSERT_COMB(str, code); | |
98 } | |
99 } | |
100 } | |
101 c = 0; | |
102 for (a = 0; alts[a]; a++) { | |
103 /* Upper-case alphabets */ | |
104 for (ch = 0; ch < 26; ch++) { | |
105 char str[2] = {'A' + ch, 0}, code[] = {'\033', 'A' + ch, 0}; | |
106 INSERT_COMB(str, code); | |
107 } | |
108 /* Digits */ | |
109 for (ch = 0; ch < 10; ch++) { | |
110 char str[2] = {'0' + ch, 0}, code[] = {'\033', '0' + ch, 0}; | |
111 INSERT_COMB(str, code); | |
112 } | |
113 } | |
114 } | |
115 | |
116 void gnt_keys_refine(char *text) | |
117 { | |
118 if (*text == 27 && *(text + 1) == '[' && | |
119 (*(text + 2) >= 'A' && *(text + 2) <= 'D')) { | |
120 /* Apparently this is necessary for urxvt and screen and xterm */ | |
121 if (strcmp(term, "screen") == 0 || strcmp(term, "rxvt-unicode") == 0 || | |
122 strcmp(term, "xterm") == 0) | |
123 *(text + 1) = 'O'; | |
124 } else if (*(unsigned char*)text == 195) { | |
125 if (*(text + 2) == 0 && strcmp(term, "xterm") == 0) { | |
126 *(text) = 27; | |
127 *(text + 1) -= 64; /* Say wha? */ | |
128 } | |
129 } | |
130 } | |
131 | |
132 const char *gnt_key_translate(const char *name) | |
133 { | |
134 return g_hash_table_lookup(specials, name); | |
135 } | |
136 | |
15979
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
137 typedef struct { |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
138 const char *name; |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
139 const char *key; |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
140 } gntkey; |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
141 |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
142 static void |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
143 get_key_name(gpointer key, gpointer value, gpointer data) |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
144 { |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
145 gntkey *k = data; |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
146 if (k->name) |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
147 return; |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
148 if (g_utf8_collate(value, k->key) == 0) |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
149 k->name = key; |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
150 } |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
151 |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
152 const char *gnt_key_lookup(const char *key) |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
153 { |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
154 gntkey k = {NULL, key}; |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
155 g_hash_table_foreach(specials, get_key_name, &k); |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
156 return k.name; |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
157 } |
2c81ebc7bf0b
Add a way to get a list of bindings for a widget. This can be used by, eg, a window-manager to show helpful messages to the user.
Sadrul Habib Chowdhury <imadil@gmail.com>
parents:
15818
diff
changeset
|
158 |
15818 | 159 /** |
160 * The key-bindings will be saved in a tree. When a keystroke happens, GNT will | |
161 * find the sequence that matches a binding and return the length. | |
162 * A sequence should not be a prefix of another sequence. If it is, then only | |
163 * the shortest one will be processed. If we want to change that, we will need | |
164 * to allow getting the k-th prefix that matches the input, and pay attention | |
165 * to the return value of gnt_wm_process_input in gntmain.c. | |
166 */ | |
167 #define SIZE 256 | |
168 | |
169 #define IS_END 1 << 0 | |
170 struct _node | |
171 { | |
172 struct _node *next[SIZE]; | |
173 int ref; | |
174 int flags; | |
175 }; | |
176 | |
177 static struct _node root = {.ref = 1, .flags = 0}; | |
178 | |
179 static void add_path(struct _node *node, const char *path) | |
180 { | |
181 struct _node *n = NULL; | |
182 if (!path || !*path) { | |
183 node->flags |= IS_END; | |
184 return; | |
185 } | |
186 while (*path && node->next[*path]) { | |
187 node = node->next[*path]; | |
188 node->ref++; | |
189 path++; | |
190 } | |
191 if (!*path) | |
192 return; | |
193 n = g_new0(struct _node, 1); | |
194 n->ref = 1; | |
195 node->next[*path++] = n; | |
196 add_path(n, path); | |
197 } | |
198 | |
199 void gnt_keys_add_combination(const char *path) | |
200 { | |
201 add_path(&root, path); | |
202 } | |
203 | |
204 static void del_path(struct _node *node, const char *path) | |
205 { | |
206 struct _node *next = NULL; | |
207 | |
208 if (!*path) | |
209 return; | |
210 next = node->next[*path]; | |
211 if (!next) | |
212 return; | |
213 del_path(next, path + 1); | |
214 next->ref--; | |
215 if (next->ref == 0) { | |
216 node->next[*path] = NULL; | |
217 g_free(next); | |
218 } | |
219 } | |
220 | |
221 void gnt_keys_del_combination(const char *path) | |
222 { | |
223 del_path(&root, path); | |
224 } | |
225 | |
226 int gnt_keys_find_combination(const char *path) | |
227 { | |
228 int depth = 0; | |
229 struct _node *n = &root; | |
230 | |
231 root.flags &= ~IS_END; | |
232 while (*path && n->next[*path] && !(n->flags & IS_END)) { | |
16044
ca463cecd432
Only ascii keys can be bound, fixes a crash when inputting non-ascii chars
Richard Nelson <wabz@pidgin.im>
parents:
15979
diff
changeset
|
233 if (!g_ascii_isspace(*path) && |
ca463cecd432
Only ascii keys can be bound, fixes a crash when inputting non-ascii chars
Richard Nelson <wabz@pidgin.im>
parents:
15979
diff
changeset
|
234 !g_ascii_iscntrl(*path) && |
ca463cecd432
Only ascii keys can be bound, fixes a crash when inputting non-ascii chars
Richard Nelson <wabz@pidgin.im>
parents:
15979
diff
changeset
|
235 !g_ascii_isgraph(*path)) |
15818 | 236 return 0; |
237 n = n->next[*path++]; | |
238 depth++; | |
239 } | |
240 | |
241 if (!(n->flags & IS_END)) | |
242 depth = 0; | |
243 return depth; | |
244 } | |
245 | |
246 static void | |
247 print_path(struct _node *node, int depth) | |
248 { | |
249 int i; | |
250 for (i = 0; i < SIZE; i++) { | |
251 if (node->next[i]) { | |
252 g_printerr("%*c (%d:%d)\n", depth * 4, i, node->next[i]->ref, | |
253 node->next[i]->flags); | |
254 print_path(node->next[i], depth + 1); | |
255 } | |
256 } | |
257 } | |
258 | |
259 /* this is purely for debugging purposes. */ | |
260 void gnt_keys_print_combinations(void); | |
261 void gnt_keys_print_combinations() | |
262 { | |
263 g_printerr("--------\n"); | |
264 print_path(&root, 1); | |
265 g_printerr("--------\n"); | |
266 } | |
267 |