1 /*
2 * Calcurse - text-based organizer
3 *
4 * Copyright (c) 2004-2020 calcurse Development Team <misc@calcurse.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above
12 * copyright notice, this list of conditions and the
13 * following disclaimer.
14 *
15 * - Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the
17 * following disclaimer in the documentation and/or other
18 * materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * Send your feedback or comments to : misc@calcurse.org
33 * Calcurse home page : http://calcurse.org
34 *
35 */
36
37 #include <string.h>
38 #include <math.h>
39
40 #include "calcurse.h"
41
42 #define MAXKEYVAL KEY_MAX /* ncurses defines KEY_MAX as maximum key value */
43
44 struct keydef_s {
45 const char *label;
46 const char *binding;
47 const char *sb_label;
48 };
49
50 static llist_t keys[NBKEYS];
51 static enum key actions[MAXKEYVAL];
52
53 struct key_ext {
54 int ch;
55 enum key action;
56 };
57
58 llist_t actions_ext;
59
60 #define gettext_noop(s) s
61 static struct keydef_s keydef[NBKEYS] = {
62 { "generic-cancel", "ESC", gettext_noop("Cancel") },
63 { "generic-select", "SPC", gettext_noop("Select") },
64 { "generic-credits", "@", gettext_noop("Credits") },
65 { "generic-help", "?", gettext_noop("Help") },
66 { "generic-quit", "q Q", gettext_noop("Quit") },
67 { "generic-save", "s S ^S", gettext_noop("Save") },
68 { "generic-reload", "R", gettext_noop("Reload") },
69 { "generic-copy", "c", gettext_noop("Copy") },
70 { "generic-paste", "p ^V", gettext_noop("Paste") },
71 { "generic-change-view", "TAB", gettext_noop("Chg Win") },
72 { "generic-import", "i I", gettext_noop("Import") },
73 { "generic-export", "x X", gettext_noop("Export") },
74 { "generic-goto", "g G", gettext_noop("Go to") },
75 { "generic-other-cmd", "o O", gettext_noop("OtherCmd") },
76 { "generic-config-menu", "C", gettext_noop("Config") },
77 { "generic-redraw", "^R", gettext_noop("Redraw") },
78 { "generic-add-appt", "^A", gettext_noop("Add Appt") },
79 { "generic-add-todo", "^T", gettext_noop("Add Todo") },
80 { "generic-prev-day", "T ^H", gettext_noop("-1 Day") },
81 { "generic-next-day", "t ^L", gettext_noop("+1 Day") },
82 { "generic-prev-week", "W ^K", gettext_noop("-1 Week") },
83 { "generic-next-week", "w", gettext_noop("+1 Week") },
84 { "generic-prev-month", "M", gettext_noop("-1 Month") },
85 { "generic-next-month", "m", gettext_noop("+1 Month") },
86 { "generic-prev-year", "Y", gettext_noop("-1 Year") },
87 { "generic-next-year", "y", gettext_noop("+1 Year") },
88 { "generic-scroll-down", "^N", gettext_noop("Nxt View") },
89 { "generic-scroll-up", "^P", gettext_noop("Prv View") },
90 { "generic-goto-today", "^G", gettext_noop("Today") },
91 { "generic-command", ":", gettext_noop("Command") },
92
93 { "move-right", "l L RGT", gettext_noop("Right") },
94 { "move-left", "h H LFT", gettext_noop("Left") },
95 { "move-down", "j J DWN", gettext_noop("Down") },
96 { "move-up", "k K UP", gettext_noop("Up") },
97 { "start-of-week", "0", gettext_noop("beg Week") },
98 { "end-of-week", "$", gettext_noop("end Week") },
99 { "add-item", "a A", gettext_noop("Add Item") },
100 { "del-item", "d D", gettext_noop("Del Item") },
101 { "edit-item", "e E", gettext_noop("Edit Itm") },
102 { "view-item", "v V RET", gettext_noop("View") },
103 { "pipe-item", "|", gettext_noop("Pipe") },
104 { "flag-item", "!", gettext_noop("Flag Itm") },
105 { "repeat", "r", gettext_noop("Repeat") },
106 { "edit-note", "n N", gettext_noop("EditNote") },
107 { "view-note", ">", gettext_noop("ViewNote") },
108 { "raise-priority", "+", gettext_noop("Prio.+") },
109 { "lower-priority", "-", gettext_noop("Prio.-") }
110 };
111
112 /*
113 * Table of cached keynames indexed by key codes.
114 */
115 static char *keynames[KEY_MAX];
116
dump_intro(FILE * fd)117 static void dump_intro(FILE * fd)
118 {
119 const char *intro =
120 _("#\n"
121 "# Calcurse keys configuration file\n#\n"
122 "# In this file the keybindings used by Calcurse are defined.\n"
123 "# It is generated automatically by Calcurse and is maintained\n"
124 "# via the key configuration menu of the interactive user\n"
125 "# interface. It should not be edited directly.\n");
126
127 fprintf(fd, "%s\n", intro);
128 }
129
keys_init(void)130 void keys_init(void)
131 {
132 int i;
133 const char *cp;
134
135 for (i = 0; i < MAXKEYVAL; i++)
136 actions[i] = KEY_UNDEF;
137 LLIST_INIT(&actions_ext);
138 for (i = 0; i < NBKEYS; i++)
139 LLIST_INIT(&keys[i]);
140
141 /* Initialization of the keynames table. */
142 for (i = 0; i < KEY_MAX; i++)
143 keynames[i] = "";
144
145 /* Insertion of ncurses names in the ASCII range ... */
146 for (i = 1; i < 128; i++)
147 if ((cp = keyname(i)))
148 keynames[i] = mem_strdup(cp);
149 /* ... and for the ncurses escape keys (pseudokeys). */
150 for (i = KEY_MIN; i < KEY_MAX; i++)
151 if ((cp = keyname(i)))
152 keynames[i] = mem_strdup(cp);
153
154 /* Replace some with calcurse short forms. */
155 keynames[TAB] = "TAB";
156 keynames[RETURN] = "RET";
157 keynames[ESCAPE] = "ESC";
158 keynames[SPACE] = "SPC";
159 keynames[KEY_UP] = "UP";
160 keynames[KEY_DOWN] = "DWN";
161 keynames[KEY_LEFT] = "LFT";
162 keynames[KEY_RIGHT] = "RGT";
163 keynames[KEY_HOME] = "HOM";
164 keynames[KEY_END] = "END";
165 keynames[KEY_NPAGE] = "PgD";
166 keynames[KEY_PPAGE] = "PgU";
167 keynames[KEY_IC] = "INS";
168 keynames[KEY_DC] = "DEL";
169 keynames[KEY_F(1)] = "F1";
170 keynames[KEY_F(2)] = "F2";
171 keynames[KEY_F(3)] = "F3";
172 keynames[KEY_F(4)] = "F4";
173 keynames[KEY_F(5)] = "F5";
174 keynames[KEY_F(6)] = "F6";
175 keynames[KEY_F(7)] = "F7";
176 keynames[KEY_F(8)] = "F8";
177 keynames[KEY_F(9)] = "F9";
178 keynames[KEY_F(10)] = "F10";
179 keynames[KEY_F(11)] = "F11";
180 keynames[KEY_F(12)] = "F12";
181 }
182
key_free(char * s)183 static void key_free(char *s)
184 {
185 mem_free(s);
186 }
187
keys_free(void)188 void keys_free(void)
189 {
190 int i;
191
192 for (i = 0; i < NBKEYS; i++) {
193 LLIST_FREE_INNER(&keys[i], key_free);
194 LLIST_FREE(&keys[i]);
195 }
196 }
197
keys_dump_defaults(char * file)198 void keys_dump_defaults(char *file)
199 {
200 FILE *fd;
201 int i;
202
203 fd = fopen(file, "w");
204 EXIT_IF(fd == NULL,
205 _("FATAL ERROR: could not create default keys file."));
206
207 dump_intro(fd);
208 for (i = 0; i < NBKEYS; i++)
209 fprintf(fd, "%s %s\n", keydef[i].label,
210 keydef[i].binding);
211 file_close(fd, __FILE_POS__);
212 }
213
keys_get_label(enum key key)214 const char *keys_get_label(enum key key)
215 {
216 EXIT_IF(key < 0
217 || key > NBKEYS,
218 _("FATAL ERROR: key value out of bounds"));
219
220 return keydef[key].label;
221 }
222
key_ext_hasch(struct key_ext * k,void * cbdata)223 static int key_ext_hasch(struct key_ext *k, void *cbdata)
224 {
225 return (k->ch == *((int *)cbdata));
226 }
227
keys_get_action(int pressed)228 enum key keys_get_action(int pressed)
229 {
230 if (pressed < 0) {
231 return -1;
232 } else if (pressed > MAXKEYVAL) {
233 llist_item_t *i = LLIST_FIND_FIRST(&actions_ext, &pressed,
234 key_ext_hasch);
235 if (!i)
236 return KEY_UNDEF;
237
238 struct key_ext *k = LLIST_GET_DATA(i);
239 return k->action;
240 } else {
241 return actions[pressed];
242 }
243 }
244
keys_wgetch(WINDOW * win)245 int keys_wgetch(WINDOW *win)
246 {
247 int ch, i;
248 char buf[UTF8_MAXLEN];
249
250 ch = wgetch(win);
251 if (ch == ERR)
252 return ch;
253
254 /* Handle curses pseudo characters. */
255 if (ch >= KEY_MIN)
256 return ch;
257
258 /* Handle 1-byte UTF-8 characters. */
259 if (UTF8_LENGTH(ch) == 1)
260 return ch;
261
262 /*
263 * Map multibyte UTF-8 characters to code point values
264 * and add KEY_MAX to avoid the curses range.
265 */
266 buf[0] = ch;
267 for (i = 1; i < UTF8_LENGTH(buf[0]); i++)
268 buf[i] = wgetch(win);
269 return utf8_decode(buf) + KEY_MAX;
270 }
271
keys_wait_for_any_key(WINDOW * win)272 void keys_wait_for_any_key(WINDOW *win)
273 {
274 keys_wgetch(win);
275 }
276
keys_get(WINDOW * win,int * count,int * reg)277 enum key keys_get(WINDOW *win, int *count, int *reg)
278 {
279 int ch = '0';
280
281 if (count && reg) {
282 *count = 0;
283 *reg = 0;
284 do {
285 *count = *count * 10 + ch - '0';
286 ch = keys_wgetch(win);
287 }
288 while ((ch == '0' && *count > 0)
289 || (ch >= '1' && ch <= '9'));
290
291 if (*count == 0)
292 *count = 1;
293
294 if (ch == '"') {
295 ch = keys_wgetch(win);
296 if (ch >= '1' && ch <= '9') {
297 *reg = ch - '1' + 1;
298 } else if (ch >= 'a' && ch <= 'z') {
299 *reg = ch - 'a' + 10;
300 }
301 ch = keys_wgetch(win);
302 }
303 } else {
304 ch = keys_wgetch(win);
305 }
306
307 switch (ch) {
308 case KEY_RESIZE:
309 return KEY_RESIZE;
310 default:
311 return keys_get_action(ch);
312 }
313 }
314
add_key_str(enum key action,int key)315 static void add_key_str(enum key action, int key)
316 {
317 if (action > NBKEYS)
318 return;
319
320 LLIST_ADD(&keys[action], keys_int2str(key));
321 }
322
keys_assign_binding(int key,enum key action)323 int keys_assign_binding(int key, enum key action)
324 {
325 if (key < 0)
326 return 1;
327 if (key > KEY_MAX) {
328 llist_item_t *i = LLIST_FIND_FIRST(&actions_ext, &key, key_ext_hasch);
329 if (i)
330 return 1;
331 struct key_ext *k = mem_malloc(sizeof(struct key_ext));
332 k->ch = key;
333 k->action = action;
334 LLIST_ADD(&actions_ext, k);
335 } else {
336 if (actions[key] != KEY_UNDEF)
337 return 1;
338 actions[key] = action;
339 }
340 add_key_str(action, key);
341 return 0;
342 }
343
del_key_str(enum key action,int key)344 static void del_key_str(enum key action, int key)
345 {
346 llist_item_t *i;
347 char *oldstr = keys_int2str(key);;
348
349 if (action > NBKEYS)
350 return;
351
352 LLIST_FOREACH(&keys[action], i) {
353 if (strcmp(LLIST_GET_DATA(i), oldstr) == 0) {
354 LLIST_REMOVE(&keys[action], i);
355 goto cleanup;
356 }
357 }
358
359 cleanup:
360 mem_free(oldstr);
361 }
362
keys_remove_binding(int key,enum key action)363 void keys_remove_binding(int key, enum key action)
364 {
365 if (key < 0)
366 return;
367
368 if (key <= MAXKEYVAL) {
369 actions[key] = KEY_UNDEF;
370 } else {
371 llist_item_t *i = LLIST_FIND_FIRST(&actions_ext, &key,
372 key_ext_hasch);
373 if (i) {
374 struct key_ext *k = LLIST_GET_DATA(i);
375 LLIST_REMOVE(&actions_ext, i);
376 mem_free(k);
377 }
378 }
379
380 del_key_str(action, key);
381 }
382
keys_str2int(const char * key)383 int keys_str2int(const char *key)
384 {
385 if (!key)
386 return -1;
387
388 /* For backwards compatibility. */
389 if (strcmp(key, "^J") == 0)
390 return RETURN;
391 else if (strcmp(key, "KEY_HOME") == 0)
392 return KEY_HOME;
393 else if (strcmp(key, "KEY_END") == 0)
394 return KEY_END;
395
396
397 /* Lookup in the keynames table. */
398 for (int i = 1; i < 128; i++)
399 if (strcmp(key, keynames[i]) == 0)
400 return i;
401 for (int i = KEY_MIN; i < KEY_MAX; i++)
402 if (strcmp(key, keynames[i]) == 0)
403 return i;
404
405 /* UTF-8 multibyte keys. */
406 return utf8_decode(key) + KEY_MAX;
407 }
408
keys_int2str(int key)409 char *keys_int2str(int key)
410 {
411 char *res;
412
413 if (key < KEY_MAX) {
414 if (strcmp(keynames[key], "") == 0)
415 return NULL;
416 else
417 return mem_strdup(keynames[key]);
418 } else {
419 asprintf(&res, "%s", utf8_encode(key - KEY_MAX));
420 return res;
421 }
422 }
423
keys_action_count_keys(enum key action)424 int keys_action_count_keys(enum key action)
425 {
426 llist_item_t *i;
427 int n = 0;
428
429 LLIST_FOREACH(&keys[action], i)
430 n++;
431
432 return n;
433 }
434
keys_action_firstkey(enum key action)435 const char *keys_action_firstkey(enum key action)
436 {
437 const char *s = LLIST_GET_DATA(LLIST_FIRST(&keys[action]));
438 return (s != NULL) ? s : "XXX";
439 }
440
keys_action_nkey(enum key action,int keynum)441 const char *keys_action_nkey(enum key action, int keynum)
442 {
443 return LLIST_GET_DATA(LLIST_NTH(&keys[action], keynum));
444 }
445
keys_action_allkeys(enum key action)446 char *keys_action_allkeys(enum key action)
447 {
448 llist_item_t *i;
449 static char keystr[BUFSIZ];
450 int keystrlen = 0;
451 int entrylen;
452
453 if (!LLIST_FIRST(&keys[action]))
454 return NULL;
455
456 keystr[0] = '\0';
457 LLIST_FOREACH(&keys[action], i) {
458 entrylen = strlen(LLIST_GET_DATA(i)) + 1;
459 if (keystrlen + entrylen >= BUFSIZ)
460 break;
461 memcpy(keystr + keystrlen, LLIST_GET_DATA(i), entrylen - 1);
462 keystr[keystrlen + entrylen - 1] = ' ';
463 keystrlen += entrylen;
464 }
465
466 keystr[keystrlen] = '\0';
467 return keystr;
468 }
469
470 /* Need this to display keys properly inside status bar. */
keys_format_label(char ** s,char * key,int width)471 static unsigned keys_format_label(char **s, char *key, int width)
472 {
473 *s = mem_strdup(key);
474 utf8_chop(*s, width);
475 return utf8_strwidth(*s);
476 }
477
478 void
keys_display_bindings_bar(WINDOW * win,int * bindings,int count,int page_base,int page_size)479 keys_display_bindings_bar(WINDOW * win, int *bindings, int count,
480 int page_base, int page_size)
481 {
482 page_size = MIN(page_size, count - page_base);
483
484 /* Padding between two key bindings. */
485 const int padding =
486 (col * 2) / page_size - (KEYS_KEYLEN + KEYS_LABELEN + 1);
487 /* Total length of a key binding (including padding). */
488 const int cmd_len = KEYS_KEYLEN + KEYS_LABELEN + 1 + padding;
489
490 int i;
491
492 wins_erase_status_bar();
493 for (i = 0; i < page_size && page_base + i < count; i++) {
494 /* Location of key and label. */
495 const int key_pos_x = (i / 2) * cmd_len;
496 const int key_pos_y = i % 2;
497 const int label_pos_x = key_pos_x + KEYS_KEYLEN + 1;
498 const int label_pos_y = key_pos_y;
499
500 char key[UTF8_MAXLEN + 1], *fmtkey;
501 unsigned dpywidth, shift_x;
502
503 int binding_key;
504
505 if (i < page_size - 1 || page_base + i == count - 1)
506 binding_key = bindings[page_base + i];
507 else
508 binding_key = KEY_GENERIC_OTHER_CMD;
509
510 const char *label;
511
512 if (binding_key < NBKEYS) {
513 strncpy(key, keys_action_firstkey(binding_key), UTF8_MAXLEN);
514 key[UTF8_MAXLEN] = '\0';
515 label = gettext(keydef[binding_key].sb_label);
516 } else {
517 switch (binding_key) {
518 case KEY_CONFIGMENU_GENERAL:
519 strcpy(key, "g");
520 label = _("General");
521 break;
522 case KEY_CONFIGMENU_LAYOUT:
523 strcpy(key, "l");
524 label = _("Layout");
525 break;
526 case KEY_CONFIGMENU_SIDEBAR:
527 strcpy(key, "s");
528 label = _("Sidebar");
529 break;
530 case KEY_CONFIGMENU_COLOR:
531 strcpy(key, "c");
532 label = _("Color");
533 break;
534 case KEY_CONFIGMENU_NOTIFY:
535 strcpy(key, "n");
536 label = _("Notify");
537 break;
538 case KEY_CONFIGMENU_KEYS:
539 strcpy(key, "k");
540 label = _("Keys");
541 break;
542 default:
543 strcpy(key, "?");
544 label = _("Unknown");
545 break;
546 }
547 }
548
549 custom_apply_attr(win, ATTR_HIGHEST);
550 dpywidth = keys_format_label(&fmtkey, key, KEYS_KEYLEN);
551 shift_x = KEYS_KEYLEN - dpywidth;
552 mvwaddstr(win, key_pos_y, key_pos_x + shift_x, fmtkey);
553 mem_free(fmtkey);
554 custom_remove_attr(win, ATTR_HIGHEST);
555 mvwaddstr(win, label_pos_y, label_pos_x, label);
556 }
557 wnoutrefresh(win);
558 }
559
560 /*
561 * Display information about the given key.
562 * (could not add the keys descriptions to keydef variable, because of i18n).
563 */
keys_popup_info(enum key key)564 void keys_popup_info(enum key key)
565 {
566 char *info[NBKEYS];
567 WINDOW *infowin;
568
569 info[KEY_GENERIC_CANCEL] = _("Cancel the ongoing action.");
570 info[KEY_GENERIC_SELECT] = _("Select the highlighted item.");
571 info[KEY_GENERIC_CREDITS] =
572 _("Print general information about calcurse's authors, license, etc.");
573 info[KEY_GENERIC_HELP] =
574 _("Display hints whenever some help screens are available.");
575 info[KEY_GENERIC_QUIT] =
576 _("Exit from the current menu, or quit calcurse.");
577 info[KEY_GENERIC_SAVE] = _("Save calcurse data.");
578 info[KEY_GENERIC_RELOAD] = _("Reload appointments and todo items.");
579 info[KEY_GENERIC_COPY] =
580 _("Copy the item that is currently selected.");
581 info[KEY_GENERIC_PASTE] =
582 _("Paste an item at the current position.");
583 info[KEY_GENERIC_CHANGE_VIEW] =
584 _("Select next panel in calcurse main screen.");
585 info[KEY_GENERIC_IMPORT] = _("Import data from an external file.");
586 info[KEY_GENERIC_EXPORT] = _("Export data to a new file format.");
587 info[KEY_GENERIC_GOTO] = _("Select the day to go to.");
588 info[KEY_GENERIC_OTHER_CMD] =
589 _("Show next possible actions inside status bar.");
590 info[KEY_GENERIC_CONFIG_MENU] = _("Enter the configuration menu.");
591 info[KEY_GENERIC_REDRAW] = _("Redraw calcurse's screen.");
592 info[KEY_GENERIC_ADD_APPT] =
593 _("Add an appointment, whichever panel is currently selected.");
594 info[KEY_GENERIC_ADD_TODO] =
595 _("Add a todo item, whichever panel is currently selected.");
596 info[KEY_GENERIC_PREV_DAY] =
597 _("Move to previous day in calendar, whichever panel is currently "
598 "selected.");
599 info[KEY_GENERIC_NEXT_DAY] =
600 _("Move to next day in calendar, whichever panel is currently selected.");
601 info[KEY_GENERIC_PREV_WEEK] =
602 _("Move to previous week in calendar, whichever panel is currently "
603 "selected");
604 info[KEY_GENERIC_NEXT_WEEK] =
605 _("Move to next week in calendar, whichever panel is currently selected.");
606 info[KEY_GENERIC_PREV_MONTH] =
607 _("Move to previous month in calendar, whichever panel is currently "
608 "selected");
609 info[KEY_GENERIC_NEXT_MONTH] =
610 _("Move to next month in calendar, whichever panel is currently "
611 "selected.");
612 info[KEY_GENERIC_PREV_YEAR] =
613 _("Move to previous year in calendar, whichever panel is currently "
614 "selected");
615 info[KEY_GENERIC_NEXT_YEAR] =
616 _("Move to next year in calendar, whichever panel is currently selected.");
617 info[KEY_GENERIC_SCROLL_DOWN] =
618 _("Scroll window down (e.g. when displaying text inside a popup window).");
619 info[KEY_GENERIC_SCROLL_UP] =
620 _("Scroll window up (e.g. when displaying text inside a popup window).");
621 info[KEY_GENERIC_GOTO_TODAY] =
622 _("Go to today, whichever panel is selected.");
623 info[KEY_GENERIC_CMD] = _("Enter command mode.");
624 info[KEY_MOVE_RIGHT] = _("Move to the right.");
625 info[KEY_MOVE_LEFT] = _("Move to the left.");
626 info[KEY_MOVE_DOWN] = _("Move down.");
627 info[KEY_MOVE_UP] = _("Move up.");
628 info[KEY_START_OF_WEEK] =
629 _("Select the first day of the current week when inside the calendar "
630 "panel.");
631 info[KEY_END_OF_WEEK] =
632 _("Select the last day of the current week when inside the calendar "
633 "panel.");
634 info[KEY_ADD_ITEM] =
635 _("Add an item to the currently selected panel.");
636 info[KEY_DEL_ITEM] = _("Delete the currently selected item.");
637 info[KEY_EDIT_ITEM] = _("Edit the currently seleted item.");
638 info[KEY_VIEW_ITEM] =
639 _("Display the currently selected item inside a popup window.");
640 info[KEY_FLAG_ITEM] =
641 _("Flag the currently selected item as important.");
642 info[KEY_REPEAT_ITEM] = _("Repeat an item");
643 info[KEY_PIPE_ITEM] =
644 _("Pipe the currently selected item to an external program.");
645 info[KEY_EDIT_NOTE] =
646 _("Attach (or edit if one exists) a note to the currently selected item");
647 info[KEY_VIEW_NOTE] =
648 _("View the note attached to the currently selected item.");
649 info[KEY_RAISE_PRIORITY] =
650 _("Raise a task priority inside the todo panel.");
651 info[KEY_LOWER_PRIORITY] =
652 _("Lower a task priority inside the todo panel.");
653
654 if (key > NBKEYS)
655 return;
656
657 #define WINROW 10
658 #define WINCOL (col - 4)
659 infowin =
660 popup(WINROW, WINCOL, (row - WINROW) / 2, (col - WINCOL) / 2,
661 keydef[key].label, info[key], 1);
662 keys_get(infowin, NULL, NULL);
663 delwin(infowin);
664 #undef WINROW
665 #undef WINCOL
666 }
667
keys_save_bindings(FILE * fd)668 void keys_save_bindings(FILE * fd)
669 {
670 int i;
671 char *action;
672
673 EXIT_IF(fd == NULL, _("FATAL ERROR: null file pointer."));
674 dump_intro(fd);
675 for (i = 0; i < NBKEYS; i++) {
676 action = keys_action_allkeys(i);
677 if (action)
678 fprintf(fd, "%s %s\n", keydef[i].label, action);
679 }
680 }
681
keys_check_missing_bindings(void)682 int keys_check_missing_bindings(void)
683 {
684 int i;
685
686 for (i = 0; i < NBKEYS; i++) {
687 if (!LLIST_FIRST(&keys[i]))
688 return 1;
689 }
690 return 0;
691 }
692
keys_fill_missing(void)693 void keys_fill_missing(void)
694 {
695 int i;
696
697 for (i = 0; i < NBKEYS; i++) {
698 if (!LLIST_FIRST(&keys[i])) {
699 char *p, tmpbuf[BUFSIZ];
700
701 strncpy(tmpbuf, keydef[i].binding, BUFSIZ);
702 tmpbuf[BUFSIZ - 1] = '\0';
703 p = tmpbuf;
704 for (;;) {
705 char key_ch[BUFSIZ];
706
707 while (*p == ' ')
708 p++;
709 if (sscanf(p, "%s", key_ch) == 1) {
710 int ch, used;
711
712 ch = keys_str2int(key_ch);
713 used = keys_assign_binding(ch, i);
714 if (used)
715 WARN_MSG(_("When adding default key for \"%s\", "
716 "\"%s\" was already assigned!"),
717 keydef[i].label,
718 key_ch);
719 p += strlen(key_ch);
720 } else {
721 break;
722 }
723 }
724 }
725 }
726 }
727