2 * Copyright 2004-2005 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
28 #include <search_mode.h>
29 #include <play_queue.h>
33 #include <ui_curses.h>
34 #include <file_load.h>
50 #define NR_CTXS (CTX_FILTERS + 1)
65 const struct key
*key
;
66 const struct function
*func
;
69 static const char * const context_names
[NR_CTXS
] = {
77 static const enum context view_to_context
[] = {
86 static struct binding
*bindings
[NR_CTXS
] = { NULL
, };
88 #define KEY_IS_CHAR -255
90 static int initializing
= 1;
91 static char *filename
;
93 static void win_activate_next(void)
95 if (ui_curses_view
== TREE_VIEW
)
96 pl_toggle_active_window();
99 static void win_bottom(void)
101 enum context c
= view_to_context
[ui_curses_view
];
111 if (window_goto_bottom(play_queue_win
))
112 play_queue_changed
= 1;
116 if (window_goto_bottom(browser_win
))
120 if (window_goto_bottom(filters_win
))
126 static void win_down(void)
128 enum context c
= view_to_context
[ui_curses_view
];
138 if (window_move(play_queue_win
, 1))
139 play_queue_changed
= 1;
143 if (window_move(browser_win
, 1))
147 if (window_move(filters_win
, 1))
153 static void win_page_down(void)
155 enum context c
= view_to_context
[ui_curses_view
];
165 if (window_page_down(play_queue_win
))
166 play_queue_changed
= 1;
170 if (window_page_down(browser_win
))
174 if (window_page_down(filters_win
))
180 static void win_page_up(void)
182 enum context c
= view_to_context
[ui_curses_view
];
192 if (window_page_up(play_queue_win
))
193 play_queue_changed
= 1;
197 if (window_page_up(browser_win
))
201 if (window_page_up(filters_win
))
207 static void win_top(void)
209 enum context c
= view_to_context
[ui_curses_view
];
219 if (window_goto_top(play_queue_win
))
220 play_queue_changed
= 1;
224 if (window_goto_top(browser_win
))
228 if (window_goto_top(filters_win
))
234 static void win_up(void)
236 enum context c
= view_to_context
[ui_curses_view
];
246 if (window_move(play_queue_win
, -1))
247 play_queue_changed
= 1;
251 if (window_move(browser_win
, -1))
255 if (window_move(filters_win
, -1))
261 static void play_selected(void)
263 struct track_info
*info
;
265 info
= pl_set_selected();
267 player_play_file(info
->filename
);
268 track_info_unref(info
);
272 static int queue_append_cb(void *data
, struct track_info
*ti
)
274 __play_queue_append(ti
);
278 static int queue_prepend_cb(void *data
, struct track_info
*ti
)
280 __play_queue_prepend(ti
);
284 static void queue_append(void)
287 pl_for_each_selected(queue_append_cb
, NULL
, 0);
292 static void queue_prepend(void)
295 pl_for_each_selected(queue_prepend_cb
, NULL
, 1);
300 static void search_next_forward(void)
303 if (!search_next(searchable
, search_str
, search_direction
))
304 ui_curses_search_not_found();
308 static void search_next_backward(void)
311 if (!search_next(searchable
, search_str
, !search_direction
))
312 ui_curses_search_not_found();
317 static const struct function common_functions
[] = {
318 { "help", display_help
},
319 { "next", cmus_next
},
320 { "pause", player_pause
},
321 { "play", player_play
},
322 { "prev", cmus_prev
},
323 { "quit", ui_curses_quit
},
324 { "search_next", search_next_forward
},
325 { "search_prev", search_next_backward
},
326 { "seek_backward", cmus_seek_bwd
},
327 { "seek_forward", cmus_seek_fwd
},
328 { "stop", player_stop
},
329 { "toggle_continue", player_toggle_cont
},
330 { "toggle_play_mode", pl_toggle_play_mode
},
331 { "toggle_playlist_mode", pl_toggle_playlist_mode
},
332 { "toggle_remaining_time", ui_curses_toggle_remaining_time
},
333 { "toggle_repeat", pl_toggle_repeat
},
334 { "view_1", ui_curses_tree_view
},
335 { "view_2", ui_curses_shuffle_view
},
336 { "view_3", ui_curses_sorted_view
},
337 { "view_4", ui_curses_play_queue_view
},
338 { "view_5", ui_curses_browser_view
},
339 { "view_6", ui_curses_filters_view
},
340 { "vol_down", cmus_vol_down
},
341 { "vol_left_down", cmus_vol_left_down
},
342 { "vol_left_up", cmus_vol_left_up
},
343 { "vol_right_down", cmus_vol_right_down
},
344 { "vol_right_up", cmus_vol_right_up
},
345 { "vol_up", cmus_vol_up
},
346 { "win_activate_next", win_activate_next
},
347 { "win_bottom", win_bottom
},
348 { "win_down", win_down
},
349 { "win_page_down", win_page_down
},
350 { "win_page_up", win_page_up
},
351 { "win_top", win_top
},
352 { "win_up", win_up
},
356 static struct function playlist_functions
[] = {
357 { "expand_artist", pl_toggle_expand_artist
},
358 { "play_selected", play_selected
},
359 { "queue_append", queue_append
},
360 { "queue_prepend", queue_prepend
},
361 { "remove", pl_remove_sel
},
362 { "select_current", pl_sel_current
},
363 { "update", cmus_update_playlist
},
367 static const struct function play_queue_functions
[] = {
368 { "remove", play_queue_delete
},
372 static const struct function browser_functions
[] = {
373 { "add", browser_add
},
374 { "cd_parent", browser_cd_parent
},
375 { "enter", browser_enter
},
376 { "queue_append", browser_queue_append
},
377 { "queue_prepend", browser_queue_prepend
},
378 { "reload", browser_reload
},
379 { "remove", browser_delete
},
380 { "toggle_show_hidden", browser_toggle_show_hidden
},
384 static const struct function filters_functions
[] = {
385 { "activate", filters_activate
},
386 { "delete_filter", filters_delete_filter
},
387 { "toggle_filter", filters_toggle_filter
},
392 static const struct function
*all_functions
[NR_CTXS
] = {
395 play_queue_functions
,
401 static const struct key keys
[] = {
402 { "!", KEY_IS_CHAR
, 33 },
403 { "#", KEY_IS_CHAR
, 35 },
404 { "$", KEY_IS_CHAR
, 36 },
405 { "%", KEY_IS_CHAR
, 37 },
406 { "&", KEY_IS_CHAR
, 38 },
407 { "'", KEY_IS_CHAR
, 39 },
408 { "(", KEY_IS_CHAR
, 40 },
409 { ")", KEY_IS_CHAR
, 41 },
410 { "*", KEY_IS_CHAR
, 42 },
411 { "+", KEY_IS_CHAR
, 43 },
412 { ",", KEY_IS_CHAR
, 44 },
413 { "-", KEY_IS_CHAR
, 45 },
414 { ".", KEY_IS_CHAR
, 46 },
415 { "0", KEY_IS_CHAR
, 48 },
416 { "1", KEY_IS_CHAR
, 49 },
417 { "2", KEY_IS_CHAR
, 50 },
418 { "3", KEY_IS_CHAR
, 51 },
419 { "4", KEY_IS_CHAR
, 52 },
420 { "5", KEY_IS_CHAR
, 53 },
421 { "6", KEY_IS_CHAR
, 54 },
422 { "7", KEY_IS_CHAR
, 55 },
423 { "8", KEY_IS_CHAR
, 56 },
424 { "9", KEY_IS_CHAR
, 57 },
425 { ";", KEY_IS_CHAR
, 59 },
426 { "<", KEY_IS_CHAR
, 60 },
427 { "=", KEY_IS_CHAR
, 61 },
428 { ">", KEY_IS_CHAR
, 62 },
429 { "@", KEY_IS_CHAR
, 64 },
430 { "A", KEY_IS_CHAR
, 65 },
431 { "B", KEY_IS_CHAR
, 66 },
432 { "C", KEY_IS_CHAR
, 67 },
433 { "D", KEY_IS_CHAR
, 68 },
434 { "E", KEY_IS_CHAR
, 69 },
435 { "F", KEY_IS_CHAR
, 70 },
436 { "F1", KEY_F(1), 0 },
437 { "F10", KEY_F(10), 0 },
438 { "F11", KEY_F(11), 0 },
439 { "F12", KEY_F(12), 0 },
440 { "F2", KEY_F(2), 0 },
441 { "F3", KEY_F(3), 0 },
442 { "F4", KEY_F(4), 0 },
443 { "F5", KEY_F(5), 0 },
444 { "F6", KEY_F(6), 0 },
445 { "F7", KEY_F(7), 0 },
446 { "F8", KEY_F(8), 0 },
447 { "F9", KEY_F(9), 0 },
448 { "G", KEY_IS_CHAR
, 71 },
449 { "H", KEY_IS_CHAR
, 72 },
450 { "I", KEY_IS_CHAR
, 73 },
451 { "J", KEY_IS_CHAR
, 74 },
452 { "K", KEY_IS_CHAR
, 75 },
453 { "KP_center", KEY_B2
, 0 },
454 { "KP_lower_left", KEY_C1
, 0 },
455 { "KP_lower_right", KEY_C3
, 0 },
456 { "KP_upper_left", KEY_A1
, 0 },
457 { "KP_upper_right", KEY_A3
, 0 },
458 { "L", KEY_IS_CHAR
, 76 },
459 { "M", KEY_IS_CHAR
, 77 },
460 { "M- ", KEY_IS_CHAR
, 160 },
461 { "M-!", KEY_IS_CHAR
, 161 },
462 { "M-#", KEY_IS_CHAR
, 163 },
463 { "M-$", KEY_IS_CHAR
, 164 },
464 { "M-%", KEY_IS_CHAR
, 165 },
465 { "M-&", KEY_IS_CHAR
, 166 },
466 { "M-'", KEY_IS_CHAR
, 167 },
467 { "M-(", KEY_IS_CHAR
, 168 },
468 { "M-)", KEY_IS_CHAR
, 169 },
469 { "M-*", KEY_IS_CHAR
, 170 },
470 { "M-+", KEY_IS_CHAR
, 171 },
471 { "M-,", KEY_IS_CHAR
, 172 },
472 { "M--", KEY_IS_CHAR
, 173 },
473 { "M-.", KEY_IS_CHAR
, 174 },
474 { "M-/", KEY_IS_CHAR
, 175 },
475 { "M-0", KEY_IS_CHAR
, 176 },
476 { "M-1", KEY_IS_CHAR
, 177 },
477 { "M-2", KEY_IS_CHAR
, 178 },
478 { "M-3", KEY_IS_CHAR
, 179 },
479 { "M-4", KEY_IS_CHAR
, 180 },
480 { "M-5", KEY_IS_CHAR
, 181 },
481 { "M-6", KEY_IS_CHAR
, 182 },
482 { "M-7", KEY_IS_CHAR
, 183 },
483 { "M-8", KEY_IS_CHAR
, 184 },
484 { "M-9", KEY_IS_CHAR
, 185 },
485 { "M-:", KEY_IS_CHAR
, 186 },
486 { "M-;", KEY_IS_CHAR
, 187 },
487 { "M-<", KEY_IS_CHAR
, 188 },
488 { "M-=", KEY_IS_CHAR
, 189 },
489 { "M->", KEY_IS_CHAR
, 190 },
490 { "M-?", KEY_IS_CHAR
, 191 },
491 { "M-@", KEY_IS_CHAR
, 192 },
492 { "M-A", KEY_IS_CHAR
, 193 },
493 { "M-B", KEY_IS_CHAR
, 194 },
494 { "M-C", KEY_IS_CHAR
, 195 },
495 { "M-D", KEY_IS_CHAR
, 196 },
496 { "M-E", KEY_IS_CHAR
, 197 },
497 { "M-F", KEY_IS_CHAR
, 198 },
498 { "M-G", KEY_IS_CHAR
, 199 },
499 { "M-H", KEY_IS_CHAR
, 200 },
500 { "M-I", KEY_IS_CHAR
, 201 },
501 { "M-J", KEY_IS_CHAR
, 202 },
502 { "M-K", KEY_IS_CHAR
, 203 },
503 { "M-L", KEY_IS_CHAR
, 204 },
504 { "M-M", KEY_IS_CHAR
, 205 },
505 { "M-N", KEY_IS_CHAR
, 206 },
506 { "M-O", KEY_IS_CHAR
, 207 },
507 { "M-P", KEY_IS_CHAR
, 208 },
508 { "M-Q", KEY_IS_CHAR
, 209 },
509 { "M-R", KEY_IS_CHAR
, 210 },
510 { "M-S", KEY_IS_CHAR
, 211 },
511 { "M-T", KEY_IS_CHAR
, 212 },
512 { "M-U", KEY_IS_CHAR
, 213 },
513 { "M-V", KEY_IS_CHAR
, 214 },
514 { "M-W", KEY_IS_CHAR
, 215 },
515 { "M-X", KEY_IS_CHAR
, 216 },
516 { "M-Y", KEY_IS_CHAR
, 217 },
517 { "M-Z", KEY_IS_CHAR
, 218 },
518 { "M-[", KEY_IS_CHAR
, 219 },
519 { "M-\"", KEY_IS_CHAR
, 162 },
520 { "M-\\", KEY_IS_CHAR
, 220 },
521 { "M-]", KEY_IS_CHAR
, 221 },
522 { "M-^", KEY_IS_CHAR
, 222 },
523 { "M-^?", KEY_IS_CHAR
, 255 },
524 { "M-^@", KEY_IS_CHAR
, 128 },
525 { "M-^A", KEY_IS_CHAR
, 129 },
526 { "M-^B", KEY_IS_CHAR
, 130 },
527 { "M-^C", KEY_IS_CHAR
, 131 },
528 { "M-^D", KEY_IS_CHAR
, 132 },
529 { "M-^E", KEY_IS_CHAR
, 133 },
530 { "M-^F", KEY_IS_CHAR
, 134 },
531 { "M-^G", KEY_IS_CHAR
, 135 },
532 { "M-^H", KEY_IS_CHAR
, 136 },
533 { "M-^I", KEY_IS_CHAR
, 137 },
534 { "M-^J", KEY_IS_CHAR
, 138 },
535 { "M-^K", KEY_IS_CHAR
, 139 },
536 { "M-^L", KEY_IS_CHAR
, 140 },
537 { "M-^M", KEY_IS_CHAR
, 141 },
538 { "M-^N", KEY_IS_CHAR
, 142 },
539 { "M-^O", KEY_IS_CHAR
, 143 },
540 { "M-^P", KEY_IS_CHAR
, 144 },
541 { "M-^Q", KEY_IS_CHAR
, 145 },
542 { "M-^R", KEY_IS_CHAR
, 146 },
543 { "M-^S", KEY_IS_CHAR
, 147 },
544 { "M-^T", KEY_IS_CHAR
, 148 },
545 { "M-^U", KEY_IS_CHAR
, 149 },
546 { "M-^V", KEY_IS_CHAR
, 150 },
547 { "M-^W", KEY_IS_CHAR
, 151 },
548 { "M-^X", KEY_IS_CHAR
, 152 },
549 { "M-^Y", KEY_IS_CHAR
, 153 },
550 { "M-^Z", KEY_IS_CHAR
, 154 },
551 { "M-^[", KEY_IS_CHAR
, 155 },
552 { "M-^\\", KEY_IS_CHAR
, 156 },
553 { "M-^]", KEY_IS_CHAR
, 157 },
554 { "M-^^", KEY_IS_CHAR
, 158 },
555 { "M-^_", KEY_IS_CHAR
, 159 },
556 { "M-_", KEY_IS_CHAR
, 223 },
557 { "M-`", KEY_IS_CHAR
, 224 },
558 { "M-a", KEY_IS_CHAR
, 225 },
559 { "M-b", KEY_IS_CHAR
, 226 },
560 { "M-c", KEY_IS_CHAR
, 227 },
561 { "M-d", KEY_IS_CHAR
, 228 },
562 { "M-e", KEY_IS_CHAR
, 229 },
563 { "M-f", KEY_IS_CHAR
, 230 },
564 { "M-g", KEY_IS_CHAR
, 231 },
565 { "M-h", KEY_IS_CHAR
, 232 },
566 { "M-i", KEY_IS_CHAR
, 233 },
567 { "M-j", KEY_IS_CHAR
, 234 },
568 { "M-k", KEY_IS_CHAR
, 235 },
569 { "M-l", KEY_IS_CHAR
, 236 },
570 { "M-m", KEY_IS_CHAR
, 237 },
571 { "M-n", KEY_IS_CHAR
, 238 },
572 { "M-o", KEY_IS_CHAR
, 239 },
573 { "M-p", KEY_IS_CHAR
, 240 },
574 { "M-q", KEY_IS_CHAR
, 241 },
575 { "M-r", KEY_IS_CHAR
, 242 },
576 { "M-s", KEY_IS_CHAR
, 243 },
577 { "M-t", KEY_IS_CHAR
, 244 },
578 { "M-u", KEY_IS_CHAR
, 245 },
579 { "M-v", KEY_IS_CHAR
, 246 },
580 { "M-w", KEY_IS_CHAR
, 247 },
581 { "M-x", KEY_IS_CHAR
, 248 },
582 { "M-y", KEY_IS_CHAR
, 249 },
583 { "M-z", KEY_IS_CHAR
, 250 },
584 { "M-{", KEY_IS_CHAR
, 251 },
585 { "M-|", KEY_IS_CHAR
, 252 },
586 { "M-}", KEY_IS_CHAR
, 253 },
587 { "M-~", KEY_IS_CHAR
, 254 },
588 { "N", KEY_IS_CHAR
, 78 },
589 { "O", KEY_IS_CHAR
, 79 },
590 { "P", KEY_IS_CHAR
, 80 },
591 { "Q", KEY_IS_CHAR
, 81 },
592 { "R", KEY_IS_CHAR
, 82 },
593 { "S", KEY_IS_CHAR
, 83 },
594 { "S-begin", KEY_SBEG
, 0 },
595 { "S-cancel", KEY_SCANCEL
, 0 },
596 { "S-command", KEY_SCOMMAND
, 0 },
597 { "S-copy", KEY_SCOPY
, 0 },
598 { "S-create", KEY_SCREATE
, 0 },
599 { "S-del_line", KEY_SDL
, 0 },
600 { "S-delete", KEY_SDC
, 0 },
601 { "S-eol", KEY_SEOL
, 0 },
602 { "S-exit", KEY_SEXIT
, 0 },
603 { "S-find", KEY_SFIND
, 0 },
604 { "S-help", KEY_SHELP
, 0 },
605 { "S-home", KEY_SHOME
, 0 },
606 { "S-insert", KEY_SIC
, 0 },
607 { "S-left", KEY_SLEFT
, 0 },
608 { "S-message", KEY_SMESSAGE
, 0 },
609 { "S-move", KEY_SMOVE
, 0 },
610 { "S-next", KEY_SNEXT
, 0 },
611 { "S-options", KEY_SOPTIONS
, 0 },
612 { "S-previous", KEY_SPREVIOUS
, 0 },
613 { "S-print", KEY_SPRINT
, 0 },
614 { "S-redo", KEY_SREDO
, 0 },
615 { "S-replace", KEY_SREPLACE
, 0 },
616 { "S-resume", KEY_SRSUME
, 0 },
617 { "S-right", KEY_SRIGHT
, 0 },
618 { "S-save", KEY_SSAVE
, 0 },
619 { "S-suspend", KEY_SSUSPEND
, 0 },
620 { "S-undo", KEY_SUNDO
, 0 },
621 { "T", KEY_IS_CHAR
, 84 },
622 { "U", KEY_IS_CHAR
, 85 },
623 { "V", KEY_IS_CHAR
, 86 },
624 { "W", KEY_IS_CHAR
, 87 },
625 { "X", KEY_IS_CHAR
, 88 },
626 { "Y", KEY_IS_CHAR
, 89 },
627 { "Z", KEY_IS_CHAR
, 90 },
628 { "[", KEY_IS_CHAR
, 91 },
629 { "\"", KEY_IS_CHAR
, 34 },
630 { "\\", KEY_IS_CHAR
, 92 },
631 { "]", KEY_IS_CHAR
, 93 },
632 { "^", KEY_IS_CHAR
, 94 },
633 { "^?", KEY_IS_CHAR
, 127 },
634 { "^A", KEY_IS_CHAR
, 1 },
635 { "^B", KEY_IS_CHAR
, 2 },
636 { "^C", KEY_IS_CHAR
, 3 },
637 { "^D", KEY_IS_CHAR
, 4 },
638 { "^E", KEY_IS_CHAR
, 5 },
639 { "^F", KEY_IS_CHAR
, 6 },
640 { "^G", KEY_IS_CHAR
, 7 },
641 { "^H", KEY_IS_CHAR
, 8 },
642 { "^K", KEY_IS_CHAR
, 11 },
643 { "^L", KEY_IS_CHAR
, 12 },
644 { "^M", KEY_IS_CHAR
, 13 },
645 { "^N", KEY_IS_CHAR
, 14 },
646 { "^O", KEY_IS_CHAR
, 15 },
647 { "^P", KEY_IS_CHAR
, 16 },
648 { "^Q", KEY_IS_CHAR
, 17 },
649 { "^R", KEY_IS_CHAR
, 18 },
650 { "^S", KEY_IS_CHAR
, 19 },
651 { "^T", KEY_IS_CHAR
, 20 },
652 { "^U", KEY_IS_CHAR
, 21 },
653 { "^V", KEY_IS_CHAR
, 22 },
654 { "^W", KEY_IS_CHAR
, 23 },
655 { "^X", KEY_IS_CHAR
, 24 },
656 { "^Y", KEY_IS_CHAR
, 25 },
657 { "^Z", KEY_IS_CHAR
, 26 },
658 { "^\\", KEY_IS_CHAR
, 28 },
659 { "^]", KEY_IS_CHAR
, 29 },
660 { "^^", KEY_IS_CHAR
, 30 },
661 { "^_", KEY_IS_CHAR
, 31 },
662 { "_", KEY_IS_CHAR
, 95 },
663 { "`", KEY_IS_CHAR
, 96 },
664 { "a", KEY_IS_CHAR
, 97 },
665 { "b", KEY_IS_CHAR
, 98 },
666 { "back_tab", KEY_BTAB
, 0 },
667 { "backspace", KEY_BACKSPACE
, 0 },
668 { "begin", KEY_BEG
, 0 },
669 { "c", KEY_IS_CHAR
, 99 },
670 { "cancel", KEY_CANCEL
, 0 },
671 { "clear", KEY_CLEAR
, 0 },
672 { "clear_all_tabs", KEY_CATAB
, 0 },
673 { "clear_tab", KEY_CTAB
, 0 },
674 { "close", KEY_CLOSE
, 0 },
675 { "command", KEY_COMMAND
, 0 },
676 { "copy", KEY_COPY
, 0 },
677 { "create", KEY_CREATE
, 0 },
678 { "d", KEY_IS_CHAR
, 100 },
679 { "del_line", KEY_DL
, 0 },
680 { "delete", KEY_DC
, 0 },
681 { "down", KEY_DOWN
, 0 },
682 { "e", KEY_IS_CHAR
, 101 },
683 { "eic", KEY_EIC
, 0 },
684 { "end", KEY_END
, 0 },
685 { "enter", KEY_IS_CHAR
, 10 },
686 { "eol", KEY_EOL
, 0 },
687 { "eos", KEY_EOS
, 0 },
688 { "exit", KEY_EXIT
, 0 },
689 { "f", KEY_IS_CHAR
, 102 },
690 { "find", KEY_FIND
, 0 },
691 { "g", KEY_IS_CHAR
, 103 },
692 { "h", KEY_IS_CHAR
, 104 },
693 { "help", KEY_HELP
, 0 },
694 { "home", KEY_HOME
, 0 },
695 { "i", KEY_IS_CHAR
, 105 },
696 { "ins_line", KEY_IL
, 0 },
697 { "insert", KEY_IC
, 0 },
698 { "j", KEY_IS_CHAR
, 106 },
699 { "k", KEY_IS_CHAR
, 107 },
700 { "l", KEY_IS_CHAR
, 108 },
701 { "left", KEY_LEFT
, 0 },
702 { "lower_left", KEY_LL
, 0 },
703 { "m", KEY_IS_CHAR
, 109 },
704 { "mark", KEY_MARK
, 0 },
705 { "message", KEY_MESSAGE
, 0 },
706 { "move", KEY_MOVE
, 0 },
707 { "n", KEY_IS_CHAR
, 110 },
708 { "next", KEY_NEXT
, 0 },
709 { "o", KEY_IS_CHAR
, 111 },
710 { "open", KEY_OPEN
, 0 },
711 { "options", KEY_OPTIONS
, 0 },
712 { "p", KEY_IS_CHAR
, 112 },
713 { "page_down", KEY_NPAGE
, 0 },
714 { "page_up", KEY_PPAGE
, 0 },
715 { "previous", KEY_PREVIOUS
, 0 },
716 { "print", KEY_PRINT
, 0 },
717 { "q", KEY_IS_CHAR
, 113 },
718 { "r", KEY_IS_CHAR
, 114 },
719 { "redo", KEY_REDO
, 0 },
720 { "reference", KEY_REFERENCE
, 0 },
721 { "refresh", KEY_REFRESH
, 0 },
722 { "replace", KEY_REPLACE
, 0 },
723 { "restart", KEY_RESTART
, 0 },
724 { "resume", KEY_RESUME
, 0 },
725 { "right", KEY_RIGHT
, 0 },
726 { "s", KEY_IS_CHAR
, 115 },
727 { "save", KEY_SAVE
, 0 },
728 { "scroll_b", KEY_SR
, 0 },
729 { "scroll_f", KEY_SF
, 0 },
730 { "select", KEY_SELECT
, 0 },
731 { "send", KEY_SEND
, 0 },
732 { "set_tab", KEY_STAB
, 0 },
733 { "space", KEY_IS_CHAR
, 32 },
734 { "suspend", KEY_SUSPEND
, 0 },
735 { "t", KEY_IS_CHAR
, 116 },
736 { "tab", KEY_IS_CHAR
, 9 },
737 { "u", KEY_IS_CHAR
, 117 },
738 { "undo", KEY_UNDO
, 0 },
740 { "v", KEY_IS_CHAR
, 118 },
741 { "w", KEY_IS_CHAR
, 119 },
742 { "x", KEY_IS_CHAR
, 120 },
743 { "y", KEY_IS_CHAR
, 121 },
744 { "z", KEY_IS_CHAR
, 122 },
745 { "{", KEY_IS_CHAR
, 123 },
746 { "|", KEY_IS_CHAR
, 124 },
747 { "}", KEY_IS_CHAR
, 125 },
748 { "~", KEY_IS_CHAR
, 126 },
753 /* default bindings {{{ */
754 static const struct {
755 enum context context
;
759 { CTX_COMMON
, "F1", "help" },
760 { CTX_COMMON
, "b", "next" },
761 { CTX_COMMON
, "c", "pause" },
762 { CTX_COMMON
, "x", "play" },
763 { CTX_COMMON
, "z", "prev" },
764 { CTX_COMMON
, "Q", "quit" },
765 { CTX_COMMON
, "n", "search_next" },
766 { CTX_COMMON
, "N", "search_prev" },
767 { CTX_COMMON
, "h", "seek_backward" },
768 { CTX_COMMON
, "l", "seek_forward" },
769 { CTX_COMMON
, "left", "seek_backward" },
770 { CTX_COMMON
, "right", "seek_forward" },
771 { CTX_COMMON
, "v", "stop" },
772 { CTX_COMMON
, "C", "toggle_continue" },
773 { CTX_COMMON
, "p", "toggle_play_mode" },
774 { CTX_COMMON
, "m", "toggle_playlist_mode" },
775 { CTX_COMMON
, "t", "toggle_remaining_time" },
776 { CTX_COMMON
, "r", "toggle_repeat" },
777 { CTX_COMMON
, "1", "view_1" },
778 { CTX_COMMON
, "2", "view_2" },
779 { CTX_COMMON
, "3", "view_3" },
780 { CTX_COMMON
, "4", "view_4" },
781 { CTX_COMMON
, "5", "view_5" },
782 { CTX_COMMON
, "6", "view_6" },
783 { CTX_COMMON
, "-", "vol_down" },
784 { CTX_COMMON
, "{", "vol_left_down" },
785 { CTX_COMMON
, "[", "vol_left_up" },
786 { CTX_COMMON
, "}", "vol_right_down" },
787 { CTX_COMMON
, "]", "vol_right_up" },
788 { CTX_COMMON
, "=", "vol_up" },
789 { CTX_COMMON
, "+", "vol_up" },
790 { CTX_COMMON
, "tab", "win_activate_next" },
791 { CTX_COMMON
, "G", "win_bottom" },
792 { CTX_COMMON
, "j", "win_down" },
793 { CTX_COMMON
, "^F", "win_page_down" },
794 { CTX_COMMON
, "^B", "win_page_up" },
795 { CTX_COMMON
, "g", "win_top" },
796 { CTX_COMMON
, "k", "win_up" },
797 { CTX_COMMON
, "end", "win_bottom" },
798 { CTX_COMMON
, "down", "win_down" },
799 { CTX_COMMON
, "page_down", "win_page_down" },
800 { CTX_COMMON
, "page_up", "win_page_up" },
801 { CTX_COMMON
, "home", "win_top" },
802 { CTX_COMMON
, "up", "win_up" },
804 { CTX_PLAYLIST
, "space", "expand_artist" },
805 { CTX_PLAYLIST
, "enter", "play_selected" },
806 { CTX_PLAYLIST
, "e", "queue_append" },
807 { CTX_PLAYLIST
, "E", "queue_prepend" },
808 { CTX_PLAYLIST
, "D", "remove" },
809 { CTX_PLAYLIST
, "delete", "remove" },
810 { CTX_PLAYLIST
, "i", "select_current" },
811 { CTX_PLAYLIST
, "u", "update" },
813 { CTX_PLAY_QUEUE
, "D", "remove" },
814 { CTX_PLAY_QUEUE
, "delete", "remove" },
816 { CTX_BROWSER
, "a", "add" },
817 { CTX_BROWSER
, "backspace", "cd_parent" },
818 { CTX_BROWSER
, "enter", "enter" },
819 { CTX_BROWSER
, "e", "queue_append" },
820 { CTX_BROWSER
, "E", "queue_prepend" },
821 { CTX_BROWSER
, "u", "reload" },
822 { CTX_BROWSER
, "D", "remove" },
823 { CTX_BROWSER
, "delete", "remove" },
824 { CTX_BROWSER
, "i", "toggle_show_hidden" },
826 { CTX_FILTERS
, "enter", "activate" },
827 { CTX_FILTERS
, "D", "delete_filter" },
828 { CTX_FILTERS
, "delete", "delete_filter" },
829 { CTX_FILTERS
, "space", "toggle_filter" },
834 static void set_defaults(void)
838 d_print("setting default keybindings\n");
839 for (i
= 0; defaults
[i
].key
; i
++)
840 key_bind(context_names
[defaults
[i
].context
], defaults
[i
].key
, defaults
[i
].func
);
845 * TODO: tables are sorted, do binary search
848 static int find_context(const char *name
)
852 for (i
= 0; i
< NR_CTXS
; i
++) {
853 if (strcmp(name
, context_names
[i
]) == 0)
857 fprintf(stderr
, "invalid context '%s'\n", name
);
859 ui_curses_display_error_msg("invalid context '%s'", name
);
864 static const struct key
*find_key(const char *name
)
868 for (i
= 0; keys
[i
].name
; i
++) {
869 if (strcmp(name
, keys
[i
].name
) == 0)
873 fprintf(stderr
, "invalid key '%s'\n", name
);
875 ui_curses_display_error_msg("invalid key '%s'", name
);
880 static const struct function
*find_function(const char *name
, enum context c
)
882 const struct function
*functions
= all_functions
[c
];
885 for (i
= 0; functions
[i
].name
; i
++) {
886 if (strcmp(name
, functions
[i
].name
) == 0)
887 return &functions
[i
];
890 fprintf(stderr
, "function '%s' not found in context %s\n", name
, context_names
[c
]);
892 ui_curses_display_error_msg("function '%s' not in context %s", name
, context_names
[c
]);
897 static struct binding
*find_binding(enum context c
, const struct key
*k
)
899 struct binding
*b
= bindings
[c
];
909 int key_bind(const char *context
, const char *key
, const char *func
)
913 const struct function
*f
;
916 c
= find_context(context
);
924 f
= find_function(func
, c
);
928 /* check if already bound */
929 b
= find_binding(c
, k
);
932 if (context
!= CTX_COMMON
) {
933 /* always search CTX_COMMON because same key can't be bound
934 * in CTX_COMMON _and_ any other context at the same time
936 b
= find_binding(CTX_COMMON
, k
);
941 b
= xnew(struct binding
, 1);
945 b
->next
= bindings
[c
];
948 d_print("bound %s in %s to %s\n", key
, context
, func
);
952 fprintf(stderr
, "key %s already bound in context %s\n", key
, context
);
954 ui_curses_display_error_msg("key %s already bound in context %s", key
, context
);
959 int key_unbind(const char *context
, const char *key
)
963 struct binding
*b
, *prev
;
965 c
= find_context(context
);
978 prev
->next
= b
->next
;
980 bindings
[c
] = b
->next
;
988 ui_curses_display_error_msg("key %s not bound in context %s", key
, context
);
992 static char *find_space(char *str
)
1002 static int parse_words(char *s
, char **words
, int nr
)
1025 static void handle_line(void *data
, const char *line
)
1029 if (parse_words((char *)line
, words
, 3))
1032 key_bind(words
[0], words
[1], words
[2]);
1036 static int load_keys(void)
1038 filename
= xstrjoin(cmus_config_dir
, "/keybindings");
1039 if (file_load(filename
, handle_line
, NULL
) && errno
!= ENOENT
) {
1040 fprintf(stderr
, "error: opening file %s: %s\n", filename
, strerror(errno
));
1053 /* set default keys only if no bingings */
1054 for (i
= 0; i
< NR_CTXS
; i
++) {
1056 d_print("user defined keys\n");
1066 void keys_exit(void)
1071 f
= fopen(filename
, "w");
1073 fprintf(stderr
, "error: creating %s: %s\n", filename
, strerror(errno
));
1076 for (i
= 0; i
< NR_CTXS
; i
++) {
1077 struct binding
*b
= bindings
[i
];
1078 const char *name
= context_names
[i
];
1081 fprintf(f
, "%s %-25s %s\n", name
, b
->key
->name
, b
->func
->name
);
1088 static int handle_key(const struct binding
*b
, const struct key
*k
)
1100 static const struct key
*ch_to_key(uchar ch
)
1104 for (i
= 0; keys
[i
].name
; i
++) {
1105 if (keys
[i
].key
== KEY_IS_CHAR
&& keys
[i
].ch
== ch
)
1111 static const struct key
*keycode_to_key(int key
)
1115 for (i
= 0; keys
[i
].name
; i
++) {
1116 if (keys
[i
].key
!= KEY_IS_CHAR
&& keys
[i
].key
== key
)
1122 void normal_mode_ch(uchar ch
)
1125 const struct key
*k
;
1127 /* you can't redefine these keys */
1130 ui_curses_command_mode();
1133 ui_curses_search_mode();
1136 ui_curses_search_backward_mode();
1140 c
= view_to_context
[ui_curses_view
];
1147 /* view-specific ch */
1148 if (handle_key(bindings
[c
], k
)) {
1149 ui_curses_update_view();
1154 if (!handle_key(bindings
[0], k
))
1155 d_print("key %s not bound in context %s or common\n", k
->name
, context_names
[c
]);
1158 void normal_mode_key(int key
)
1160 enum context c
= view_to_context
[ui_curses_view
];
1161 const struct key
*k
= keycode_to_key(key
);
1167 /* view-specific key */
1168 if (handle_key(bindings
[c
], k
)) {
1169 ui_curses_update_view();
1174 if (!handle_key(bindings
[0], k
))
1175 d_print("key %s not bound in context %s or common\n", k
->name
, context_names
[c
]);