Add struct stat into struct directory, special case for symbolic links
[cmus.git] / keys.c
blobbc0cea57bc1a7fa100fcc03f8d7bd3ed4291b4f4
1 /*
2 * Copyright 2004-2006 Timo Hirvonen
4 * keys.[ch] by Frank Terbeck <frank.terbeck@rwth-aachen.de>
5 * heavily modified by Timo Hirvonen
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
23 #include <keys.h>
24 #include <ui_curses.h>
25 #include <command_mode.h>
26 #include <xmalloc.h>
28 #if defined(__sun__)
29 #include <ncurses.h>
30 #else
31 #include <curses.h>
32 #endif
34 const char * const key_context_names[NR_CTXS + 1] = {
35 "browser",
36 "common",
37 "filters",
38 "library",
39 "playlist",
40 "queue",
41 NULL
44 struct binding *key_bindings[NR_CTXS] = { NULL, };
46 static const enum key_context view_to_context[] = {
47 CTX_LIBRARY,
48 CTX_LIBRARY,
49 CTX_PLAYLIST,
50 CTX_QUEUE,
51 CTX_BROWSER,
52 CTX_FILTERS
55 #define KEY_IS_CHAR -255
57 /* key_table {{{
59 * key: KEY_IS_CHAR, not a key
60 * ch: 0, not a char
62 const struct key key_table[] = {
63 { "!", KEY_IS_CHAR, 33 },
64 { "\"", KEY_IS_CHAR, 34 },
65 { "#", KEY_IS_CHAR, 35 },
66 { "$", KEY_IS_CHAR, 36 },
67 { "%", KEY_IS_CHAR, 37 },
68 { "&", KEY_IS_CHAR, 38 },
69 { "'", KEY_IS_CHAR, 39 },
70 { "(", KEY_IS_CHAR, 40 },
71 { ")", KEY_IS_CHAR, 41 },
72 { "*", KEY_IS_CHAR, 42 },
73 { "+", KEY_IS_CHAR, 43 },
74 { ",", KEY_IS_CHAR, 44 },
75 { "-", KEY_IS_CHAR, 45 },
76 { ".", KEY_IS_CHAR, 46 },
77 { "0", KEY_IS_CHAR, 48 },
78 { "1", KEY_IS_CHAR, 49 },
79 { "2", KEY_IS_CHAR, 50 },
80 { "3", KEY_IS_CHAR, 51 },
81 { "4", KEY_IS_CHAR, 52 },
82 { "5", KEY_IS_CHAR, 53 },
83 { "6", KEY_IS_CHAR, 54 },
84 { "7", KEY_IS_CHAR, 55 },
85 { "8", KEY_IS_CHAR, 56 },
86 { "9", KEY_IS_CHAR, 57 },
87 { ";", KEY_IS_CHAR, 59 },
88 { "<", KEY_IS_CHAR, 60 },
89 { "=", KEY_IS_CHAR, 61 },
90 { ">", KEY_IS_CHAR, 62 },
91 { "@", KEY_IS_CHAR, 64 },
92 { "A", KEY_IS_CHAR, 65 },
93 { "B", KEY_IS_CHAR, 66 },
94 { "C", KEY_IS_CHAR, 67 },
95 { "D", KEY_IS_CHAR, 68 },
96 { "E", KEY_IS_CHAR, 69 },
97 { "F", KEY_IS_CHAR, 70 },
98 { "F1", KEY_F(1), 0 },
99 { "F10", KEY_F(10), 0 },
100 { "F11", KEY_F(11), 0 },
101 { "F12", KEY_F(12), 0 },
102 { "F2", KEY_F(2), 0 },
103 { "F3", KEY_F(3), 0 },
104 { "F4", KEY_F(4), 0 },
105 { "F5", KEY_F(5), 0 },
106 { "F6", KEY_F(6), 0 },
107 { "F7", KEY_F(7), 0 },
108 { "F8", KEY_F(8), 0 },
109 { "F9", KEY_F(9), 0 },
110 { "G", KEY_IS_CHAR, 71 },
111 { "H", KEY_IS_CHAR, 72 },
112 { "I", KEY_IS_CHAR, 73 },
113 { "J", KEY_IS_CHAR, 74 },
114 { "K", KEY_IS_CHAR, 75 },
115 { "KP_center", KEY_B2, 0 },
116 { "KP_lower_left", KEY_C1, 0 },
117 { "KP_lower_right", KEY_C3, 0 },
118 { "KP_upper_left", KEY_A1, 0 },
119 { "KP_upper_right", KEY_A3, 0 },
120 { "L", KEY_IS_CHAR, 76 },
121 { "M", KEY_IS_CHAR, 77 },
122 { "M-!", KEY_IS_CHAR, 161 },
123 { "M-\"", KEY_IS_CHAR, 162 },
124 { "M-#", KEY_IS_CHAR, 163 },
125 { "M-$", KEY_IS_CHAR, 164 },
126 { "M-%", KEY_IS_CHAR, 165 },
127 { "M-&", KEY_IS_CHAR, 166 },
128 { "M-'", KEY_IS_CHAR, 167 },
129 { "M-(", KEY_IS_CHAR, 168 },
130 { "M-)", KEY_IS_CHAR, 169 },
131 { "M-*", KEY_IS_CHAR, 170 },
132 { "M-+", KEY_IS_CHAR, 171 },
133 { "M-,", KEY_IS_CHAR, 172 },
134 { "M--", KEY_IS_CHAR, 173 },
135 { "M-.", KEY_IS_CHAR, 174 },
136 { "M-/", KEY_IS_CHAR, 175 },
137 { "M-0", KEY_IS_CHAR, 176 },
138 { "M-1", KEY_IS_CHAR, 177 },
139 { "M-2", KEY_IS_CHAR, 178 },
140 { "M-3", KEY_IS_CHAR, 179 },
141 { "M-4", KEY_IS_CHAR, 180 },
142 { "M-5", KEY_IS_CHAR, 181 },
143 { "M-6", KEY_IS_CHAR, 182 },
144 { "M-7", KEY_IS_CHAR, 183 },
145 { "M-8", KEY_IS_CHAR, 184 },
146 { "M-9", KEY_IS_CHAR, 185 },
147 { "M-:", KEY_IS_CHAR, 186 },
148 { "M-;", KEY_IS_CHAR, 187 },
149 { "M-<", KEY_IS_CHAR, 188 },
150 { "M-=", KEY_IS_CHAR, 189 },
151 { "M->", KEY_IS_CHAR, 190 },
152 { "M-?", KEY_IS_CHAR, 191 },
153 { "M-@", KEY_IS_CHAR, 192 },
154 { "M-A", KEY_IS_CHAR, 193 },
155 { "M-B", KEY_IS_CHAR, 194 },
156 { "M-C", KEY_IS_CHAR, 195 },
157 { "M-D", KEY_IS_CHAR, 196 },
158 { "M-E", KEY_IS_CHAR, 197 },
159 { "M-F", KEY_IS_CHAR, 198 },
160 { "M-G", KEY_IS_CHAR, 199 },
161 { "M-H", KEY_IS_CHAR, 200 },
162 { "M-I", KEY_IS_CHAR, 201 },
163 { "M-J", KEY_IS_CHAR, 202 },
164 { "M-K", KEY_IS_CHAR, 203 },
165 { "M-L", KEY_IS_CHAR, 204 },
166 { "M-M", KEY_IS_CHAR, 205 },
167 { "M-N", KEY_IS_CHAR, 206 },
168 { "M-O", KEY_IS_CHAR, 207 },
169 { "M-P", KEY_IS_CHAR, 208 },
170 { "M-Q", KEY_IS_CHAR, 209 },
171 { "M-R", KEY_IS_CHAR, 210 },
172 { "M-S", KEY_IS_CHAR, 211 },
173 { "M-T", KEY_IS_CHAR, 212 },
174 { "M-U", KEY_IS_CHAR, 213 },
175 { "M-V", KEY_IS_CHAR, 214 },
176 { "M-W", KEY_IS_CHAR, 215 },
177 { "M-X", KEY_IS_CHAR, 216 },
178 { "M-Y", KEY_IS_CHAR, 217 },
179 { "M-Z", KEY_IS_CHAR, 218 },
180 { "M-[", KEY_IS_CHAR, 219 },
181 { "M-\\", KEY_IS_CHAR, 220 },
182 { "M-]", KEY_IS_CHAR, 221 },
183 { "M-^", KEY_IS_CHAR, 222 },
184 { "M-^?", KEY_IS_CHAR, 255 },
185 { "M-^@", KEY_IS_CHAR, 128 },
186 { "M-^A", KEY_IS_CHAR, 129 },
187 { "M-^B", KEY_IS_CHAR, 130 },
188 { "M-^C", KEY_IS_CHAR, 131 },
189 { "M-^D", KEY_IS_CHAR, 132 },
190 { "M-^E", KEY_IS_CHAR, 133 },
191 { "M-^F", KEY_IS_CHAR, 134 },
192 { "M-^G", KEY_IS_CHAR, 135 },
193 { "M-^H", KEY_IS_CHAR, 136 },
194 { "M-^I", KEY_IS_CHAR, 137 },
195 { "M-^J", KEY_IS_CHAR, 138 },
196 { "M-^K", KEY_IS_CHAR, 139 },
197 { "M-^L", KEY_IS_CHAR, 140 },
198 { "M-^M", KEY_IS_CHAR, 141 },
199 { "M-^N", KEY_IS_CHAR, 142 },
200 { "M-^O", KEY_IS_CHAR, 143 },
201 { "M-^P", KEY_IS_CHAR, 144 },
202 { "M-^Q", KEY_IS_CHAR, 145 },
203 { "M-^R", KEY_IS_CHAR, 146 },
204 { "M-^S", KEY_IS_CHAR, 147 },
205 { "M-^T", KEY_IS_CHAR, 148 },
206 { "M-^U", KEY_IS_CHAR, 149 },
207 { "M-^V", KEY_IS_CHAR, 150 },
208 { "M-^W", KEY_IS_CHAR, 151 },
209 { "M-^X", KEY_IS_CHAR, 152 },
210 { "M-^Y", KEY_IS_CHAR, 153 },
211 { "M-^Z", KEY_IS_CHAR, 154 },
212 { "M-^[", KEY_IS_CHAR, 155 },
213 { "M-^\\", KEY_IS_CHAR, 156 },
214 { "M-^]", KEY_IS_CHAR, 157 },
215 { "M-^^", KEY_IS_CHAR, 158 },
216 { "M-^_", KEY_IS_CHAR, 159 },
217 { "M-_", KEY_IS_CHAR, 223 },
218 { "M-`", KEY_IS_CHAR, 224 },
219 { "M-a", KEY_IS_CHAR, 225 },
220 { "M-b", KEY_IS_CHAR, 226 },
221 { "M-c", KEY_IS_CHAR, 227 },
222 { "M-d", KEY_IS_CHAR, 228 },
223 { "M-e", KEY_IS_CHAR, 229 },
224 { "M-f", KEY_IS_CHAR, 230 },
225 { "M-g", KEY_IS_CHAR, 231 },
226 { "M-h", KEY_IS_CHAR, 232 },
227 { "M-i", KEY_IS_CHAR, 233 },
228 { "M-j", KEY_IS_CHAR, 234 },
229 { "M-k", KEY_IS_CHAR, 235 },
230 { "M-l", KEY_IS_CHAR, 236 },
231 { "M-m", KEY_IS_CHAR, 237 },
232 { "M-n", KEY_IS_CHAR, 238 },
233 { "M-o", KEY_IS_CHAR, 239 },
234 { "M-p", KEY_IS_CHAR, 240 },
235 { "M-q", KEY_IS_CHAR, 241 },
236 { "M-r", KEY_IS_CHAR, 242 },
237 { "M-s", KEY_IS_CHAR, 243 },
238 { "M-space", KEY_IS_CHAR, 160 },
239 { "M-t", KEY_IS_CHAR, 244 },
240 { "M-u", KEY_IS_CHAR, 245 },
241 { "M-v", KEY_IS_CHAR, 246 },
242 { "M-w", KEY_IS_CHAR, 247 },
243 { "M-x", KEY_IS_CHAR, 248 },
244 { "M-y", KEY_IS_CHAR, 249 },
245 { "M-z", KEY_IS_CHAR, 250 },
246 { "M-{", KEY_IS_CHAR, 251 },
247 { "M-|", KEY_IS_CHAR, 252 },
248 { "M-}", KEY_IS_CHAR, 253 },
249 { "M-~", KEY_IS_CHAR, 254 },
250 { "N", KEY_IS_CHAR, 78 },
251 { "O", KEY_IS_CHAR, 79 },
252 { "P", KEY_IS_CHAR, 80 },
253 { "Q", KEY_IS_CHAR, 81 },
254 { "R", KEY_IS_CHAR, 82 },
255 { "S", KEY_IS_CHAR, 83 },
256 { "S-begin", KEY_SBEG, 0 },
257 { "S-cancel", KEY_SCANCEL, 0 },
258 { "S-command", KEY_SCOMMAND, 0 },
259 { "S-copy", KEY_SCOPY, 0 },
260 { "S-create", KEY_SCREATE, 0 },
261 { "S-del_line", KEY_SDL, 0 },
262 { "S-delete", KEY_SDC, 0 },
263 { "S-eol", KEY_SEOL, 0 },
264 { "S-exit", KEY_SEXIT, 0 },
265 { "S-find", KEY_SFIND, 0 },
266 { "S-help", KEY_SHELP, 0 },
267 { "S-home", KEY_SHOME, 0 },
268 { "S-insert", KEY_SIC, 0 },
269 { "S-left", KEY_SLEFT, 0 },
270 { "S-message", KEY_SMESSAGE, 0 },
271 { "S-move", KEY_SMOVE, 0 },
272 { "S-next", KEY_SNEXT, 0 },
273 { "S-options", KEY_SOPTIONS, 0 },
274 { "S-previous", KEY_SPREVIOUS, 0 },
275 { "S-print", KEY_SPRINT, 0 },
276 { "S-redo", KEY_SREDO, 0 },
277 { "S-replace", KEY_SREPLACE, 0 },
278 { "S-resume", KEY_SRSUME, 0 },
279 { "S-right", KEY_SRIGHT, 0 },
280 { "S-save", KEY_SSAVE, 0 },
281 { "S-suspend", KEY_SSUSPEND, 0 },
282 { "S-undo", KEY_SUNDO, 0 },
283 { "T", KEY_IS_CHAR, 84 },
284 { "U", KEY_IS_CHAR, 85 },
285 { "V", KEY_IS_CHAR, 86 },
286 { "W", KEY_IS_CHAR, 87 },
287 { "X", KEY_IS_CHAR, 88 },
288 { "Y", KEY_IS_CHAR, 89 },
289 { "Z", KEY_IS_CHAR, 90 },
290 { "[", KEY_IS_CHAR, 91 },
291 { "\\", KEY_IS_CHAR, 92 },
292 { "]", KEY_IS_CHAR, 93 },
293 { "^", KEY_IS_CHAR, 94 },
294 { "^A", KEY_IS_CHAR, 1 },
295 { "^B", KEY_IS_CHAR, 2 },
296 { "^C", KEY_IS_CHAR, 3 },
297 { "^D", KEY_IS_CHAR, 4 },
298 { "^E", KEY_IS_CHAR, 5 },
299 { "^F", KEY_IS_CHAR, 6 },
300 { "^G", KEY_IS_CHAR, 7 },
301 { "^H", KEY_IS_CHAR, 8 },
302 { "^K", KEY_IS_CHAR, 11 },
303 { "^L", KEY_IS_CHAR, 12 },
304 { "^M", KEY_IS_CHAR, 13 },
305 { "^N", KEY_IS_CHAR, 14 },
306 { "^O", KEY_IS_CHAR, 15 },
307 { "^P", KEY_IS_CHAR, 16 },
308 { "^Q", KEY_IS_CHAR, 17 },
309 { "^R", KEY_IS_CHAR, 18 },
310 { "^S", KEY_IS_CHAR, 19 },
311 { "^T", KEY_IS_CHAR, 20 },
312 { "^U", KEY_IS_CHAR, 21 },
313 { "^V", KEY_IS_CHAR, 22 },
314 { "^W", KEY_IS_CHAR, 23 },
315 { "^X", KEY_IS_CHAR, 24 },
316 { "^Y", KEY_IS_CHAR, 25 },
317 { "^Z", KEY_IS_CHAR, 26 },
318 { "^\\", KEY_IS_CHAR, 28 },
319 { "^]", KEY_IS_CHAR, 29 },
320 { "^^", KEY_IS_CHAR, 30 },
321 { "^_", KEY_IS_CHAR, 31 },
322 { "_", KEY_IS_CHAR, 95 },
323 { "`", KEY_IS_CHAR, 96 },
324 { "a", KEY_IS_CHAR, 97 },
325 { "b", KEY_IS_CHAR, 98 },
326 { "back_tab", KEY_BTAB, 0 },
327 { "backspace", KEY_BACKSPACE, 127 }, /* NOTE: both key and ch */
328 { "begin", KEY_BEG, 0 },
329 { "c", KEY_IS_CHAR, 99 },
330 { "cancel", KEY_CANCEL, 0 },
331 { "clear", KEY_CLEAR, 0 },
332 { "clear_all_tabs", KEY_CATAB, 0 },
333 { "clear_tab", KEY_CTAB, 0 },
334 { "close", KEY_CLOSE, 0 },
335 { "command", KEY_COMMAND, 0 },
336 { "copy", KEY_COPY, 0 },
337 { "create", KEY_CREATE, 0 },
338 { "d", KEY_IS_CHAR, 100 },
339 { "del_line", KEY_DL, 0 },
340 { "delete", KEY_DC, 0 },
341 { "down", KEY_DOWN, 0 },
342 { "e", KEY_IS_CHAR, 101 },
343 { "eic", KEY_EIC, 0 },
344 { "end", KEY_END, 0 },
345 { "enter", KEY_IS_CHAR, 10 },
346 { "eol", KEY_EOL, 0 },
347 { "eos", KEY_EOS, 0 },
348 { "exit", KEY_EXIT, 0 },
349 { "f", KEY_IS_CHAR, 102 },
350 { "find", KEY_FIND, 0 },
351 { "g", KEY_IS_CHAR, 103 },
352 { "h", KEY_IS_CHAR, 104 },
353 { "help", KEY_HELP, 0 },
354 { "home", KEY_HOME, 0 },
355 { "i", KEY_IS_CHAR, 105 },
356 { "ins_line", KEY_IL, 0 },
357 { "insert", KEY_IC, 0 },
358 { "j", KEY_IS_CHAR, 106 },
359 { "k", KEY_IS_CHAR, 107 },
360 { "l", KEY_IS_CHAR, 108 },
361 { "left", KEY_LEFT, 0 },
362 { "lower_left", KEY_LL, 0 },
363 { "m", KEY_IS_CHAR, 109 },
364 { "mark", KEY_MARK, 0 },
365 { "message", KEY_MESSAGE, 0 },
366 { "move", KEY_MOVE, 0 },
367 { "n", KEY_IS_CHAR, 110 },
368 { "next", KEY_NEXT, 0 },
369 { "o", KEY_IS_CHAR, 111 },
370 { "open", KEY_OPEN, 0 },
371 { "options", KEY_OPTIONS, 0 },
372 { "p", KEY_IS_CHAR, 112 },
373 { "page_down", KEY_NPAGE, 0 },
374 { "page_up", KEY_PPAGE, 0 },
375 { "previous", KEY_PREVIOUS, 0 },
376 { "print", KEY_PRINT, 0 },
377 { "q", KEY_IS_CHAR, 113 },
378 { "r", KEY_IS_CHAR, 114 },
379 { "redo", KEY_REDO, 0 },
380 { "reference", KEY_REFERENCE, 0 },
381 { "refresh", KEY_REFRESH, 0 },
382 { "replace", KEY_REPLACE, 0 },
383 { "restart", KEY_RESTART, 0 },
384 { "resume", KEY_RESUME, 0 },
385 { "right", KEY_RIGHT, 0 },
386 { "s", KEY_IS_CHAR, 115 },
387 { "save", KEY_SAVE, 0 },
388 { "scroll_b", KEY_SR, 0 },
389 { "scroll_f", KEY_SF, 0 },
390 { "select", KEY_SELECT, 0 },
391 { "send", KEY_SEND, 0 },
392 { "set_tab", KEY_STAB, 0 },
393 { "space", KEY_IS_CHAR, 32 },
394 { "suspend", KEY_SUSPEND, 0 },
395 { "t", KEY_IS_CHAR, 116 },
396 { "tab", KEY_IS_CHAR, 9 },
397 { "u", KEY_IS_CHAR, 117 },
398 { "undo", KEY_UNDO, 0 },
399 { "up", KEY_UP, 0 },
400 { "v", KEY_IS_CHAR, 118 },
401 { "w", KEY_IS_CHAR, 119 },
402 { "x", KEY_IS_CHAR, 120 },
403 { "y", KEY_IS_CHAR, 121 },
404 { "z", KEY_IS_CHAR, 122 },
405 { "{", KEY_IS_CHAR, 123 },
406 { "|", KEY_IS_CHAR, 124 },
407 { "}", KEY_IS_CHAR, 125 },
408 { "~", KEY_IS_CHAR, 126 },
409 { NULL, 0, 0 }
411 /* }}} */
413 static int find_context(const char *name)
415 int i;
417 for (i = 0; i < NR_CTXS; i++) {
418 if (strcmp(name, key_context_names[i]) == 0)
419 return i;
421 error_msg("invalid context '%s'", name);
422 return -1;
425 static const struct key *find_key(const char *name)
427 int i;
429 for (i = 0; key_table[i].name; i++) {
430 if (strcmp(name, key_table[i].name) == 0)
431 return &key_table[i];
433 error_msg("invalid key '%s'", name);
434 return NULL;
437 static struct binding *find_binding(enum key_context c, const struct key *k)
439 struct binding *b = key_bindings[c];
441 while (b) {
442 if (b->key == k)
443 break;
444 b = b->next;
446 return b;
449 void show_binding(const char *context, const char *key)
451 const struct key *k;
452 const struct binding *b;
453 int c;
455 c = find_context(context);
456 if (c < 0)
457 return;
459 k = find_key(key);
460 if (k == NULL)
461 return;
463 b = find_binding(c, k);
464 if (b == NULL) {
465 info_msg("No such binding");
466 } else {
467 info_msg("bind %s %s %s", context, key, b->cmd);
471 int key_bind(const char *context, const char *key, const char *cmd, int force)
473 const struct key *k;
474 struct binding *b, *ptr, *prev;
475 int c, size;
477 c = find_context(context);
478 if (c < 0)
479 return -1;
481 k = find_key(key);
482 if (k == NULL)
483 return -1;
485 /* check if already bound */
486 b = find_binding(c, k);
487 if (b) {
488 if (!force)
489 goto bound;
490 key_unbind(context, key, 0);
493 if (*cmd == ':')
494 cmd++;
495 size = strlen(cmd) + 1;
497 b = xmalloc(sizeof(struct binding) + size);
498 b->key = k;
499 memcpy(b->cmd, cmd, size);
501 /* insert keeping sorted by key */
502 prev = NULL;
503 ptr = key_bindings[c];
504 while (ptr) {
505 if (strcmp(b->key->name, ptr->key->name) < 0)
506 break;
507 prev = ptr;
508 ptr = ptr->next;
510 b->next = ptr;
511 if (prev) {
512 prev->next = b;
513 } else {
514 key_bindings[c] = b;
516 return 0;
517 bound:
518 error_msg("key %s already bound in context %s", key, key_context_names[c]);
519 return -1;
522 int key_unbind(const char *context, const char *key, int force)
524 enum key_context c;
525 const struct key *k;
526 struct binding *b, *prev;
528 c = find_context(context);
529 if (c < 0)
530 return -1;
532 k = find_key(key);
533 if (k == NULL)
534 return -1;
536 prev = NULL;
537 b = key_bindings[c];
538 while (b) {
539 if (b->key == k) {
540 if (prev) {
541 prev->next = b->next;
542 } else {
543 key_bindings[c] = b->next;
545 free(b);
546 return 0;
548 prev = b;
549 b = b->next;
551 if (!force) {
552 error_msg("key %s not bound in context %s", key, context);
553 return -1;
555 return 0;
558 static int handle_key(const struct binding *b, const struct key *k)
560 while (b) {
561 if (b->key == k) {
562 run_command(b->cmd);
563 return 1;
565 b = b->next;
567 return 0;
570 static const struct key *ch_to_key(uchar ch)
572 int i;
574 for (i = 0; key_table[i].name; i++) {
575 if (key_table[i].ch == ch)
576 return &key_table[i];
578 return NULL;
581 static const struct key *keycode_to_key(int key)
583 int i;
585 for (i = 0; key_table[i].name; i++) {
586 if (key_table[i].key != KEY_IS_CHAR && key_table[i].key == key)
587 return &key_table[i];
589 return NULL;
592 void normal_mode_ch(uchar ch)
594 enum key_context c;
595 const struct key *k;
597 /* you can't redefine these keys */
598 switch (ch) {
599 case ':':
600 enter_command_mode();
601 return;
602 case '/':
603 enter_search_mode();
604 return;
605 case '?':
606 enter_search_backward_mode();
607 return;
610 c = view_to_context[cur_view];
611 k = ch_to_key(ch);
613 if (k == NULL) {
614 return;
617 /* view-specific ch */
618 if (handle_key(key_bindings[c], k))
619 return;
621 /* common ch */
622 handle_key(key_bindings[CTX_COMMON], k);
625 void normal_mode_key(int key)
627 enum key_context c = view_to_context[cur_view];
628 const struct key *k = keycode_to_key(key);
630 if (k == NULL) {
631 return;
634 /* view-specific key */
635 if (handle_key(key_bindings[c], k))
636 return;
638 /* common key */
639 handle_key(key_bindings[CTX_COMMON], k);