comparison finch/libgnt/gntkeys.c @ 23219:7b7af53e136a

disapproval of revision '79699160e06b69f70db91eef65287f15685ec2bf'
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Tue, 27 May 2008 04:10:43 +0000
parents 02b6569d99e9
children ded0a9cf1785
comparison
equal deleted inserted replaced
23218:02b6569d99e9 23219:7b7af53e136a
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
189 void gnt_init_keys() 37 void gnt_init_keys()
190 { 38 {
191 const char *controls[] = {"", "c-", "ctrl-", "ctr-", "ctl-", NULL}; 39 const char *controls[] = {"", "c-", "ctrl-", "ctr-", "ctl-", NULL};
192 const char *alts[] = {"", "alt-", "a-", "m-", "meta-", NULL}; 40 const char *alts[] = {"", "alt-", "a-", "m-", "meta-", NULL};
193 int c, a, ch; 41 int c, a, ch;
194 char key[32]; 42 char key[32];
195
196 memset(&root, 0, sizeof(root));
197 root.ref = 1;
198 43
199 if (term == NULL) { 44 if (term == NULL) {
200 term = getenv("TERM"); 45 term = getenv("TERM");
201 if (!term) 46 if (!term)
202 term = ""; /* Just in case */ 47 term = ""; /* Just in case */
289 INSERT_COMB(str, code); 134 INSERT_COMB(str, code);
290 } 135 }
291 } 136 }
292 } 137 }
293 138
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