Mercurial > pidgin.yaz
comparison finch/libgnt/gntkeys.c @ 23218:02b6569d99e9
We don't need named initialiers here since we're already doing an active initilization
author | Gary Kramlich <grim@reaperworld.com> |
---|---|
date | Tue, 27 May 2008 03:24:19 +0000 |
parents | 44b4e8bd759b |
children | 7b7af53e136a |
comparison
equal
deleted
inserted
replaced
23215:b24d5d112a14 | 23218:02b6569d99e9 |
---|---|
32 char *gnt_key_cright; | 32 char *gnt_key_cright; |
33 | 33 |
34 static const char *term; | 34 static const char *term; |
35 static GHashTable *specials; | 35 static GHashTable *specials; |
36 | 36 |
37 void gnt_keys_refine(char *text) | |
38 { | |
39 if (*text == 27 && *(text + 1) == '[' && | |
40 (*(text + 2) >= 'A' && *(text + 2) <= 'D')) { | |
41 /* Apparently this is necessary for urxvt and screen and xterm */ | |
42 if (strcmp(term, "screen") == 0 || strcmp(term, "rxvt-unicode") == 0 || | |
43 strcmp(term, "xterm") == 0) | |
44 *(text + 1) = 'O'; | |
45 } else if (*(unsigned char*)text == 195) { | |
46 if (*(text + 2) == 0 && strcmp(term, "xterm") == 0) { | |
47 *(text) = 27; | |
48 *(text + 1) -= 64; /* Say wha? */ | |
49 } | |
50 } | |
51 } | |
52 | |
53 const char *gnt_key_translate(const char *name) | |
54 { | |
55 return name ? g_hash_table_lookup(specials, name) : NULL; | |
56 } | |
57 | |
58 typedef struct { | |
59 const char *name; | |
60 const char *key; | |
61 } gntkey; | |
62 | |
63 static void | |
64 get_key_name(gpointer key, gpointer value, gpointer data) | |
65 { | |
66 gntkey *k = data; | |
67 if (k->name) | |
68 return; | |
69 if (g_utf8_collate(value, k->key) == 0) | |
70 k->name = key; | |
71 } | |
72 | |
73 const char *gnt_key_lookup(const char *key) | |
74 { | |
75 gntkey k = {NULL, key}; | |
76 g_hash_table_foreach(specials, get_key_name, &k); | |
77 return k.name; | |
78 } | |
79 | |
80 /** | |
81 * The key-bindings will be saved in a tree. When a keystroke happens, GNT will | |
82 * find the sequence that matches a binding and return the length. | |
83 * A sequence should not be a prefix of another sequence. If it is, then only | |
84 * the shortest one will be processed. If we want to change that, we will need | |
85 * to allow getting the k-th prefix that matches the input, and pay attention | |
86 * to the return value of gnt_wm_process_input in gntmain.c. | |
87 */ | |
88 #define SIZE 256 | |
89 | |
90 #define IS_END 1 << 0 | |
91 struct _node | |
92 { | |
93 struct _node *next[SIZE]; | |
94 int ref; | |
95 int flags; | |
96 }; | |
97 | |
98 struct _node root; | |
99 | |
100 static void add_path(struct _node *node, const char *path) | |
101 { | |
102 struct _node *n = NULL; | |
103 if (!path || !*path) { | |
104 node->flags |= IS_END; | |
105 return; | |
106 } | |
107 while (*path && node->next[(unsigned char)*path]) { | |
108 node = node->next[(unsigned char)*path]; | |
109 node->ref++; | |
110 path++; | |
111 } | |
112 if (!*path) | |
113 return; | |
114 n = g_new0(struct _node, 1); | |
115 n->ref = 1; | |
116 node->next[(unsigned char)*path++] = n; | |
117 add_path(n, path); | |
118 } | |
119 | |
120 void gnt_keys_add_combination(const char *path) | |
121 { | |
122 add_path(&root, path); | |
123 } | |
124 | |
125 static void del_path(struct _node *node, const char *path) | |
126 { | |
127 struct _node *next = NULL; | |
128 | |
129 if (!*path) | |
130 return; | |
131 next = node->next[(unsigned char)*path]; | |
132 if (!next) | |
133 return; | |
134 del_path(next, path + 1); | |
135 next->ref--; | |
136 if (next->ref == 0) { | |
137 node->next[(unsigned char)*path] = NULL; | |
138 g_free(next); | |
139 } | |
140 } | |
141 | |
142 void gnt_keys_del_combination(const char *path) | |
143 { | |
144 del_path(&root, path); | |
145 } | |
146 | |
147 int gnt_keys_find_combination(const char *path) | |
148 { | |
149 int depth = 0; | |
150 struct _node *n = &root; | |
151 | |
152 root.flags &= ~IS_END; | |
153 while (*path && n->next[(unsigned char)*path] && !(n->flags & IS_END)) { | |
154 if (!g_ascii_isspace(*path) && | |
155 !g_ascii_iscntrl(*path) && | |
156 !g_ascii_isgraph(*path)) | |
157 return 0; | |
158 n = n->next[(unsigned char)*path++]; | |
159 depth++; | |
160 } | |
161 | |
162 if (!(n->flags & IS_END)) | |
163 depth = 0; | |
164 return depth; | |
165 } | |
166 | |
167 static void | |
168 print_path(struct _node *node, int depth) | |
169 { | |
170 int i; | |
171 for (i = 0; i < SIZE; i++) { | |
172 if (node->next[i]) { | |
173 g_printerr("%*c (%d:%d)\n", depth * 4, i, node->next[i]->ref, | |
174 node->next[i]->flags); | |
175 print_path(node->next[i], depth + 1); | |
176 } | |
177 } | |
178 } | |
179 | |
180 /* this is purely for debugging purposes. */ | |
181 void gnt_keys_print_combinations(void); | |
182 void gnt_keys_print_combinations() | |
183 { | |
184 g_printerr("--------\n"); | |
185 print_path(&root, 1); | |
186 g_printerr("--------\n"); | |
187 } | |
188 | |
37 void gnt_init_keys() | 189 void gnt_init_keys() |
38 { | 190 { |
39 const char *controls[] = {"", "c-", "ctrl-", "ctr-", "ctl-", NULL}; | 191 const char *controls[] = {"", "c-", "ctrl-", "ctr-", "ctl-", NULL}; |
40 const char *alts[] = {"", "alt-", "a-", "m-", "meta-", NULL}; | 192 const char *alts[] = {"", "alt-", "a-", "m-", "meta-", NULL}; |
41 int c, a, ch; | 193 int c, a, ch; |
42 char key[32]; | 194 char key[32]; |
195 | |
196 memset(&root, 0, sizeof(root)); | |
197 root.ref = 1; | |
43 | 198 |
44 if (term == NULL) { | 199 if (term == NULL) { |
45 term = getenv("TERM"); | 200 term = getenv("TERM"); |
46 if (!term) | 201 if (!term) |
47 term = ""; /* Just in case */ | 202 term = ""; /* Just in case */ |
134 INSERT_COMB(str, code); | 289 INSERT_COMB(str, code); |
135 } | 290 } |
136 } | 291 } |
137 } | 292 } |
138 | 293 |
139 void gnt_keys_refine(char *text) | |
140 { | |
141 if (*text == 27 && *(text + 1) == '[' && | |
142 (*(text + 2) >= 'A' && *(text + 2) <= 'D')) { | |
143 /* Apparently this is necessary for urxvt and screen and xterm */ | |
144 if (strcmp(term, "screen") == 0 || strcmp(term, "rxvt-unicode") == 0 || | |
145 strcmp(term, "xterm") == 0) | |
146 *(text + 1) = 'O'; | |
147 } else if (*(unsigned char*)text == 195) { | |
148 if (*(text + 2) == 0 && strcmp(term, "xterm") == 0) { | |
149 *(text) = 27; | |
150 *(text + 1) -= 64; /* Say wha? */ | |
151 } | |
152 } | |
153 } | |
154 | |
155 const char *gnt_key_translate(const char *name) | |
156 { | |
157 return name ? g_hash_table_lookup(specials, name) : NULL; | |
158 } | |
159 | |
160 typedef struct { | |
161 const char *name; | |
162 const char *key; | |
163 } gntkey; | |
164 | |
165 static void | |
166 get_key_name(gpointer key, gpointer value, gpointer data) | |
167 { | |
168 gntkey *k = data; | |
169 if (k->name) | |
170 return; | |
171 if (g_utf8_collate(value, k->key) == 0) | |
172 k->name = key; | |
173 } | |
174 | |
175 const char *gnt_key_lookup(const char *key) | |
176 { | |
177 gntkey k = {NULL, key}; | |
178 g_hash_table_foreach(specials, get_key_name, &k); | |
179 return k.name; | |
180 } | |
181 | |
182 /** | |
183 * The key-bindings will be saved in a tree. When a keystroke happens, GNT will | |
184 * find the sequence that matches a binding and return the length. | |
185 * A sequence should not be a prefix of another sequence. If it is, then only | |
186 * the shortest one will be processed. If we want to change that, we will need | |
187 * to allow getting the k-th prefix that matches the input, and pay attention | |
188 * to the return value of gnt_wm_process_input in gntmain.c. | |
189 */ | |
190 #define SIZE 256 | |
191 | |
192 #define IS_END 1 << 0 | |
193 struct _node | |
194 { | |
195 struct _node *next[SIZE]; | |
196 int ref; | |
197 int flags; | |
198 }; | |
199 | |
200 static struct _node root = {.ref = 1, .flags = 0}; | |
201 | |
202 static void add_path(struct _node *node, const char *path) | |
203 { | |
204 struct _node *n = NULL; | |
205 if (!path || !*path) { | |
206 node->flags |= IS_END; | |
207 return; | |
208 } | |
209 while (*path && node->next[(unsigned char)*path]) { | |
210 node = node->next[(unsigned char)*path]; | |
211 node->ref++; | |
212 path++; | |
213 } | |
214 if (!*path) | |
215 return; | |
216 n = g_new0(struct _node, 1); | |
217 n->ref = 1; | |
218 node->next[(unsigned char)*path++] = n; | |
219 add_path(n, path); | |
220 } | |
221 | |
222 void gnt_keys_add_combination(const char *path) | |
223 { | |
224 add_path(&root, path); | |
225 } | |
226 | |
227 static void del_path(struct _node *node, const char *path) | |
228 { | |
229 struct _node *next = NULL; | |
230 | |
231 if (!*path) | |
232 return; | |
233 next = node->next[(unsigned char)*path]; | |
234 if (!next) | |
235 return; | |
236 del_path(next, path + 1); | |
237 next->ref--; | |
238 if (next->ref == 0) { | |
239 node->next[(unsigned char)*path] = NULL; | |
240 g_free(next); | |
241 } | |
242 } | |
243 | |
244 void gnt_keys_del_combination(const char *path) | |
245 { | |
246 del_path(&root, path); | |
247 } | |
248 | |
249 int gnt_keys_find_combination(const char *path) | |
250 { | |
251 int depth = 0; | |
252 struct _node *n = &root; | |
253 | |
254 root.flags &= ~IS_END; | |
255 while (*path && n->next[(unsigned char)*path] && !(n->flags & IS_END)) { | |
256 if (!g_ascii_isspace(*path) && | |
257 !g_ascii_iscntrl(*path) && | |
258 !g_ascii_isgraph(*path)) | |
259 return 0; | |
260 n = n->next[(unsigned char)*path++]; | |
261 depth++; | |
262 } | |
263 | |
264 if (!(n->flags & IS_END)) | |
265 depth = 0; | |
266 return depth; | |
267 } | |
268 | |
269 static void | |
270 print_path(struct _node *node, int depth) | |
271 { | |
272 int i; | |
273 for (i = 0; i < SIZE; i++) { | |
274 if (node->next[i]) { | |
275 g_printerr("%*c (%d:%d)\n", depth * 4, i, node->next[i]->ref, | |
276 node->next[i]->flags); | |
277 print_path(node->next[i], depth + 1); | |
278 } | |
279 } | |
280 } | |
281 | |
282 /* this is purely for debugging purposes. */ | |
283 void gnt_keys_print_combinations(void); | |
284 void gnt_keys_print_combinations() | |
285 { | |
286 g_printerr("--------\n"); | |
287 print_path(&root, 1); | |
288 g_printerr("--------\n"); | |
289 } | |
290 |