2 * $Id: dlg_keys.c,v 1.34 2011/10/14 00:41:08 tom Exp $
4 * dlg_keys.c -- runtime binding support for dialog
6 * Copyright 2006-2009,2011 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
) {
233 if (p
->win
== win
|| (p
->win
== 0 && !strcmp(p
->name
, name
))) {
234 int function_key
= (*fkey
!= 0);
235 for (q
= p
->binding
; q
->is_function_key
>= 0; ++q
) {
238 && q
->curses_key
== (int) dlg_toupper(curses_key
)) {
240 return q
->dialog_key
;
242 if (q
->curses_key
== curses_key
243 && q
->is_function_key
== function_key
) {
244 *fkey
= q
->dialog_key
;
255 * Test a dialog internal keycode to see if it corresponds to one of the push
256 * buttons on the widget such as "OK".
258 * This is only useful if there are user-defined key bindings, since there are
259 * no built-in bindings that map directly to DLGK_OK, etc.
261 * See also dlg_ok_buttoncode().
264 dlg_result_key(int dialog_key
, int fkey GCC_UNUSED
, int *resultp
)
270 switch ((DLG_KEYS_ENUM
) dialog_key
) {
272 *resultp
= DLG_EXIT_OK
;
276 if (!dialog_vars
.nocancel
) {
277 *resultp
= DLG_EXIT_CANCEL
;
282 if (dialog_vars
.extra_button
) {
283 *resultp
= DLG_EXIT_EXTRA
;
288 if (dialog_vars
.help_button
) {
289 *resultp
= DLG_EXIT_HELP
;
294 *resultp
= DLG_EXIT_ESC
;
302 if (dialog_key
== ESC
) {
303 *resultp
= DLG_EXIT_ESC
;
305 } else if (dialog_key
== ERR
) {
306 *resultp
= DLG_EXIT_ERROR
;
319 #define ASCII_NAME(name,code) { #name, code }
320 #define CURSES_NAME(upper) { #upper, KEY_ ## upper }
321 #define COUNT_CURSES sizeof(curses_names)/sizeof(curses_names[0])
322 static const CODENAME curses_names
[] =
324 ASCII_NAME(ESC
, '\033'),
325 ASCII_NAME(CR
, '\r'),
326 ASCII_NAME(LF
, '\n'),
327 ASCII_NAME(FF
, '\f'),
328 ASCII_NAME(TAB
, '\t'),
329 ASCII_NAME(DEL
, '\177'),
336 CURSES_NAME(BACKSPACE
),
365 CURSES_NAME(COMMAND
),
373 CURSES_NAME(MESSAGE
),
377 CURSES_NAME(OPTIONS
),
378 CURSES_NAME(PREVIOUS
),
380 CURSES_NAME(REFERENCE
),
381 CURSES_NAME(REFRESH
),
382 CURSES_NAME(REPLACE
),
383 CURSES_NAME(RESTART
),
387 CURSES_NAME(SCANCEL
),
388 CURSES_NAME(SCOMMAND
),
390 CURSES_NAME(SCREATE
),
402 CURSES_NAME(SMESSAGE
),
405 CURSES_NAME(SOPTIONS
),
406 CURSES_NAME(SPREVIOUS
),
409 CURSES_NAME(SREPLACE
),
413 CURSES_NAME(SSUSPEND
),
415 CURSES_NAME(SUSPEND
),
419 #define DIALOG_NAME(upper) { #upper, DLGK_ ## upper }
420 #define COUNT_DIALOG sizeof(dialog_names)/sizeof(dialog_names[0])
421 static const CODENAME dialog_names
[] =
428 DIALOG_NAME(PAGE_FIRST
),
429 DIALOG_NAME(PAGE_LAST
),
430 DIALOG_NAME(PAGE_NEXT
),
431 DIALOG_NAME(PAGE_PREV
),
432 DIALOG_NAME(ITEM_FIRST
),
433 DIALOG_NAME(ITEM_LAST
),
434 DIALOG_NAME(ITEM_NEXT
),
435 DIALOG_NAME(ITEM_PREV
),
436 DIALOG_NAME(FIELD_FIRST
),
437 DIALOG_NAME(FIELD_LAST
),
438 DIALOG_NAME(FIELD_NEXT
),
439 DIALOG_NAME(FIELD_PREV
),
440 DIALOG_NAME(FORM_FIRST
),
441 DIALOG_NAME(FORM_LAST
),
442 DIALOG_NAME(FORM_NEXT
),
443 DIALOG_NAME(FORM_PREV
),
444 DIALOG_NAME(GRID_UP
),
445 DIALOG_NAME(GRID_DOWN
),
446 DIALOG_NAME(GRID_LEFT
),
447 DIALOG_NAME(GRID_RIGHT
),
448 DIALOG_NAME(DELETE_LEFT
),
449 DIALOG_NAME(DELETE_RIGHT
),
450 DIALOG_NAME(DELETE_ALL
),
455 DIALOG_NAME(HELPFILE
),
462 while (*s
!= '\0' && isspace(UCH(*s
)))
470 while (*s
!= '\0' && !isspace(UCH(*s
)))
476 * Find a user-defined binding, given the curses key code.
478 static DLG_KEYS_BINDING
*
479 find_binding(char *widget
, int curses_key
)
482 DLG_KEYS_BINDING
*result
= 0;
484 for (p
= all_bindings
; p
!= 0; p
= p
->link
) {
486 && !dlg_strcmp(p
->name
, widget
)
487 && p
->binding
->curses_key
== curses_key
) {
496 * Built-in bindings have a nonzero "win" member, and the associated binding
497 * table can have more than one entry. We keep those last, since lookups will
498 * find the user-defined bindings first and use those.
500 * Sort "*" (all-widgets) entries past named widgets, since those are less
504 compare_bindings(LIST_BINDINGS
* a
, LIST_BINDINGS
* b
)
507 if (a
->win
== b
->win
) {
508 if (!strcmp(a
->name
, b
->name
)) {
509 result
= a
->binding
[0].curses_key
- b
->binding
[0].curses_key
;
510 } else if (!strcmp(b
->name
, WILDNAME
)) {
512 } else if (!strcmp(a
->name
, WILDNAME
)) {
515 result
= dlg_strcmp(a
->name
, b
->name
);
526 * Find a user-defined binding, given the curses key code. If it does not
527 * exist, create a new one, inserting it into the linked list, keeping it
528 * sorted to simplify lookups for user-defined bindings that can override
529 * the built-in bindings.
531 static DLG_KEYS_BINDING
*
532 make_binding(char *widget
, int curses_key
, int is_function
, int dialog_key
)
534 LIST_BINDINGS
*entry
= 0;
535 DLG_KEYS_BINDING
*data
= 0;
537 LIST_BINDINGS
*p
, *q
;
538 DLG_KEYS_BINDING
*result
= find_binding(widget
, curses_key
);
541 && (entry
= dlg_calloc(LIST_BINDINGS
, 1)) != 0
542 && (data
= dlg_calloc(DLG_KEYS_BINDING
, 2)) != 0
543 && (name
= dlg_strclone(widget
)) != 0) {
546 entry
->binding
= data
;
548 data
[0].is_function_key
= is_function
;
549 data
[0].curses_key
= curses_key
;
550 data
[0].dialog_key
= dialog_key
;
552 data
[1] = end_keys_binding
;
554 for (p
= all_bindings
, q
= 0; p
!= 0; q
= p
, p
= p
->link
) {
555 if (compare_bindings(entry
, p
) < 0) {
562 all_bindings
= entry
;
568 } else if (entry
!= 0) {
578 * Parse the parameters of the "bindkeys" configuration-file entry. This
579 * expects widget name which may be "*", followed by curses key definition and
580 * then dialog key definition.
582 * The curses key "should" be one of the names (ignoring case) from
583 * curses_names[], but may also be a single control character (prefix "^" or
584 * "~" depending on whether it is C0 or C1), or an escaped single character.
585 * Binding a printable character with dialog is possible but not useful.
587 * The dialog key must be one of the names from dialog_names[].
590 dlg_parse_bindkey(char *params
)
592 char *p
= skip_white(params
);
594 bool escaped
= FALSE
;
599 int is_function
= FALSE
;
608 if (p
!= widget
&& *p
!= '\0') {
612 while (*p
!= '\0' && curses_key
< 0) {
616 } else if (*p
== '\\') {
618 } else if (modified
) {
620 curses_key
= ((modified
== '^')
624 curses_key
= ((modified
== '^')
626 : ((*p
& 0x1f) | 0x80));
628 } else if (*p
== '^') {
630 } else if (*p
== '~') {
632 } else if (isspace(UCH(*p
))) {
637 if (!isspace(UCH(*p
))) {
641 if (curses_key
< 0) {
645 if (sscanf(q
, "%[Ff]%d%c", fprefix
, &keynumber
, check
) == 2) {
646 curses_key
= KEY_F(keynumber
);
649 for (xx
= 0; xx
< COUNT_CURSES
; ++xx
) {
650 if (!dlg_strcmp(curses_names
[xx
].name
, q
)) {
651 curses_key
= curses_names
[xx
].code
;
652 is_function
= (curses_key
>= KEY_MIN
);
662 for (xx
= 0; xx
< COUNT_DIALOG
; ++xx
) {
663 if (!dlg_strcmp(dialog_names
[xx
].name
, q
)) {
664 dialog_key
= dialog_names
[xx
].code
;
672 && make_binding(widget
, curses_key
, is_function
, dialog_key
) != 0) {
680 dump_curses_key(FILE *fp
, int curses_key
)
682 if (curses_key
> KEY_MIN
) {
685 for (n
= 0; n
< COUNT_CURSES
; ++n
) {
686 if (curses_names
[n
].code
== curses_key
) {
687 fprintf(fp
, "%s", curses_names
[n
].name
);
693 if (curses_key
>= KEY_F(0)) {
694 fprintf(fp
, "F%d", curses_key
- KEY_F(0));
696 fprintf(fp
, "curses%d", curses_key
);
699 } else if (curses_key
>= 0 && curses_key
< 32) {
700 fprintf(fp
, "^%c", curses_key
+ 64);
701 } else if (curses_key
== 127) {
703 } else if (curses_key
>= 128 && curses_key
< 160) {
704 fprintf(fp
, "~%c", curses_key
- 64);
705 } else if (curses_key
== 255) {
708 fprintf(fp
, "\\%c", curses_key
);
713 dump_dialog_key(FILE *fp
, int dialog_key
)
717 for (n
= 0; n
< COUNT_DIALOG
; ++n
) {
718 if (dialog_names
[n
].code
== dialog_key
) {
719 fputs(dialog_names
[n
].name
, fp
);
725 fprintf(fp
, "dialog%d", dialog_key
);
730 dump_one_binding(FILE *fp
, const char *widget
, DLG_KEYS_BINDING
* binding
)
732 fprintf(fp
, "bindkey %s ", widget
);
733 dump_curses_key(fp
, binding
->curses_key
);
735 dump_dialog_key(fp
, binding
->dialog_key
);
740 * Dump bindings for the given window. If it is a null, then this dumps the
741 * initial bindings which were loaded from the rc-file that are used as
745 dlg_dump_window_keys(FILE *fp
, WINDOW
*win
)
750 const char *last
= "";
752 for (p
= all_bindings
; p
!= 0; p
= p
->link
) {
754 if (dlg_strcmp(last
, p
->name
)) {
755 fprintf(fp
, "\n# key bindings for %s widgets\n",
756 !strcmp(p
->name
, WILDNAME
) ? "all" : p
->name
);
759 for (q
= p
->binding
; q
->is_function_key
>= 0; ++q
) {
760 dump_one_binding(fp
, p
->name
, q
);
768 * Dump all of the bindings which are not specific to a given widget, i.e.,
769 * the "win" member is null.
772 dlg_dump_keys(FILE *fp
)
778 for (p
= all_bindings
; p
!= 0; p
= p
->link
) {
784 dlg_dump_window_keys(fp
, 0);
788 #endif /* HAVE_RC_FILE */