2 * $Id: dlg_keys.c,v 1.35 2014/01/12 18:21:52 tom Exp $
4 * dlg_keys.c -- runtime binding support for dialog
6 * Copyright 2006-2011,2014 Thomas E. Dickey
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License, version 2.1
10 * as published by the Free Software Foundation.
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 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to
19 * Free Software Foundation, Inc.
20 * 51 Franklin St., Fifth Floor
21 * Boston, MA 02110, USA.
27 #define LIST_BINDINGS struct _list_bindings
31 WINDOW *win; /* window on which widget gets input */
32 const char *name; /* widget name */
33 bool buttons; /* true only for dlg_register_buttons() */
34 DLG_KEYS_BINDING *binding; /* list of bindings */
38 static LIST_BINDINGS *all_bindings;
39 static const DLG_KEYS_BINDING end_keys_binding = END_KEYS_BINDING;
42 * For a given named widget's window, associate a binding table.
45 dlg_register_window(WINDOW *win, const char *name, DLG_KEYS_BINDING * binding)
49 for (p = all_bindings, q = 0; p != 0; q = p, p = p->link) {
50 if (p->win == win && !strcmp(p->name, name)) {
55 /* add built-in bindings at the end of the list (see compare_bindings). */
56 if ((p = dlg_calloc(LIST_BINDINGS, 1)) != 0) {
65 #if defined(HAVE_DLG_TRACE) && defined(HAVE_RC_FILE)
67 * Trace the binding information assigned to this window. For most widgets
68 * there is only one binding table. forms have two, so the trace will be
69 * longer. Since compiled-in bindings are only visible when the widget is
70 * registered, there is no other way to see what bindings are available,
71 * than by running dialog and tracing it.
73 dlg_trace_msg("# dlg_register_window %s\n", name);
74 dlg_dump_window_keys(dialog_state.trace_output, win);
79 * Unlike dlg_lookup_key(), this looks for either widget-builtin or rc-file
80 * definitions, depending on whether 'win' is null.
83 key_is_bound(WINDOW *win, const char *name, int curses_key, int function_key)
87 for (p = all_bindings; p != 0; p = p->link) {
88 if (p->win == win && !dlg_strcmp(p->name, name)) {
90 for (n = 0; p->binding[n].is_function_key >= 0; ++n) {
91 if (p->binding[n].curses_key == curses_key
92 && p->binding[n].is_function_key == function_key) {
102 * Call this function after dlg_register_window(), for the list of button
103 * labels associated with the widget.
105 * Ensure that dlg_lookup_key() will not accidentally translate a key that
106 * we would like to use for a button abbreviation to some other key, e.g.,
107 * h/j/k/l for navigation into a cursor key. Do this by binding the key
110 * See dlg_char_to_button().
113 dlg_register_buttons(WINDOW *win, const char *name, const char **buttons)
122 for (n = 0; buttons[n] != 0; ++n) {
123 int curses_key = dlg_button_to_char(buttons[n]);
125 /* ignore multibyte characters */
126 if (curses_key >= KEY_MIN)
129 /* if it is not bound in the widget, skip it (no conflicts) */
130 if (!key_is_bound(win, name, curses_key, FALSE))
134 /* if it is bound in the rc-file, skip it */
135 if (key_is_bound(0, name, curses_key, FALSE))
139 if ((p = dlg_calloc(LIST_BINDINGS, 1)) != 0) {
140 if ((q = dlg_calloc(DLG_KEYS_BINDING, 2)) != 0) {
141 q[0].is_function_key = 0;
142 q[0].curses_key = curses_key;
143 q[0].dialog_key = curses_key;
144 q[1] = end_keys_binding;
151 /* put these at the beginning, to override the widget's table */
152 p->link = all_bindings;
162 * Remove the bindings for a given window.
165 dlg_unregister_window(WINDOW *win)
167 LIST_BINDINGS *p, *q;
169 for (p = all_bindings, q = 0; p != 0; p = p->link) {
174 all_bindings = p->link;
176 /* the user-defined and buttons-bindings all are length=1 */
177 if (p->binding[1].is_function_key < 0)
180 dlg_unregister_window(win);
188 * Call this after wgetch(), using the same window pointer and passing
191 * If there is no binding associated with the widget, it simply returns
192 * the given curses-key.
195 * win is the window on which the wgetch() was done.
196 * curses_key is the value returned by wgetch().
197 * fkey in/out (on input, it is true if curses_key is a function key,
198 * and on output, it is true if the result is a function key).
201 dlg_lookup_key(WINDOW *win, int curses_key, int *fkey)
207 * Ignore mouse clicks, since they are already encoded properly.
210 if (*fkey != 0 && curses_key == KEY_MOUSE) {
215 * Ignore resize events, since they are already encoded properly.
218 if (*fkey != 0 && curses_key == KEY_RESIZE) {
222 if (*fkey == 0 || curses_key < KEY_MAX) {
223 const char *name = WILDNAME;
225 for (p = all_bindings; p != 0; p = p->link) {
232 for (p = all_bindings; p != 0; p = p->link) {
235 (!strcmp(p->name, name) || !strcmp(p->name, WILDNAME)))) {
236 int function_key = (*fkey != 0);
237 for (q = p->binding; q->is_function_key >= 0; ++q) {
240 && q->curses_key == (int) dlg_toupper(curses_key)) {
242 return q->dialog_key;
244 if (q->curses_key == curses_key
245 && q->is_function_key == function_key) {
246 *fkey = q->dialog_key;
257 * Test a dialog internal keycode to see if it corresponds to one of the push
258 * buttons on the widget such as "OK".
260 * This is only useful if there are user-defined key bindings, since there are
261 * no built-in bindings that map directly to DLGK_OK, etc.
263 * See also dlg_ok_buttoncode().
266 dlg_result_key(int dialog_key, int fkey GCC_UNUSED, int *resultp)
272 switch ((DLG_KEYS_ENUM) dialog_key) {
274 *resultp = DLG_EXIT_OK;
278 if (!dialog_vars.nocancel) {
279 *resultp = DLG_EXIT_CANCEL;
284 if (dialog_vars.extra_button) {
285 *resultp = DLG_EXIT_EXTRA;
290 if (dialog_vars.help_button) {
291 *resultp = DLG_EXIT_HELP;
296 *resultp = DLG_EXIT_ESC;
304 if (dialog_key == ESC) {
305 *resultp = DLG_EXIT_ESC;
307 } else if (dialog_key == ERR) {
308 *resultp = DLG_EXIT_ERROR;
321 #define ASCII_NAME(name,code) { #name, code }
322 #define CURSES_NAME(upper) { #upper, KEY_ ## upper }
323 #define COUNT_CURSES sizeof(curses_names)/sizeof(curses_names[0])
324 static const CODENAME curses_names[] =
326 ASCII_NAME(ESC, '\033'),
327 ASCII_NAME(CR, '\r'),
328 ASCII_NAME(LF, '\n'),
329 ASCII_NAME(FF, '\f'),
330 ASCII_NAME(TAB, '\t'),
331 ASCII_NAME(DEL, '\177'),
338 CURSES_NAME(BACKSPACE),
367 CURSES_NAME(COMMAND),
375 CURSES_NAME(MESSAGE),
379 CURSES_NAME(OPTIONS),
380 CURSES_NAME(PREVIOUS),
382 CURSES_NAME(REFERENCE),
383 CURSES_NAME(REFRESH),
384 CURSES_NAME(REPLACE),
385 CURSES_NAME(RESTART),
389 CURSES_NAME(SCANCEL),
390 CURSES_NAME(SCOMMAND),
392 CURSES_NAME(SCREATE),
404 CURSES_NAME(SMESSAGE),
407 CURSES_NAME(SOPTIONS),
408 CURSES_NAME(SPREVIOUS),
411 CURSES_NAME(SREPLACE),
415 CURSES_NAME(SSUSPEND),
417 CURSES_NAME(SUSPEND),
421 #define DIALOG_NAME(upper) { #upper, DLGK_ ## upper }
422 #define COUNT_DIALOG sizeof(dialog_names)/sizeof(dialog_names[0])
423 static const CODENAME dialog_names[] =
430 DIALOG_NAME(PAGE_FIRST),
431 DIALOG_NAME(PAGE_LAST),
432 DIALOG_NAME(PAGE_NEXT),
433 DIALOG_NAME(PAGE_PREV),
434 DIALOG_NAME(ITEM_FIRST),
435 DIALOG_NAME(ITEM_LAST),
436 DIALOG_NAME(ITEM_NEXT),
437 DIALOG_NAME(ITEM_PREV),
438 DIALOG_NAME(FIELD_FIRST),
439 DIALOG_NAME(FIELD_LAST),
440 DIALOG_NAME(FIELD_NEXT),
441 DIALOG_NAME(FIELD_PREV),
442 DIALOG_NAME(FORM_FIRST),
443 DIALOG_NAME(FORM_LAST),
444 DIALOG_NAME(FORM_NEXT),
445 DIALOG_NAME(FORM_PREV),
446 DIALOG_NAME(GRID_UP),
447 DIALOG_NAME(GRID_DOWN),
448 DIALOG_NAME(GRID_LEFT),
449 DIALOG_NAME(GRID_RIGHT),
450 DIALOG_NAME(DELETE_LEFT),
451 DIALOG_NAME(DELETE_RIGHT),
452 DIALOG_NAME(DELETE_ALL),
457 DIALOG_NAME(HELPFILE),
464 while (*s != '\0' && isspace(UCH(*s)))
472 while (*s != '\0' && !isspace(UCH(*s)))
478 * Find a user-defined binding, given the curses key code.
480 static DLG_KEYS_BINDING *
481 find_binding(char *widget, int curses_key)
484 DLG_KEYS_BINDING *result = 0;
486 for (p = all_bindings; p != 0; p = p->link) {
488 && !dlg_strcmp(p->name, widget)
489 && p->binding->curses_key == curses_key) {
498 * Built-in bindings have a nonzero "win" member, and the associated binding
499 * table can have more than one entry. We keep those last, since lookups will
500 * find the user-defined bindings first and use those.
502 * Sort "*" (all-widgets) entries past named widgets, since those are less
506 compare_bindings(LIST_BINDINGS * a, LIST_BINDINGS * b)
509 if (a->win == b->win) {
510 if (!strcmp(a->name, b->name)) {
511 result = a->binding[0].curses_key - b->binding[0].curses_key;
512 } else if (!strcmp(b->name, WILDNAME)) {
514 } else if (!strcmp(a->name, WILDNAME)) {
517 result = dlg_strcmp(a->name, b->name);
528 * Find a user-defined binding, given the curses key code. If it does not
529 * exist, create a new one, inserting it into the linked list, keeping it
530 * sorted to simplify lookups for user-defined bindings that can override
531 * the built-in bindings.
533 static DLG_KEYS_BINDING *
534 make_binding(char *widget, int curses_key, int is_function, int dialog_key)
536 LIST_BINDINGS *entry = 0;
537 DLG_KEYS_BINDING *data = 0;
539 LIST_BINDINGS *p, *q;
540 DLG_KEYS_BINDING *result = find_binding(widget, curses_key);
543 && (entry = dlg_calloc(LIST_BINDINGS, 1)) != 0
544 && (data = dlg_calloc(DLG_KEYS_BINDING, 2)) != 0
545 && (name = dlg_strclone(widget)) != 0) {
548 entry->binding = data;
550 data[0].is_function_key = is_function;
551 data[0].curses_key = curses_key;
552 data[0].dialog_key = dialog_key;
554 data[1] = end_keys_binding;
556 for (p = all_bindings, q = 0; p != 0; q = p, p = p->link) {
557 if (compare_bindings(entry, p) < 0) {
564 all_bindings = entry;
570 } else if (entry != 0) {
580 * Parse the parameters of the "bindkeys" configuration-file entry. This
581 * expects widget name which may be "*", followed by curses key definition and
582 * then dialog key definition.
584 * The curses key "should" be one of the names (ignoring case) from
585 * curses_names[], but may also be a single control character (prefix "^" or
586 * "~" depending on whether it is C0 or C1), or an escaped single character.
587 * Binding a printable character with dialog is possible but not useful.
589 * The dialog key must be one of the names from dialog_names[].
592 dlg_parse_bindkey(char *params)
594 char *p = skip_white(params);
596 bool escaped = FALSE;
601 int is_function = FALSE;
610 if (p != widget && *p != '\0') {
614 while (*p != '\0' && curses_key < 0) {
618 } else if (*p == '\\') {
620 } else if (modified) {
622 curses_key = ((modified == '^')
626 curses_key = ((modified == '^')
628 : ((*p & 0x1f) | 0x80));
630 } else if (*p == '^') {
632 } else if (*p == '~') {
634 } else if (isspace(UCH(*p))) {
639 if (!isspace(UCH(*p))) {
643 if (curses_key < 0) {
647 if (sscanf(q, "%[Ff]%d%c", fprefix, &keynumber, check) == 2) {
648 curses_key = KEY_F(keynumber);
651 for (xx = 0; xx < COUNT_CURSES; ++xx) {
652 if (!dlg_strcmp(curses_names[xx].name, q)) {
653 curses_key = curses_names[xx].code;
654 is_function = (curses_key >= KEY_MIN);
664 for (xx = 0; xx < COUNT_DIALOG; ++xx) {
665 if (!dlg_strcmp(dialog_names[xx].name, q)) {
666 dialog_key = dialog_names[xx].code;
674 && make_binding(widget, curses_key, is_function, dialog_key) != 0) {
682 dump_curses_key(FILE *fp, int curses_key)
684 if (curses_key > KEY_MIN) {
687 for (n = 0; n < COUNT_CURSES; ++n) {
688 if (curses_names[n].code == curses_key) {
689 fprintf(fp, "%s", curses_names[n].name);
695 if (curses_key >= KEY_F(0)) {
696 fprintf(fp, "F%d", curses_key - KEY_F(0));
698 fprintf(fp, "curses%d", curses_key);
701 } else if (curses_key >= 0 && curses_key < 32) {
702 fprintf(fp, "^%c", curses_key + 64);
703 } else if (curses_key == 127) {
705 } else if (curses_key >= 128 && curses_key < 160) {
706 fprintf(fp, "~%c", curses_key - 64);
707 } else if (curses_key == 255) {
710 fprintf(fp, "\\%c", curses_key);
715 dump_dialog_key(FILE *fp, int dialog_key)
719 for (n = 0; n < COUNT_DIALOG; ++n) {
720 if (dialog_names[n].code == dialog_key) {
721 fputs(dialog_names[n].name, fp);
727 fprintf(fp, "dialog%d", dialog_key);
732 dump_one_binding(FILE *fp, const char *widget, DLG_KEYS_BINDING * binding)
734 fprintf(fp, "bindkey %s ", widget);
735 dump_curses_key(fp, binding->curses_key);
737 dump_dialog_key(fp, binding->dialog_key);
742 * Dump bindings for the given window. If it is a null, then this dumps the
743 * initial bindings which were loaded from the rc-file that are used as
747 dlg_dump_window_keys(FILE *fp, WINDOW *win)
752 const char *last = "";
754 for (p = all_bindings; p != 0; p = p->link) {
756 if (dlg_strcmp(last, p->name)) {
757 fprintf(fp, "\n# key bindings for %s widgets\n",
758 !strcmp(p->name, WILDNAME) ? "all" : p->name);
761 for (q = p->binding; q->is_function_key >= 0; ++q) {
762 dump_one_binding(fp, p->name, q);
770 * Dump all of the bindings which are not specific to a given widget, i.e.,
771 * the "win" member is null.
774 dlg_dump_keys(FILE *fp)
780 for (p = all_bindings; p != 0; p = p->link) {
786 dlg_dump_window_keys(fp, 0);
790 #endif /* HAVE_RC_FILE */