14c8945a0SNathan Whitehorn /*
2*a96ef450SBaptiste Daroussin * $Id: dlg_keys.c,v 1.58 2020/11/26 17:11:56 Glenn.Herteg Exp $
34c8945a0SNathan Whitehorn *
44c8945a0SNathan Whitehorn * dlg_keys.c -- runtime binding support for dialog
54c8945a0SNathan Whitehorn *
6*a96ef450SBaptiste Daroussin * Copyright 2006-2019,2020 Thomas E. Dickey
74c8945a0SNathan Whitehorn *
84c8945a0SNathan Whitehorn * This program is free software; you can redistribute it and/or modify
94c8945a0SNathan Whitehorn * it under the terms of the GNU Lesser General Public License, version 2.1
104c8945a0SNathan Whitehorn * as published by the Free Software Foundation.
114c8945a0SNathan Whitehorn *
124c8945a0SNathan Whitehorn * This program is distributed in the hope that it will be useful, but
134c8945a0SNathan Whitehorn * WITHOUT ANY WARRANTY; without even the implied warranty of
144c8945a0SNathan Whitehorn * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
154c8945a0SNathan Whitehorn * Lesser General Public License for more details.
164c8945a0SNathan Whitehorn *
174c8945a0SNathan Whitehorn * You should have received a copy of the GNU Lesser General Public
184c8945a0SNathan Whitehorn * License along with this program; if not, write to
194c8945a0SNathan Whitehorn * Free Software Foundation, Inc.
204c8945a0SNathan Whitehorn * 51 Franklin St., Fifth Floor
214c8945a0SNathan Whitehorn * Boston, MA 02110, USA.
224c8945a0SNathan Whitehorn */
234c8945a0SNathan Whitehorn
244c8945a0SNathan Whitehorn #include <dialog.h>
254c8945a0SNathan Whitehorn #include <dlg_keys.h>
26*a96ef450SBaptiste Daroussin #include <dlg_internals.h>
274c8945a0SNathan Whitehorn
284c8945a0SNathan Whitehorn #define LIST_BINDINGS struct _list_bindings
294c8945a0SNathan Whitehorn
30f4f33ea0SBaptiste Daroussin #define CHR_BACKSLASH '\\'
31f4f33ea0SBaptiste Daroussin #define IsOctal(ch) ((ch) >= '0' && (ch) <= '7')
32f4f33ea0SBaptiste Daroussin
334c8945a0SNathan Whitehorn LIST_BINDINGS {
344c8945a0SNathan Whitehorn LIST_BINDINGS *link;
354c8945a0SNathan Whitehorn WINDOW *win; /* window on which widget gets input */
364c8945a0SNathan Whitehorn const char *name; /* widget name */
374c8945a0SNathan Whitehorn bool buttons; /* true only for dlg_register_buttons() */
384c8945a0SNathan Whitehorn DLG_KEYS_BINDING *binding; /* list of bindings */
394c8945a0SNathan Whitehorn };
404c8945a0SNathan Whitehorn
412a3e3873SBaptiste Daroussin #define WILDNAME "*"
424c8945a0SNathan Whitehorn static LIST_BINDINGS *all_bindings;
434c8945a0SNathan Whitehorn static const DLG_KEYS_BINDING end_keys_binding = END_KEYS_BINDING;
444c8945a0SNathan Whitehorn
454c8945a0SNathan Whitehorn /*
464c8945a0SNathan Whitehorn * For a given named widget's window, associate a binding table.
474c8945a0SNathan Whitehorn */
484c8945a0SNathan Whitehorn void
dlg_register_window(WINDOW * win,const char * name,DLG_KEYS_BINDING * binding)494c8945a0SNathan Whitehorn dlg_register_window(WINDOW *win, const char *name, DLG_KEYS_BINDING * binding)
504c8945a0SNathan Whitehorn {
514c8945a0SNathan Whitehorn LIST_BINDINGS *p, *q;
524c8945a0SNathan Whitehorn
534c8945a0SNathan Whitehorn for (p = all_bindings, q = 0; p != 0; q = p, p = p->link) {
544c8945a0SNathan Whitehorn if (p->win == win && !strcmp(p->name, name)) {
554c8945a0SNathan Whitehorn p->binding = binding;
564c8945a0SNathan Whitehorn return;
574c8945a0SNathan Whitehorn }
584c8945a0SNathan Whitehorn }
594c8945a0SNathan Whitehorn /* add built-in bindings at the end of the list (see compare_bindings). */
604c8945a0SNathan Whitehorn if ((p = dlg_calloc(LIST_BINDINGS, 1)) != 0) {
614c8945a0SNathan Whitehorn p->win = win;
624c8945a0SNathan Whitehorn p->name = name;
634c8945a0SNathan Whitehorn p->binding = binding;
64f4f33ea0SBaptiste Daroussin if (q != 0) {
654c8945a0SNathan Whitehorn q->link = p;
66f4f33ea0SBaptiste Daroussin } else {
674c8945a0SNathan Whitehorn all_bindings = p;
684c8945a0SNathan Whitehorn }
69f4f33ea0SBaptiste Daroussin }
702a3e3873SBaptiste Daroussin #if defined(HAVE_DLG_TRACE) && defined(HAVE_RC_FILE)
712a3e3873SBaptiste Daroussin /*
722a3e3873SBaptiste Daroussin * Trace the binding information assigned to this window. For most widgets
732a3e3873SBaptiste Daroussin * there is only one binding table. forms have two, so the trace will be
742a3e3873SBaptiste Daroussin * longer. Since compiled-in bindings are only visible when the widget is
752a3e3873SBaptiste Daroussin * registered, there is no other way to see what bindings are available,
762a3e3873SBaptiste Daroussin * than by running dialog and tracing it.
772a3e3873SBaptiste Daroussin */
78f4f33ea0SBaptiste Daroussin DLG_TRACE(("# dlg_register_window %s\n", name));
79f4f33ea0SBaptiste Daroussin dlg_dump_keys(dialog_state.trace_output);
802a3e3873SBaptiste Daroussin dlg_dump_window_keys(dialog_state.trace_output, win);
81f4f33ea0SBaptiste Daroussin DLG_TRACE(("# ...done dlg_register_window %s\n", name));
822a3e3873SBaptiste Daroussin #endif
834c8945a0SNathan Whitehorn }
844c8945a0SNathan Whitehorn
854c8945a0SNathan Whitehorn /*
864c8945a0SNathan Whitehorn * Unlike dlg_lookup_key(), this looks for either widget-builtin or rc-file
874c8945a0SNathan Whitehorn * definitions, depending on whether 'win' is null.
884c8945a0SNathan Whitehorn */
894c8945a0SNathan Whitehorn static int
key_is_bound(WINDOW * win,const char * name,int curses_key,int function_key)904c8945a0SNathan Whitehorn key_is_bound(WINDOW *win, const char *name, int curses_key, int function_key)
914c8945a0SNathan Whitehorn {
924c8945a0SNathan Whitehorn LIST_BINDINGS *p;
934c8945a0SNathan Whitehorn
944c8945a0SNathan Whitehorn for (p = all_bindings; p != 0; p = p->link) {
954c8945a0SNathan Whitehorn if (p->win == win && !dlg_strcmp(p->name, name)) {
964c8945a0SNathan Whitehorn int n;
974c8945a0SNathan Whitehorn for (n = 0; p->binding[n].is_function_key >= 0; ++n) {
984c8945a0SNathan Whitehorn if (p->binding[n].curses_key == curses_key
994c8945a0SNathan Whitehorn && p->binding[n].is_function_key == function_key) {
1004c8945a0SNathan Whitehorn return TRUE;
1014c8945a0SNathan Whitehorn }
1024c8945a0SNathan Whitehorn }
1034c8945a0SNathan Whitehorn }
1044c8945a0SNathan Whitehorn }
1054c8945a0SNathan Whitehorn return FALSE;
1064c8945a0SNathan Whitehorn }
1074c8945a0SNathan Whitehorn
1084c8945a0SNathan Whitehorn /*
1094c8945a0SNathan Whitehorn * Call this function after dlg_register_window(), for the list of button
1104c8945a0SNathan Whitehorn * labels associated with the widget.
1114c8945a0SNathan Whitehorn *
1124c8945a0SNathan Whitehorn * Ensure that dlg_lookup_key() will not accidentally translate a key that
1134c8945a0SNathan Whitehorn * we would like to use for a button abbreviation to some other key, e.g.,
1144c8945a0SNathan Whitehorn * h/j/k/l for navigation into a cursor key. Do this by binding the key
1154c8945a0SNathan Whitehorn * to itself.
1164c8945a0SNathan Whitehorn *
1174c8945a0SNathan Whitehorn * See dlg_char_to_button().
1184c8945a0SNathan Whitehorn */
1194c8945a0SNathan Whitehorn void
dlg_register_buttons(WINDOW * win,const char * name,const char ** buttons)1204c8945a0SNathan Whitehorn dlg_register_buttons(WINDOW *win, const char *name, const char **buttons)
1214c8945a0SNathan Whitehorn {
1224c8945a0SNathan Whitehorn int n;
1234c8945a0SNathan Whitehorn LIST_BINDINGS *p;
1244c8945a0SNathan Whitehorn DLG_KEYS_BINDING *q;
1254c8945a0SNathan Whitehorn
1264c8945a0SNathan Whitehorn if (buttons == 0)
1274c8945a0SNathan Whitehorn return;
1284c8945a0SNathan Whitehorn
1294c8945a0SNathan Whitehorn for (n = 0; buttons[n] != 0; ++n) {
1304c8945a0SNathan Whitehorn int curses_key = dlg_button_to_char(buttons[n]);
1314c8945a0SNathan Whitehorn
132*a96ef450SBaptiste Daroussin /* ignore binding if there is no key to bind */
133*a96ef450SBaptiste Daroussin if (curses_key < 0)
134*a96ef450SBaptiste Daroussin continue;
135*a96ef450SBaptiste Daroussin
1364c8945a0SNathan Whitehorn /* ignore multibyte characters */
1374c8945a0SNathan Whitehorn if (curses_key >= KEY_MIN)
1384c8945a0SNathan Whitehorn continue;
1394c8945a0SNathan Whitehorn
1404c8945a0SNathan Whitehorn /* if it is not bound in the widget, skip it (no conflicts) */
1414c8945a0SNathan Whitehorn if (!key_is_bound(win, name, curses_key, FALSE))
1424c8945a0SNathan Whitehorn continue;
1434c8945a0SNathan Whitehorn
1444c8945a0SNathan Whitehorn #ifdef HAVE_RC_FILE
1454c8945a0SNathan Whitehorn /* if it is bound in the rc-file, skip it */
1464c8945a0SNathan Whitehorn if (key_is_bound(0, name, curses_key, FALSE))
1474c8945a0SNathan Whitehorn continue;
1484c8945a0SNathan Whitehorn #endif
1494c8945a0SNathan Whitehorn
1504c8945a0SNathan Whitehorn if ((p = dlg_calloc(LIST_BINDINGS, 1)) != 0) {
1514c8945a0SNathan Whitehorn if ((q = dlg_calloc(DLG_KEYS_BINDING, 2)) != 0) {
1524c8945a0SNathan Whitehorn q[0].is_function_key = 0;
1534c8945a0SNathan Whitehorn q[0].curses_key = curses_key;
1544c8945a0SNathan Whitehorn q[0].dialog_key = curses_key;
1554c8945a0SNathan Whitehorn q[1] = end_keys_binding;
1564c8945a0SNathan Whitehorn
1574c8945a0SNathan Whitehorn p->win = win;
1584c8945a0SNathan Whitehorn p->name = name;
1594c8945a0SNathan Whitehorn p->buttons = TRUE;
1604c8945a0SNathan Whitehorn p->binding = q;
1614c8945a0SNathan Whitehorn
1624c8945a0SNathan Whitehorn /* put these at the beginning, to override the widget's table */
1634c8945a0SNathan Whitehorn p->link = all_bindings;
1644c8945a0SNathan Whitehorn all_bindings = p;
1654c8945a0SNathan Whitehorn } else {
1664c8945a0SNathan Whitehorn free(p);
1674c8945a0SNathan Whitehorn }
1684c8945a0SNathan Whitehorn }
1694c8945a0SNathan Whitehorn }
1704c8945a0SNathan Whitehorn }
1714c8945a0SNathan Whitehorn
1724c8945a0SNathan Whitehorn /*
1734c8945a0SNathan Whitehorn * Remove the bindings for a given window.
1744c8945a0SNathan Whitehorn */
1754c8945a0SNathan Whitehorn void
dlg_unregister_window(WINDOW * win)1764c8945a0SNathan Whitehorn dlg_unregister_window(WINDOW *win)
1774c8945a0SNathan Whitehorn {
1784c8945a0SNathan Whitehorn LIST_BINDINGS *p, *q;
1794c8945a0SNathan Whitehorn
1804c8945a0SNathan Whitehorn for (p = all_bindings, q = 0; p != 0; p = p->link) {
1814c8945a0SNathan Whitehorn if (p->win == win) {
1824c8945a0SNathan Whitehorn if (q != 0) {
1834c8945a0SNathan Whitehorn q->link = p->link;
1844c8945a0SNathan Whitehorn } else {
1854c8945a0SNathan Whitehorn all_bindings = p->link;
1864c8945a0SNathan Whitehorn }
1874c8945a0SNathan Whitehorn /* the user-defined and buttons-bindings all are length=1 */
1884c8945a0SNathan Whitehorn if (p->binding[1].is_function_key < 0)
1894c8945a0SNathan Whitehorn free(p->binding);
1904c8945a0SNathan Whitehorn free(p);
1914c8945a0SNathan Whitehorn dlg_unregister_window(win);
1924c8945a0SNathan Whitehorn break;
1934c8945a0SNathan Whitehorn }
1944c8945a0SNathan Whitehorn q = p;
1954c8945a0SNathan Whitehorn }
1964c8945a0SNathan Whitehorn }
1974c8945a0SNathan Whitehorn
1984c8945a0SNathan Whitehorn /*
1994c8945a0SNathan Whitehorn * Call this after wgetch(), using the same window pointer and passing
2004c8945a0SNathan Whitehorn * the curses-key.
2014c8945a0SNathan Whitehorn *
2024c8945a0SNathan Whitehorn * If there is no binding associated with the widget, it simply returns
2034c8945a0SNathan Whitehorn * the given curses-key.
2044c8945a0SNathan Whitehorn *
2054c8945a0SNathan Whitehorn * Parameters:
2064c8945a0SNathan Whitehorn * win is the window on which the wgetch() was done.
2074c8945a0SNathan Whitehorn * curses_key is the value returned by wgetch().
208f4f33ea0SBaptiste Daroussin * fkey in/out (on input, it is nonzero if curses_key is a function key,
209f4f33ea0SBaptiste Daroussin * and on output, it is nonzero if the result is a function key).
2104c8945a0SNathan Whitehorn */
2114c8945a0SNathan Whitehorn int
dlg_lookup_key(WINDOW * win,int curses_key,int * fkey)2124c8945a0SNathan Whitehorn dlg_lookup_key(WINDOW *win, int curses_key, int *fkey)
2134c8945a0SNathan Whitehorn {
2144c8945a0SNathan Whitehorn LIST_BINDINGS *p;
2152a3e3873SBaptiste Daroussin DLG_KEYS_BINDING *q;
2164c8945a0SNathan Whitehorn
2174c8945a0SNathan Whitehorn /*
2184c8945a0SNathan Whitehorn * Ignore mouse clicks, since they are already encoded properly.
2194c8945a0SNathan Whitehorn */
2204c8945a0SNathan Whitehorn #ifdef KEY_MOUSE
2214c8945a0SNathan Whitehorn if (*fkey != 0 && curses_key == KEY_MOUSE) {
2224c8945a0SNathan Whitehorn ;
2234c8945a0SNathan Whitehorn } else
2244c8945a0SNathan Whitehorn #endif
2254c8945a0SNathan Whitehorn /*
2264c8945a0SNathan Whitehorn * Ignore resize events, since they are already encoded properly.
2274c8945a0SNathan Whitehorn */
2284c8945a0SNathan Whitehorn #ifdef KEY_RESIZE
2294c8945a0SNathan Whitehorn if (*fkey != 0 && curses_key == KEY_RESIZE) {
2304c8945a0SNathan Whitehorn ;
2314c8945a0SNathan Whitehorn } else
2324c8945a0SNathan Whitehorn #endif
2334c8945a0SNathan Whitehorn if (*fkey == 0 || curses_key < KEY_MAX) {
2342a3e3873SBaptiste Daroussin const char *name = WILDNAME;
2352a3e3873SBaptiste Daroussin if (win != 0) {
2364c8945a0SNathan Whitehorn for (p = all_bindings; p != 0; p = p->link) {
2372a3e3873SBaptiste Daroussin if (p->win == win) {
2382a3e3873SBaptiste Daroussin name = p->name;
2392a3e3873SBaptiste Daroussin break;
2402a3e3873SBaptiste Daroussin }
2412a3e3873SBaptiste Daroussin }
2422a3e3873SBaptiste Daroussin }
2432a3e3873SBaptiste Daroussin for (p = all_bindings; p != 0; p = p->link) {
244f4f33ea0SBaptiste Daroussin if (p->win == win ||
245f4f33ea0SBaptiste Daroussin (p->win == 0 &&
246f4f33ea0SBaptiste Daroussin (!strcmp(p->name, name) || !strcmp(p->name, WILDNAME)))) {
2474c8945a0SNathan Whitehorn int function_key = (*fkey != 0);
2482a3e3873SBaptiste Daroussin for (q = p->binding; q->is_function_key >= 0; ++q) {
2494c8945a0SNathan Whitehorn if (p->buttons
2504c8945a0SNathan Whitehorn && !function_key
2512a3e3873SBaptiste Daroussin && q->curses_key == (int) dlg_toupper(curses_key)) {
2524c8945a0SNathan Whitehorn *fkey = 0;
2532a3e3873SBaptiste Daroussin return q->dialog_key;
2544c8945a0SNathan Whitehorn }
2552a3e3873SBaptiste Daroussin if (q->curses_key == curses_key
2562a3e3873SBaptiste Daroussin && q->is_function_key == function_key) {
2572a3e3873SBaptiste Daroussin *fkey = q->dialog_key;
2584c8945a0SNathan Whitehorn return *fkey;
2594c8945a0SNathan Whitehorn }
2604c8945a0SNathan Whitehorn }
2614c8945a0SNathan Whitehorn }
2624c8945a0SNathan Whitehorn }
2634c8945a0SNathan Whitehorn }
2644c8945a0SNathan Whitehorn return curses_key;
2654c8945a0SNathan Whitehorn }
2664c8945a0SNathan Whitehorn
2674c8945a0SNathan Whitehorn /*
2684c8945a0SNathan Whitehorn * Test a dialog internal keycode to see if it corresponds to one of the push
2694c8945a0SNathan Whitehorn * buttons on the widget such as "OK".
2704c8945a0SNathan Whitehorn *
2714c8945a0SNathan Whitehorn * This is only useful if there are user-defined key bindings, since there are
2724c8945a0SNathan Whitehorn * no built-in bindings that map directly to DLGK_OK, etc.
2734c8945a0SNathan Whitehorn *
2744c8945a0SNathan Whitehorn * See also dlg_ok_buttoncode().
2754c8945a0SNathan Whitehorn */
2764c8945a0SNathan Whitehorn int
dlg_result_key(int dialog_key,int fkey GCC_UNUSED,int * resultp)2774c8945a0SNathan Whitehorn dlg_result_key(int dialog_key, int fkey GCC_UNUSED, int *resultp)
2784c8945a0SNathan Whitehorn {
2794c8945a0SNathan Whitehorn int done = FALSE;
2804c8945a0SNathan Whitehorn
281*a96ef450SBaptiste Daroussin DLG_TRACE(("# dlg_result_key(dialog_key=%d, fkey=%d)\n", dialog_key, fkey));
282*a96ef450SBaptiste Daroussin #ifdef KEY_RESIZE
283*a96ef450SBaptiste Daroussin if (dialog_state.had_resize) {
284*a96ef450SBaptiste Daroussin if (dialog_key == ERR) {
285*a96ef450SBaptiste Daroussin dialog_key = 0;
286*a96ef450SBaptiste Daroussin } else {
287*a96ef450SBaptiste Daroussin dialog_state.had_resize = FALSE;
288*a96ef450SBaptiste Daroussin }
289*a96ef450SBaptiste Daroussin } else if (fkey && dialog_key == KEY_RESIZE) {
290*a96ef450SBaptiste Daroussin dialog_state.had_resize = TRUE;
291*a96ef450SBaptiste Daroussin }
292*a96ef450SBaptiste Daroussin #endif
2934c8945a0SNathan Whitehorn #ifdef HAVE_RC_FILE
2944c8945a0SNathan Whitehorn if (fkey) {
2954c8945a0SNathan Whitehorn switch ((DLG_KEYS_ENUM) dialog_key) {
2964c8945a0SNathan Whitehorn case DLGK_OK:
297*a96ef450SBaptiste Daroussin if (!dialog_vars.nook) {
2984c8945a0SNathan Whitehorn *resultp = DLG_EXIT_OK;
2994c8945a0SNathan Whitehorn done = TRUE;
300*a96ef450SBaptiste Daroussin }
3014c8945a0SNathan Whitehorn break;
3024c8945a0SNathan Whitehorn case DLGK_CANCEL:
3034c8945a0SNathan Whitehorn if (!dialog_vars.nocancel) {
3044c8945a0SNathan Whitehorn *resultp = DLG_EXIT_CANCEL;
3054c8945a0SNathan Whitehorn done = TRUE;
3064c8945a0SNathan Whitehorn }
3074c8945a0SNathan Whitehorn break;
3084c8945a0SNathan Whitehorn case DLGK_EXTRA:
3094c8945a0SNathan Whitehorn if (dialog_vars.extra_button) {
3104c8945a0SNathan Whitehorn *resultp = DLG_EXIT_EXTRA;
3114c8945a0SNathan Whitehorn done = TRUE;
3124c8945a0SNathan Whitehorn }
3134c8945a0SNathan Whitehorn break;
3144c8945a0SNathan Whitehorn case DLGK_HELP:
3154c8945a0SNathan Whitehorn if (dialog_vars.help_button) {
3164c8945a0SNathan Whitehorn *resultp = DLG_EXIT_HELP;
3174c8945a0SNathan Whitehorn done = TRUE;
3184c8945a0SNathan Whitehorn }
3194c8945a0SNathan Whitehorn break;
3204c8945a0SNathan Whitehorn case DLGK_ESC:
3214c8945a0SNathan Whitehorn *resultp = DLG_EXIT_ESC;
3224c8945a0SNathan Whitehorn done = TRUE;
3234c8945a0SNathan Whitehorn break;
3244c8945a0SNathan Whitehorn default:
3254c8945a0SNathan Whitehorn break;
3264c8945a0SNathan Whitehorn }
3274c8945a0SNathan Whitehorn } else
3284c8945a0SNathan Whitehorn #endif
3294c8945a0SNathan Whitehorn if (dialog_key == ESC) {
3304c8945a0SNathan Whitehorn *resultp = DLG_EXIT_ESC;
3314c8945a0SNathan Whitehorn done = TRUE;
3324c8945a0SNathan Whitehorn } else if (dialog_key == ERR) {
3334c8945a0SNathan Whitehorn *resultp = DLG_EXIT_ERROR;
3344c8945a0SNathan Whitehorn done = TRUE;
3354c8945a0SNathan Whitehorn }
3364c8945a0SNathan Whitehorn
3374c8945a0SNathan Whitehorn return done;
3384c8945a0SNathan Whitehorn }
3394c8945a0SNathan Whitehorn
340*a96ef450SBaptiste Daroussin /*
341*a96ef450SBaptiste Daroussin * If a key was bound to one of the button-codes in dlg_result_key(), fake
342*a96ef450SBaptiste Daroussin * a button-value and an "Enter" key to cause the calling widget to return
343*a96ef450SBaptiste Daroussin * the corresponding status.
344*a96ef450SBaptiste Daroussin *
345*a96ef450SBaptiste Daroussin * See dlg_ok_buttoncode(), which maps settings for ok/extra/help and button
346*a96ef450SBaptiste Daroussin * number into exit-code.
347*a96ef450SBaptiste Daroussin */
348*a96ef450SBaptiste Daroussin int
dlg_button_key(int exit_code,int * button,int * dialog_key,int * fkey)349*a96ef450SBaptiste Daroussin dlg_button_key(int exit_code, int *button, int *dialog_key, int *fkey)
350*a96ef450SBaptiste Daroussin {
351*a96ef450SBaptiste Daroussin int changed = FALSE;
352*a96ef450SBaptiste Daroussin switch (exit_code) {
353*a96ef450SBaptiste Daroussin case DLG_EXIT_OK:
354*a96ef450SBaptiste Daroussin if (!dialog_vars.nook) {
355*a96ef450SBaptiste Daroussin *button = 0;
356*a96ef450SBaptiste Daroussin changed = TRUE;
357*a96ef450SBaptiste Daroussin }
358*a96ef450SBaptiste Daroussin break;
359*a96ef450SBaptiste Daroussin case DLG_EXIT_EXTRA:
360*a96ef450SBaptiste Daroussin if (dialog_vars.extra_button) {
361*a96ef450SBaptiste Daroussin *button = dialog_vars.nook ? 0 : 1;
362*a96ef450SBaptiste Daroussin changed = TRUE;
363*a96ef450SBaptiste Daroussin }
364*a96ef450SBaptiste Daroussin break;
365*a96ef450SBaptiste Daroussin case DLG_EXIT_CANCEL:
366*a96ef450SBaptiste Daroussin if (!dialog_vars.nocancel) {
367*a96ef450SBaptiste Daroussin *button = dialog_vars.nook ? 1 : 2;
368*a96ef450SBaptiste Daroussin changed = TRUE;
369*a96ef450SBaptiste Daroussin }
370*a96ef450SBaptiste Daroussin break;
371*a96ef450SBaptiste Daroussin case DLG_EXIT_HELP:
372*a96ef450SBaptiste Daroussin if (dialog_vars.help_button) {
373*a96ef450SBaptiste Daroussin int cancel = dialog_vars.nocancel ? 0 : 1;
374*a96ef450SBaptiste Daroussin int extra = dialog_vars.extra_button ? 1 : 0;
375*a96ef450SBaptiste Daroussin int okay = dialog_vars.nook ? 0 : 1;
376*a96ef450SBaptiste Daroussin *button = okay + extra + cancel;
377*a96ef450SBaptiste Daroussin changed = TRUE;
378*a96ef450SBaptiste Daroussin }
379*a96ef450SBaptiste Daroussin break;
380*a96ef450SBaptiste Daroussin }
381*a96ef450SBaptiste Daroussin if (changed) {
382*a96ef450SBaptiste Daroussin DLG_TRACE(("# dlg_button_key(%d:%s) button %d\n",
383*a96ef450SBaptiste Daroussin exit_code, dlg_exitcode2s(exit_code), *button));
384*a96ef450SBaptiste Daroussin *dialog_key = *fkey = DLGK_ENTER;
385*a96ef450SBaptiste Daroussin }
386*a96ef450SBaptiste Daroussin return changed;
387*a96ef450SBaptiste Daroussin }
388*a96ef450SBaptiste Daroussin
389*a96ef450SBaptiste Daroussin int
dlg_ok_button_key(int exit_code,int * button,int * dialog_key,int * fkey)390*a96ef450SBaptiste Daroussin dlg_ok_button_key(int exit_code, int *button, int *dialog_key, int *fkey)
391*a96ef450SBaptiste Daroussin {
392*a96ef450SBaptiste Daroussin int result;
393*a96ef450SBaptiste Daroussin DIALOG_VARS save;
394*a96ef450SBaptiste Daroussin
395*a96ef450SBaptiste Daroussin dlg_save_vars(&save);
396*a96ef450SBaptiste Daroussin dialog_vars.nocancel = TRUE;
397*a96ef450SBaptiste Daroussin
398*a96ef450SBaptiste Daroussin result = dlg_button_key(exit_code, button, dialog_key, fkey);
399*a96ef450SBaptiste Daroussin
400*a96ef450SBaptiste Daroussin dlg_restore_vars(&save);
401*a96ef450SBaptiste Daroussin return result;
402*a96ef450SBaptiste Daroussin }
403*a96ef450SBaptiste Daroussin
4044c8945a0SNathan Whitehorn #ifdef HAVE_RC_FILE
4054c8945a0SNathan Whitehorn typedef struct {
4064c8945a0SNathan Whitehorn const char *name;
4074c8945a0SNathan Whitehorn int code;
4084c8945a0SNathan Whitehorn } CODENAME;
4094c8945a0SNathan Whitehorn
4102a3e3873SBaptiste Daroussin #define ASCII_NAME(name,code) { #name, code }
4114c8945a0SNathan Whitehorn #define CURSES_NAME(upper) { #upper, KEY_ ## upper }
412f4f33ea0SBaptiste Daroussin #define COUNT_CURSES TableSize(curses_names)
4134c8945a0SNathan Whitehorn static const CODENAME curses_names[] =
4144c8945a0SNathan Whitehorn {
4152a3e3873SBaptiste Daroussin ASCII_NAME(ESC, '\033'),
4162a3e3873SBaptiste Daroussin ASCII_NAME(CR, '\r'),
4172a3e3873SBaptiste Daroussin ASCII_NAME(LF, '\n'),
4182a3e3873SBaptiste Daroussin ASCII_NAME(FF, '\f'),
4192a3e3873SBaptiste Daroussin ASCII_NAME(TAB, '\t'),
4202a3e3873SBaptiste Daroussin ASCII_NAME(DEL, '\177'),
4212a3e3873SBaptiste Daroussin
4224c8945a0SNathan Whitehorn CURSES_NAME(DOWN),
4234c8945a0SNathan Whitehorn CURSES_NAME(UP),
4244c8945a0SNathan Whitehorn CURSES_NAME(LEFT),
4254c8945a0SNathan Whitehorn CURSES_NAME(RIGHT),
4264c8945a0SNathan Whitehorn CURSES_NAME(HOME),
4274c8945a0SNathan Whitehorn CURSES_NAME(BACKSPACE),
4284c8945a0SNathan Whitehorn CURSES_NAME(F0),
4294c8945a0SNathan Whitehorn CURSES_NAME(DL),
4304c8945a0SNathan Whitehorn CURSES_NAME(IL),
4314c8945a0SNathan Whitehorn CURSES_NAME(DC),
4324c8945a0SNathan Whitehorn CURSES_NAME(IC),
4334c8945a0SNathan Whitehorn CURSES_NAME(EIC),
4344c8945a0SNathan Whitehorn CURSES_NAME(CLEAR),
4354c8945a0SNathan Whitehorn CURSES_NAME(EOS),
4364c8945a0SNathan Whitehorn CURSES_NAME(EOL),
4374c8945a0SNathan Whitehorn CURSES_NAME(SF),
4384c8945a0SNathan Whitehorn CURSES_NAME(SR),
4394c8945a0SNathan Whitehorn CURSES_NAME(NPAGE),
4404c8945a0SNathan Whitehorn CURSES_NAME(PPAGE),
4414c8945a0SNathan Whitehorn CURSES_NAME(STAB),
4424c8945a0SNathan Whitehorn CURSES_NAME(CTAB),
4434c8945a0SNathan Whitehorn CURSES_NAME(CATAB),
4444c8945a0SNathan Whitehorn CURSES_NAME(ENTER),
4454c8945a0SNathan Whitehorn CURSES_NAME(PRINT),
4464c8945a0SNathan Whitehorn CURSES_NAME(LL),
4474c8945a0SNathan Whitehorn CURSES_NAME(A1),
4484c8945a0SNathan Whitehorn CURSES_NAME(A3),
4494c8945a0SNathan Whitehorn CURSES_NAME(B2),
4504c8945a0SNathan Whitehorn CURSES_NAME(C1),
4514c8945a0SNathan Whitehorn CURSES_NAME(C3),
4524c8945a0SNathan Whitehorn CURSES_NAME(BTAB),
4534c8945a0SNathan Whitehorn CURSES_NAME(BEG),
4544c8945a0SNathan Whitehorn CURSES_NAME(CANCEL),
4554c8945a0SNathan Whitehorn CURSES_NAME(CLOSE),
4564c8945a0SNathan Whitehorn CURSES_NAME(COMMAND),
4574c8945a0SNathan Whitehorn CURSES_NAME(COPY),
4584c8945a0SNathan Whitehorn CURSES_NAME(CREATE),
4594c8945a0SNathan Whitehorn CURSES_NAME(END),
4604c8945a0SNathan Whitehorn CURSES_NAME(EXIT),
4614c8945a0SNathan Whitehorn CURSES_NAME(FIND),
4624c8945a0SNathan Whitehorn CURSES_NAME(HELP),
4634c8945a0SNathan Whitehorn CURSES_NAME(MARK),
4644c8945a0SNathan Whitehorn CURSES_NAME(MESSAGE),
4654c8945a0SNathan Whitehorn CURSES_NAME(MOVE),
4664c8945a0SNathan Whitehorn CURSES_NAME(NEXT),
4674c8945a0SNathan Whitehorn CURSES_NAME(OPEN),
4684c8945a0SNathan Whitehorn CURSES_NAME(OPTIONS),
4694c8945a0SNathan Whitehorn CURSES_NAME(PREVIOUS),
4704c8945a0SNathan Whitehorn CURSES_NAME(REDO),
4714c8945a0SNathan Whitehorn CURSES_NAME(REFERENCE),
4724c8945a0SNathan Whitehorn CURSES_NAME(REFRESH),
4734c8945a0SNathan Whitehorn CURSES_NAME(REPLACE),
4744c8945a0SNathan Whitehorn CURSES_NAME(RESTART),
4754c8945a0SNathan Whitehorn CURSES_NAME(RESUME),
4764c8945a0SNathan Whitehorn CURSES_NAME(SAVE),
4774c8945a0SNathan Whitehorn CURSES_NAME(SBEG),
4784c8945a0SNathan Whitehorn CURSES_NAME(SCANCEL),
4794c8945a0SNathan Whitehorn CURSES_NAME(SCOMMAND),
4804c8945a0SNathan Whitehorn CURSES_NAME(SCOPY),
4814c8945a0SNathan Whitehorn CURSES_NAME(SCREATE),
4824c8945a0SNathan Whitehorn CURSES_NAME(SDC),
4834c8945a0SNathan Whitehorn CURSES_NAME(SDL),
4844c8945a0SNathan Whitehorn CURSES_NAME(SELECT),
4854c8945a0SNathan Whitehorn CURSES_NAME(SEND),
4864c8945a0SNathan Whitehorn CURSES_NAME(SEOL),
4874c8945a0SNathan Whitehorn CURSES_NAME(SEXIT),
4884c8945a0SNathan Whitehorn CURSES_NAME(SFIND),
4894c8945a0SNathan Whitehorn CURSES_NAME(SHELP),
4904c8945a0SNathan Whitehorn CURSES_NAME(SHOME),
4914c8945a0SNathan Whitehorn CURSES_NAME(SIC),
4924c8945a0SNathan Whitehorn CURSES_NAME(SLEFT),
4934c8945a0SNathan Whitehorn CURSES_NAME(SMESSAGE),
4944c8945a0SNathan Whitehorn CURSES_NAME(SMOVE),
4954c8945a0SNathan Whitehorn CURSES_NAME(SNEXT),
4964c8945a0SNathan Whitehorn CURSES_NAME(SOPTIONS),
4974c8945a0SNathan Whitehorn CURSES_NAME(SPREVIOUS),
4984c8945a0SNathan Whitehorn CURSES_NAME(SPRINT),
4994c8945a0SNathan Whitehorn CURSES_NAME(SREDO),
5004c8945a0SNathan Whitehorn CURSES_NAME(SREPLACE),
5014c8945a0SNathan Whitehorn CURSES_NAME(SRIGHT),
5024c8945a0SNathan Whitehorn CURSES_NAME(SRSUME),
5034c8945a0SNathan Whitehorn CURSES_NAME(SSAVE),
5044c8945a0SNathan Whitehorn CURSES_NAME(SSUSPEND),
5054c8945a0SNathan Whitehorn CURSES_NAME(SUNDO),
5064c8945a0SNathan Whitehorn CURSES_NAME(SUSPEND),
5074c8945a0SNathan Whitehorn CURSES_NAME(UNDO),
5084c8945a0SNathan Whitehorn };
5094c8945a0SNathan Whitehorn
5104c8945a0SNathan Whitehorn #define DIALOG_NAME(upper) { #upper, DLGK_ ## upper }
511f4f33ea0SBaptiste Daroussin #define COUNT_DIALOG TableSize(dialog_names)
5124c8945a0SNathan Whitehorn static const CODENAME dialog_names[] =
5134c8945a0SNathan Whitehorn {
5144c8945a0SNathan Whitehorn DIALOG_NAME(OK),
5154c8945a0SNathan Whitehorn DIALOG_NAME(CANCEL),
5164c8945a0SNathan Whitehorn DIALOG_NAME(EXTRA),
5174c8945a0SNathan Whitehorn DIALOG_NAME(HELP),
5184c8945a0SNathan Whitehorn DIALOG_NAME(ESC),
5194c8945a0SNathan Whitehorn DIALOG_NAME(PAGE_FIRST),
5204c8945a0SNathan Whitehorn DIALOG_NAME(PAGE_LAST),
5214c8945a0SNathan Whitehorn DIALOG_NAME(PAGE_NEXT),
5224c8945a0SNathan Whitehorn DIALOG_NAME(PAGE_PREV),
5234c8945a0SNathan Whitehorn DIALOG_NAME(ITEM_FIRST),
5244c8945a0SNathan Whitehorn DIALOG_NAME(ITEM_LAST),
5254c8945a0SNathan Whitehorn DIALOG_NAME(ITEM_NEXT),
5264c8945a0SNathan Whitehorn DIALOG_NAME(ITEM_PREV),
5274c8945a0SNathan Whitehorn DIALOG_NAME(FIELD_FIRST),
5284c8945a0SNathan Whitehorn DIALOG_NAME(FIELD_LAST),
5294c8945a0SNathan Whitehorn DIALOG_NAME(FIELD_NEXT),
5304c8945a0SNathan Whitehorn DIALOG_NAME(FIELD_PREV),
5312a3e3873SBaptiste Daroussin DIALOG_NAME(FORM_FIRST),
5322a3e3873SBaptiste Daroussin DIALOG_NAME(FORM_LAST),
5332a3e3873SBaptiste Daroussin DIALOG_NAME(FORM_NEXT),
5342a3e3873SBaptiste Daroussin DIALOG_NAME(FORM_PREV),
5354c8945a0SNathan Whitehorn DIALOG_NAME(GRID_UP),
5364c8945a0SNathan Whitehorn DIALOG_NAME(GRID_DOWN),
5374c8945a0SNathan Whitehorn DIALOG_NAME(GRID_LEFT),
5384c8945a0SNathan Whitehorn DIALOG_NAME(GRID_RIGHT),
5394c8945a0SNathan Whitehorn DIALOG_NAME(DELETE_LEFT),
5404c8945a0SNathan Whitehorn DIALOG_NAME(DELETE_RIGHT),
5414c8945a0SNathan Whitehorn DIALOG_NAME(DELETE_ALL),
5424c8945a0SNathan Whitehorn DIALOG_NAME(ENTER),
5434c8945a0SNathan Whitehorn DIALOG_NAME(BEGIN),
5444c8945a0SNathan Whitehorn DIALOG_NAME(FINAL),
5452a3e3873SBaptiste Daroussin DIALOG_NAME(SELECT),
5462a3e3873SBaptiste Daroussin DIALOG_NAME(HELPFILE),
547f4f33ea0SBaptiste Daroussin DIALOG_NAME(TRACE),
548*a96ef450SBaptiste Daroussin DIALOG_NAME(TOGGLE),
549*a96ef450SBaptiste Daroussin DIALOG_NAME(LEAVE)
5504c8945a0SNathan Whitehorn };
5514c8945a0SNathan Whitehorn
552f4f33ea0SBaptiste Daroussin #define MAP2(letter,actual) { letter, actual }
553f4f33ea0SBaptiste Daroussin
554f4f33ea0SBaptiste Daroussin static const struct {
555f4f33ea0SBaptiste Daroussin int letter;
556f4f33ea0SBaptiste Daroussin int actual;
557f4f33ea0SBaptiste Daroussin } escaped_letters[] = {
558f4f33ea0SBaptiste Daroussin
559f4f33ea0SBaptiste Daroussin MAP2('a', DLG_CTRL('G')),
560f4f33ea0SBaptiste Daroussin MAP2('b', DLG_CTRL('H')),
561f4f33ea0SBaptiste Daroussin MAP2('f', DLG_CTRL('L')),
562f4f33ea0SBaptiste Daroussin MAP2('n', DLG_CTRL('J')),
563f4f33ea0SBaptiste Daroussin MAP2('r', DLG_CTRL('M')),
564f4f33ea0SBaptiste Daroussin MAP2('s', CHR_SPACE),
565f4f33ea0SBaptiste Daroussin MAP2('t', DLG_CTRL('I')),
566f4f33ea0SBaptiste Daroussin MAP2('\\', '\\'),
567f4f33ea0SBaptiste Daroussin };
568f4f33ea0SBaptiste Daroussin
569f4f33ea0SBaptiste Daroussin #undef MAP2
570f4f33ea0SBaptiste Daroussin
5714c8945a0SNathan Whitehorn static char *
skip_white(char * s)5724c8945a0SNathan Whitehorn skip_white(char *s)
5734c8945a0SNathan Whitehorn {
5744c8945a0SNathan Whitehorn while (*s != '\0' && isspace(UCH(*s)))
5754c8945a0SNathan Whitehorn ++s;
5764c8945a0SNathan Whitehorn return s;
5774c8945a0SNathan Whitehorn }
5784c8945a0SNathan Whitehorn
5794c8945a0SNathan Whitehorn static char *
skip_black(char * s)5804c8945a0SNathan Whitehorn skip_black(char *s)
5814c8945a0SNathan Whitehorn {
5824c8945a0SNathan Whitehorn while (*s != '\0' && !isspace(UCH(*s)))
5834c8945a0SNathan Whitehorn ++s;
5844c8945a0SNathan Whitehorn return s;
5854c8945a0SNathan Whitehorn }
5864c8945a0SNathan Whitehorn
5874c8945a0SNathan Whitehorn /*
5884c8945a0SNathan Whitehorn * Find a user-defined binding, given the curses key code.
5894c8945a0SNathan Whitehorn */
5904c8945a0SNathan Whitehorn static DLG_KEYS_BINDING *
find_binding(char * widget,int curses_key)5914c8945a0SNathan Whitehorn find_binding(char *widget, int curses_key)
5924c8945a0SNathan Whitehorn {
5934c8945a0SNathan Whitehorn LIST_BINDINGS *p;
5944c8945a0SNathan Whitehorn DLG_KEYS_BINDING *result = 0;
5954c8945a0SNathan Whitehorn
5964c8945a0SNathan Whitehorn for (p = all_bindings; p != 0; p = p->link) {
5974c8945a0SNathan Whitehorn if (p->win == 0
5984c8945a0SNathan Whitehorn && !dlg_strcmp(p->name, widget)
5994c8945a0SNathan Whitehorn && p->binding->curses_key == curses_key) {
6004c8945a0SNathan Whitehorn result = p->binding;
6014c8945a0SNathan Whitehorn break;
6024c8945a0SNathan Whitehorn }
6034c8945a0SNathan Whitehorn }
6044c8945a0SNathan Whitehorn return result;
6054c8945a0SNathan Whitehorn }
6064c8945a0SNathan Whitehorn
6074c8945a0SNathan Whitehorn /*
6084c8945a0SNathan Whitehorn * Built-in bindings have a nonzero "win" member, and the associated binding
6094c8945a0SNathan Whitehorn * table can have more than one entry. We keep those last, since lookups will
6104c8945a0SNathan Whitehorn * find the user-defined bindings first and use those.
6114c8945a0SNathan Whitehorn *
6124c8945a0SNathan Whitehorn * Sort "*" (all-widgets) entries past named widgets, since those are less
6134c8945a0SNathan Whitehorn * specific.
6144c8945a0SNathan Whitehorn */
6154c8945a0SNathan Whitehorn static int
compare_bindings(LIST_BINDINGS * a,LIST_BINDINGS * b)6164c8945a0SNathan Whitehorn compare_bindings(LIST_BINDINGS * a, LIST_BINDINGS * b)
6174c8945a0SNathan Whitehorn {
6184c8945a0SNathan Whitehorn int result = 0;
6194c8945a0SNathan Whitehorn if (a->win == b->win) {
6204c8945a0SNathan Whitehorn if (!strcmp(a->name, b->name)) {
6214c8945a0SNathan Whitehorn result = a->binding[0].curses_key - b->binding[0].curses_key;
6222a3e3873SBaptiste Daroussin } else if (!strcmp(b->name, WILDNAME)) {
6234c8945a0SNathan Whitehorn result = -1;
6242a3e3873SBaptiste Daroussin } else if (!strcmp(a->name, WILDNAME)) {
6254c8945a0SNathan Whitehorn result = 1;
6264c8945a0SNathan Whitehorn } else {
6274c8945a0SNathan Whitehorn result = dlg_strcmp(a->name, b->name);
6284c8945a0SNathan Whitehorn }
6294c8945a0SNathan Whitehorn } else if (b->win) {
6304c8945a0SNathan Whitehorn result = -1;
6314c8945a0SNathan Whitehorn } else {
6324c8945a0SNathan Whitehorn result = 1;
6334c8945a0SNathan Whitehorn }
6344c8945a0SNathan Whitehorn return result;
6354c8945a0SNathan Whitehorn }
6364c8945a0SNathan Whitehorn
6374c8945a0SNathan Whitehorn /*
6384c8945a0SNathan Whitehorn * Find a user-defined binding, given the curses key code. If it does not
6394c8945a0SNathan Whitehorn * exist, create a new one, inserting it into the linked list, keeping it
6404c8945a0SNathan Whitehorn * sorted to simplify lookups for user-defined bindings that can override
6414c8945a0SNathan Whitehorn * the built-in bindings.
6424c8945a0SNathan Whitehorn */
6434c8945a0SNathan Whitehorn static DLG_KEYS_BINDING *
make_binding(char * widget,int curses_key,int is_function,int dialog_key)6444c8945a0SNathan Whitehorn make_binding(char *widget, int curses_key, int is_function, int dialog_key)
6454c8945a0SNathan Whitehorn {
6464c8945a0SNathan Whitehorn LIST_BINDINGS *entry = 0;
6474c8945a0SNathan Whitehorn DLG_KEYS_BINDING *data = 0;
6484c8945a0SNathan Whitehorn char *name;
6494c8945a0SNathan Whitehorn DLG_KEYS_BINDING *result = find_binding(widget, curses_key);
6504c8945a0SNathan Whitehorn
6514c8945a0SNathan Whitehorn if (result == 0
6524c8945a0SNathan Whitehorn && (entry = dlg_calloc(LIST_BINDINGS, 1)) != 0
6534c8945a0SNathan Whitehorn && (data = dlg_calloc(DLG_KEYS_BINDING, 2)) != 0
6544c8945a0SNathan Whitehorn && (name = dlg_strclone(widget)) != 0) {
655*a96ef450SBaptiste Daroussin LIST_BINDINGS *p, *q;
6564c8945a0SNathan Whitehorn
6574c8945a0SNathan Whitehorn entry->name = name;
6584c8945a0SNathan Whitehorn entry->binding = data;
6594c8945a0SNathan Whitehorn
6604c8945a0SNathan Whitehorn data[0].is_function_key = is_function;
6614c8945a0SNathan Whitehorn data[0].curses_key = curses_key;
6624c8945a0SNathan Whitehorn data[0].dialog_key = dialog_key;
6634c8945a0SNathan Whitehorn
6644c8945a0SNathan Whitehorn data[1] = end_keys_binding;
6654c8945a0SNathan Whitehorn
6664c8945a0SNathan Whitehorn for (p = all_bindings, q = 0; p != 0; q = p, p = p->link) {
6674c8945a0SNathan Whitehorn if (compare_bindings(entry, p) < 0) {
6684c8945a0SNathan Whitehorn break;
6694c8945a0SNathan Whitehorn }
6704c8945a0SNathan Whitehorn }
6714c8945a0SNathan Whitehorn if (q != 0) {
6724c8945a0SNathan Whitehorn q->link = entry;
6734c8945a0SNathan Whitehorn } else {
6744c8945a0SNathan Whitehorn all_bindings = entry;
6754c8945a0SNathan Whitehorn }
6764c8945a0SNathan Whitehorn if (p != 0) {
6774c8945a0SNathan Whitehorn entry->link = p;
6784c8945a0SNathan Whitehorn }
6794c8945a0SNathan Whitehorn result = data;
6804c8945a0SNathan Whitehorn } else if (entry != 0) {
6814c8945a0SNathan Whitehorn free(entry);
6824c8945a0SNathan Whitehorn if (data)
6834c8945a0SNathan Whitehorn free(data);
6844c8945a0SNathan Whitehorn }
6854c8945a0SNathan Whitehorn
6864c8945a0SNathan Whitehorn return result;
6874c8945a0SNathan Whitehorn }
6884c8945a0SNathan Whitehorn
689f4f33ea0SBaptiste Daroussin static int
decode_escaped(char ** string)690f4f33ea0SBaptiste Daroussin decode_escaped(char **string)
691f4f33ea0SBaptiste Daroussin {
692f4f33ea0SBaptiste Daroussin int result = 0;
693f4f33ea0SBaptiste Daroussin
694f4f33ea0SBaptiste Daroussin if (IsOctal(**string)) {
695f4f33ea0SBaptiste Daroussin int limit = 3;
696f4f33ea0SBaptiste Daroussin while (limit-- > 0 && IsOctal(**string)) {
697f4f33ea0SBaptiste Daroussin int ch = (**string);
698f4f33ea0SBaptiste Daroussin *string += 1;
699f4f33ea0SBaptiste Daroussin result = (result << 3) | (ch - '0');
700f4f33ea0SBaptiste Daroussin }
701f4f33ea0SBaptiste Daroussin } else {
702*a96ef450SBaptiste Daroussin unsigned n;
703*a96ef450SBaptiste Daroussin
704f4f33ea0SBaptiste Daroussin for (n = 0; n < TableSize(escaped_letters); ++n) {
705f4f33ea0SBaptiste Daroussin if (**string == escaped_letters[n].letter) {
706f4f33ea0SBaptiste Daroussin *string += 1;
707f4f33ea0SBaptiste Daroussin result = escaped_letters[n].actual;
708f4f33ea0SBaptiste Daroussin break;
709f4f33ea0SBaptiste Daroussin }
710f4f33ea0SBaptiste Daroussin }
711f4f33ea0SBaptiste Daroussin }
712f4f33ea0SBaptiste Daroussin return result;
713f4f33ea0SBaptiste Daroussin }
714f4f33ea0SBaptiste Daroussin
715f4f33ea0SBaptiste Daroussin static char *
encode_escaped(int value)716f4f33ea0SBaptiste Daroussin encode_escaped(int value)
717f4f33ea0SBaptiste Daroussin {
718f4f33ea0SBaptiste Daroussin static char result[80];
719f4f33ea0SBaptiste Daroussin unsigned n;
720f4f33ea0SBaptiste Daroussin bool found = FALSE;
721f4f33ea0SBaptiste Daroussin for (n = 0; n < TableSize(escaped_letters); ++n) {
722f4f33ea0SBaptiste Daroussin if (value == escaped_letters[n].actual) {
723f4f33ea0SBaptiste Daroussin found = TRUE;
724f4f33ea0SBaptiste Daroussin sprintf(result, "%c", escaped_letters[n].letter);
725f4f33ea0SBaptiste Daroussin break;
726f4f33ea0SBaptiste Daroussin }
727f4f33ea0SBaptiste Daroussin }
728f4f33ea0SBaptiste Daroussin if (!found) {
729f4f33ea0SBaptiste Daroussin sprintf(result, "%03o", value & 0xff);
730f4f33ea0SBaptiste Daroussin }
731f4f33ea0SBaptiste Daroussin return result;
732f4f33ea0SBaptiste Daroussin }
733f4f33ea0SBaptiste Daroussin
7344c8945a0SNathan Whitehorn /*
735f4f33ea0SBaptiste Daroussin * Parse the parameters of the "bindkey" configuration-file entry. This
7364c8945a0SNathan Whitehorn * expects widget name which may be "*", followed by curses key definition and
7374c8945a0SNathan Whitehorn * then dialog key definition.
7384c8945a0SNathan Whitehorn *
7394c8945a0SNathan Whitehorn * The curses key "should" be one of the names (ignoring case) from
7404c8945a0SNathan Whitehorn * curses_names[], but may also be a single control character (prefix "^" or
7414c8945a0SNathan Whitehorn * "~" depending on whether it is C0 or C1), or an escaped single character.
7424c8945a0SNathan Whitehorn * Binding a printable character with dialog is possible but not useful.
7434c8945a0SNathan Whitehorn *
7444c8945a0SNathan Whitehorn * The dialog key must be one of the names from dialog_names[].
7454c8945a0SNathan Whitehorn */
7464c8945a0SNathan Whitehorn int
dlg_parse_bindkey(char * params)7474c8945a0SNathan Whitehorn dlg_parse_bindkey(char *params)
7484c8945a0SNathan Whitehorn {
7494c8945a0SNathan Whitehorn char *p = skip_white(params);
7504c8945a0SNathan Whitehorn int result = FALSE;
7514c8945a0SNathan Whitehorn char *widget;
7524c8945a0SNathan Whitehorn int curses_key;
7534c8945a0SNathan Whitehorn int dialog_key;
7544c8945a0SNathan Whitehorn
7554c8945a0SNathan Whitehorn curses_key = -1;
7564c8945a0SNathan Whitehorn dialog_key = -1;
7574c8945a0SNathan Whitehorn widget = p;
7584c8945a0SNathan Whitehorn
7594c8945a0SNathan Whitehorn p = skip_black(p);
7604c8945a0SNathan Whitehorn if (p != widget && *p != '\0') {
761*a96ef450SBaptiste Daroussin char *q;
762*a96ef450SBaptiste Daroussin unsigned xx;
763*a96ef450SBaptiste Daroussin bool escaped = FALSE;
764*a96ef450SBaptiste Daroussin int modified = 0;
765*a96ef450SBaptiste Daroussin int is_function = FALSE;
766*a96ef450SBaptiste Daroussin
7674c8945a0SNathan Whitehorn *p++ = '\0';
7682a3e3873SBaptiste Daroussin p = skip_white(p);
7694c8945a0SNathan Whitehorn q = p;
7704c8945a0SNathan Whitehorn while (*p != '\0' && curses_key < 0) {
7714c8945a0SNathan Whitehorn if (escaped) {
7724c8945a0SNathan Whitehorn escaped = FALSE;
773f4f33ea0SBaptiste Daroussin curses_key = decode_escaped(&p);
774f4f33ea0SBaptiste Daroussin } else if (*p == CHR_BACKSLASH) {
7754c8945a0SNathan Whitehorn escaped = TRUE;
7764c8945a0SNathan Whitehorn } else if (modified) {
7774c8945a0SNathan Whitehorn if (*p == '?') {
7784c8945a0SNathan Whitehorn curses_key = ((modified == '^')
7794c8945a0SNathan Whitehorn ? 127
7804c8945a0SNathan Whitehorn : 255);
7814c8945a0SNathan Whitehorn } else {
7824c8945a0SNathan Whitehorn curses_key = ((modified == '^')
7834c8945a0SNathan Whitehorn ? (*p & 0x1f)
7844c8945a0SNathan Whitehorn : ((*p & 0x1f) | 0x80));
7854c8945a0SNathan Whitehorn }
7864c8945a0SNathan Whitehorn } else if (*p == '^') {
7874c8945a0SNathan Whitehorn modified = *p;
7884c8945a0SNathan Whitehorn } else if (*p == '~') {
7894c8945a0SNathan Whitehorn modified = *p;
7904c8945a0SNathan Whitehorn } else if (isspace(UCH(*p))) {
7914c8945a0SNathan Whitehorn break;
7924c8945a0SNathan Whitehorn }
7934c8945a0SNathan Whitehorn ++p;
7944c8945a0SNathan Whitehorn }
7954c8945a0SNathan Whitehorn if (!isspace(UCH(*p))) {
7964c8945a0SNathan Whitehorn ;
7974c8945a0SNathan Whitehorn } else {
7984c8945a0SNathan Whitehorn *p++ = '\0';
7994c8945a0SNathan Whitehorn if (curses_key < 0) {
8004c8945a0SNathan Whitehorn char fprefix[2];
8014c8945a0SNathan Whitehorn char check[2];
8024c8945a0SNathan Whitehorn int keynumber;
803*a96ef450SBaptiste Daroussin if (sscanf(q, "%1[Ff]%d%c", fprefix, &keynumber, check) == 2) {
8044c8945a0SNathan Whitehorn curses_key = KEY_F(keynumber);
8054c8945a0SNathan Whitehorn is_function = TRUE;
8064c8945a0SNathan Whitehorn } else {
8074c8945a0SNathan Whitehorn for (xx = 0; xx < COUNT_CURSES; ++xx) {
8084c8945a0SNathan Whitehorn if (!dlg_strcmp(curses_names[xx].name, q)) {
8094c8945a0SNathan Whitehorn curses_key = curses_names[xx].code;
8102a3e3873SBaptiste Daroussin is_function = (curses_key >= KEY_MIN);
8114c8945a0SNathan Whitehorn break;
8124c8945a0SNathan Whitehorn }
8134c8945a0SNathan Whitehorn }
8144c8945a0SNathan Whitehorn }
8154c8945a0SNathan Whitehorn }
8164c8945a0SNathan Whitehorn }
8174c8945a0SNathan Whitehorn q = skip_white(p);
8184c8945a0SNathan Whitehorn p = skip_black(q);
8194c8945a0SNathan Whitehorn if (p != q) {
8204c8945a0SNathan Whitehorn for (xx = 0; xx < COUNT_DIALOG; ++xx) {
8214c8945a0SNathan Whitehorn if (!dlg_strcmp(dialog_names[xx].name, q)) {
8224c8945a0SNathan Whitehorn dialog_key = dialog_names[xx].code;
8234c8945a0SNathan Whitehorn break;
8244c8945a0SNathan Whitehorn }
8254c8945a0SNathan Whitehorn }
8264c8945a0SNathan Whitehorn }
8274c8945a0SNathan Whitehorn if (*widget != '\0'
8284c8945a0SNathan Whitehorn && curses_key >= 0
8294c8945a0SNathan Whitehorn && dialog_key >= 0
8304c8945a0SNathan Whitehorn && make_binding(widget, curses_key, is_function, dialog_key) != 0) {
8314c8945a0SNathan Whitehorn result = TRUE;
8324c8945a0SNathan Whitehorn }
8334c8945a0SNathan Whitehorn }
8344c8945a0SNathan Whitehorn return result;
8354c8945a0SNathan Whitehorn }
8364c8945a0SNathan Whitehorn
8374c8945a0SNathan Whitehorn static void
dump_curses_key(FILE * fp,int curses_key)8384c8945a0SNathan Whitehorn dump_curses_key(FILE *fp, int curses_key)
8394c8945a0SNathan Whitehorn {
8404c8945a0SNathan Whitehorn if (curses_key > KEY_MIN) {
8414c8945a0SNathan Whitehorn unsigned n;
8424c8945a0SNathan Whitehorn bool found = FALSE;
8434c8945a0SNathan Whitehorn for (n = 0; n < COUNT_CURSES; ++n) {
8444c8945a0SNathan Whitehorn if (curses_names[n].code == curses_key) {
8454c8945a0SNathan Whitehorn fprintf(fp, "%s", curses_names[n].name);
8464c8945a0SNathan Whitehorn found = TRUE;
8474c8945a0SNathan Whitehorn break;
8484c8945a0SNathan Whitehorn }
8494c8945a0SNathan Whitehorn }
8504c8945a0SNathan Whitehorn if (!found) {
851f4f33ea0SBaptiste Daroussin #ifdef KEY_MOUSE
852f4f33ea0SBaptiste Daroussin if (is_DLGK_MOUSE(curses_key)) {
853f4f33ea0SBaptiste Daroussin fprintf(fp, "MOUSE-");
854f4f33ea0SBaptiste Daroussin dump_curses_key(fp, curses_key - M_EVENT);
855f4f33ea0SBaptiste Daroussin } else
856f4f33ea0SBaptiste Daroussin #endif
8574c8945a0SNathan Whitehorn if (curses_key >= KEY_F(0)) {
8584c8945a0SNathan Whitehorn fprintf(fp, "F%d", curses_key - KEY_F(0));
8594c8945a0SNathan Whitehorn } else {
8604c8945a0SNathan Whitehorn fprintf(fp, "curses%d", curses_key);
8614c8945a0SNathan Whitehorn }
8624c8945a0SNathan Whitehorn }
8634c8945a0SNathan Whitehorn } else if (curses_key >= 0 && curses_key < 32) {
8644c8945a0SNathan Whitehorn fprintf(fp, "^%c", curses_key + 64);
8654c8945a0SNathan Whitehorn } else if (curses_key == 127) {
8664c8945a0SNathan Whitehorn fprintf(fp, "^?");
8674c8945a0SNathan Whitehorn } else if (curses_key >= 128 && curses_key < 160) {
8684c8945a0SNathan Whitehorn fprintf(fp, "~%c", curses_key - 64);
8694c8945a0SNathan Whitehorn } else if (curses_key == 255) {
8704c8945a0SNathan Whitehorn fprintf(fp, "~?");
871f4f33ea0SBaptiste Daroussin } else if (curses_key > 32 &&
872f4f33ea0SBaptiste Daroussin curses_key < 127 &&
873f4f33ea0SBaptiste Daroussin curses_key != CHR_BACKSLASH) {
874f4f33ea0SBaptiste Daroussin fprintf(fp, "%c", curses_key);
8754c8945a0SNathan Whitehorn } else {
876f4f33ea0SBaptiste Daroussin fprintf(fp, "%c%s", CHR_BACKSLASH, encode_escaped(curses_key));
8774c8945a0SNathan Whitehorn }
8784c8945a0SNathan Whitehorn }
8794c8945a0SNathan Whitehorn
8804c8945a0SNathan Whitehorn static void
dump_dialog_key(FILE * fp,int dialog_key)8814c8945a0SNathan Whitehorn dump_dialog_key(FILE *fp, int dialog_key)
8824c8945a0SNathan Whitehorn {
8834c8945a0SNathan Whitehorn unsigned n;
8844c8945a0SNathan Whitehorn bool found = FALSE;
8854c8945a0SNathan Whitehorn for (n = 0; n < COUNT_DIALOG; ++n) {
8864c8945a0SNathan Whitehorn if (dialog_names[n].code == dialog_key) {
8874c8945a0SNathan Whitehorn fputs(dialog_names[n].name, fp);
8884c8945a0SNathan Whitehorn found = TRUE;
8894c8945a0SNathan Whitehorn break;
8904c8945a0SNathan Whitehorn }
8914c8945a0SNathan Whitehorn }
8924c8945a0SNathan Whitehorn if (!found) {
8934c8945a0SNathan Whitehorn fprintf(fp, "dialog%d", dialog_key);
8944c8945a0SNathan Whitehorn }
8954c8945a0SNathan Whitehorn }
8964c8945a0SNathan Whitehorn
8974c8945a0SNathan Whitehorn static void
dump_one_binding(FILE * fp,WINDOW * win,const char * widget,DLG_KEYS_BINDING * binding)898f4f33ea0SBaptiste Daroussin dump_one_binding(FILE *fp,
899f4f33ea0SBaptiste Daroussin WINDOW *win,
900f4f33ea0SBaptiste Daroussin const char *widget,
901f4f33ea0SBaptiste Daroussin DLG_KEYS_BINDING * binding)
9024c8945a0SNathan Whitehorn {
903f4f33ea0SBaptiste Daroussin int actual;
904f4f33ea0SBaptiste Daroussin int fkey = (binding->curses_key > 255);
905f4f33ea0SBaptiste Daroussin
9064c8945a0SNathan Whitehorn fprintf(fp, "bindkey %s ", widget);
9074c8945a0SNathan Whitehorn dump_curses_key(fp, binding->curses_key);
9084c8945a0SNathan Whitehorn fputc(' ', fp);
9094c8945a0SNathan Whitehorn dump_dialog_key(fp, binding->dialog_key);
910f4f33ea0SBaptiste Daroussin actual = dlg_lookup_key(win, binding->curses_key, &fkey);
911f4f33ea0SBaptiste Daroussin #ifdef KEY_MOUSE
912f4f33ea0SBaptiste Daroussin if (is_DLGK_MOUSE(binding->curses_key) && is_DLGK_MOUSE(actual)) {
913f4f33ea0SBaptiste Daroussin ; /* EMPTY */
914f4f33ea0SBaptiste Daroussin } else
915f4f33ea0SBaptiste Daroussin #endif
916f4f33ea0SBaptiste Daroussin if (actual != binding->dialog_key) {
917f4f33ea0SBaptiste Daroussin fprintf(fp, "\t# overridden by ");
918f4f33ea0SBaptiste Daroussin dump_dialog_key(fp, actual);
919f4f33ea0SBaptiste Daroussin }
9204c8945a0SNathan Whitehorn fputc('\n', fp);
9214c8945a0SNathan Whitehorn }
9224c8945a0SNathan Whitehorn
9232a3e3873SBaptiste Daroussin /*
9242a3e3873SBaptiste Daroussin * Dump bindings for the given window. If it is a null, then this dumps the
9252a3e3873SBaptiste Daroussin * initial bindings which were loaded from the rc-file that are used as
9262a3e3873SBaptiste Daroussin * overall defaults.
9272a3e3873SBaptiste Daroussin */
9282a3e3873SBaptiste Daroussin void
dlg_dump_window_keys(FILE * fp,WINDOW * win)9292a3e3873SBaptiste Daroussin dlg_dump_window_keys(FILE *fp, WINDOW *win)
9302a3e3873SBaptiste Daroussin {
9312a3e3873SBaptiste Daroussin if (fp != 0) {
9322a3e3873SBaptiste Daroussin LIST_BINDINGS *p;
9332a3e3873SBaptiste Daroussin DLG_KEYS_BINDING *q;
9342a3e3873SBaptiste Daroussin const char *last = "";
9352a3e3873SBaptiste Daroussin
9362a3e3873SBaptiste Daroussin for (p = all_bindings; p != 0; p = p->link) {
9372a3e3873SBaptiste Daroussin if (p->win == win) {
9382a3e3873SBaptiste Daroussin if (dlg_strcmp(last, p->name)) {
939f4f33ea0SBaptiste Daroussin fprintf(fp, "# key bindings for %s widgets%s\n",
940f4f33ea0SBaptiste Daroussin !strcmp(p->name, WILDNAME) ? "all" : p->name,
941f4f33ea0SBaptiste Daroussin win == 0 ? " (user-defined)" : "");
9422a3e3873SBaptiste Daroussin last = p->name;
9432a3e3873SBaptiste Daroussin }
9442a3e3873SBaptiste Daroussin for (q = p->binding; q->is_function_key >= 0; ++q) {
945f4f33ea0SBaptiste Daroussin dump_one_binding(fp, win, p->name, q);
9462a3e3873SBaptiste Daroussin }
9472a3e3873SBaptiste Daroussin }
9482a3e3873SBaptiste Daroussin }
9492a3e3873SBaptiste Daroussin }
9502a3e3873SBaptiste Daroussin }
9512a3e3873SBaptiste Daroussin
9522a3e3873SBaptiste Daroussin /*
9532a3e3873SBaptiste Daroussin * Dump all of the bindings which are not specific to a given widget, i.e.,
9542a3e3873SBaptiste Daroussin * the "win" member is null.
9552a3e3873SBaptiste Daroussin */
9564c8945a0SNathan Whitehorn void
dlg_dump_keys(FILE * fp)9574c8945a0SNathan Whitehorn dlg_dump_keys(FILE *fp)
9584c8945a0SNathan Whitehorn {
9592a3e3873SBaptiste Daroussin if (fp != 0) {
9604c8945a0SNathan Whitehorn LIST_BINDINGS *p;
9614c8945a0SNathan Whitehorn unsigned count = 0;
9624c8945a0SNathan Whitehorn
9634c8945a0SNathan Whitehorn for (p = all_bindings; p != 0; p = p->link) {
9644c8945a0SNathan Whitehorn if (p->win == 0) {
9654c8945a0SNathan Whitehorn ++count;
9664c8945a0SNathan Whitehorn }
9674c8945a0SNathan Whitehorn }
9684c8945a0SNathan Whitehorn if (count != 0) {
9692a3e3873SBaptiste Daroussin dlg_dump_window_keys(fp, 0);
9704c8945a0SNathan Whitehorn }
9714c8945a0SNathan Whitehorn }
9724c8945a0SNathan Whitehorn }
9734c8945a0SNathan Whitehorn #endif /* HAVE_RC_FILE */
974