diff options
Diffstat (limited to 'Build/source/utils/dialog/dialog-1.1-20080819/dlg_keys.c')
-rw-r--r-- | Build/source/utils/dialog/dialog-1.1-20080819/dlg_keys.c | 725 |
1 files changed, 725 insertions, 0 deletions
diff --git a/Build/source/utils/dialog/dialog-1.1-20080819/dlg_keys.c b/Build/source/utils/dialog/dialog-1.1-20080819/dlg_keys.c new file mode 100644 index 00000000000..2a141dbd518 --- /dev/null +++ b/Build/source/utils/dialog/dialog-1.1-20080819/dlg_keys.c @@ -0,0 +1,725 @@ +/* + * $Id: dlg_keys.c,v 1.24 2007/09/30 21:15:42 tom Exp $ + * + * dlg_keys.c -- runtime binding support for dialog + * + * Copyright 2006,2007 Thomas E. Dickey + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License, version 2.1 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to + * Free Software Foundation, Inc. + * 51 Franklin St., Fifth Floor + * Boston, MA 02110, USA. + */ + +#include <dialog.h> +#include <dlg_keys.h> + +#define LIST_BINDINGS struct _list_bindings + +LIST_BINDINGS { + LIST_BINDINGS *link; + WINDOW *win; /* window on which widget gets input */ + const char *name; /* widget name */ + bool buttons; /* true only for dlg_register_buttons() */ + DLG_KEYS_BINDING *binding; /* list of bindings */ +}; + +static LIST_BINDINGS *all_bindings; +static const DLG_KEYS_BINDING end_keys_binding = END_KEYS_BINDING; + +/* + * For a given named widget's window, associate a binding table. + */ +void +dlg_register_window(WINDOW *win, const char *name, DLG_KEYS_BINDING * binding) +{ + LIST_BINDINGS *p, *q; + + for (p = all_bindings, q = 0; p != 0; q = p, p = p->link) { + if (p->win == win && !strcmp(p->name, name)) { + p->binding = binding; + return; + } + } + /* add built-in bindings at the end of the list (see compare_bindings). */ + if ((p = dlg_calloc(LIST_BINDINGS, 1)) != 0) { + p->win = win; + p->name = name; + p->binding = binding; + if (q != 0) + q->link = p; + else + all_bindings = p; + } +} + +/* + * Unlike dlg_lookup_key(), this looks for either widget-builtin or rc-file + * definitions, depending on whether 'win' is null. + */ +static int +key_is_bound(WINDOW *win, const char *name, int curses_key, int function_key) +{ + LIST_BINDINGS *p; + + for (p = all_bindings; p != 0; p = p->link) { + if (p->win == win && !dlg_strcmp(p->name, name)) { + int n; + for (n = 0; p->binding[n].is_function_key >= 0; ++n) { + if (p->binding[n].curses_key == curses_key + && p->binding[n].is_function_key == function_key) { + return TRUE; + } + } + } + } + return FALSE; +} + +/* + * Call this function after dlg_register_window(), for the list of button + * labels associated with the widget. + * + * Ensure that dlg_lookup_key() will not accidentally translate a key that + * we would like to use for a button abbreviation to some other key, e.g., + * h/j/k/l for navigation into a cursor key. Do this by binding the key + * to itself. + * + * See dlg_char_to_button(). + */ +void +dlg_register_buttons(WINDOW *win, const char *name, const char **buttons) +{ + int n; + LIST_BINDINGS *p; + DLG_KEYS_BINDING *q; + + if (buttons == 0) + return; + + for (n = 0; buttons[n] != 0; ++n) { + int curses_key = dlg_button_to_char(buttons[n]); + + /* ignore multibyte characters */ + if (curses_key >= KEY_MIN) + continue; + + /* if it is not bound in the widget, skip it (no conflicts) */ + if (!key_is_bound(win, name, curses_key, FALSE)) + continue; + +#ifdef HAVE_RC_FILE + /* if it is bound in the rc-file, skip it */ + if (key_is_bound(0, name, curses_key, FALSE)) + continue; +#endif + + if ((p = dlg_calloc(LIST_BINDINGS, 1)) != 0) { + if ((q = dlg_calloc(DLG_KEYS_BINDING, 2)) != 0) { + q[0].is_function_key = 0; + q[0].curses_key = curses_key; + q[0].dialog_key = curses_key; + q[1] = end_keys_binding; + + p->win = win; + p->name = name; + p->buttons = TRUE; + p->binding = q; + + /* put these at the beginning, to override the widget's table */ + p->link = all_bindings; + all_bindings = p; + } else { + free(p); + } + } + } +} + +/* + * Remove the bindings for a given window. + */ +void +dlg_unregister_window(WINDOW *win) +{ + LIST_BINDINGS *p, *q; + + for (p = all_bindings, q = 0; p != 0; p = p->link) { + if (p->win == win) { + if (q != 0) { + q->link = p->link; + } else { + all_bindings = p->link; + } + /* the user-defined and buttons-bindings all are length=1 */ + if (p->binding[1].is_function_key < 0) + free(p->binding); + free(p); + dlg_unregister_window(win); + break; + } + q = p; + } +} + +/* + * Call this after wgetch(), using the same window pointer and passing + * the curses-key. + * + * If there is no binding associated with the widget, it simply returns + * the given curses-key. + * + * Parameters: + * win is the window on which the wgetch() was done. + * curses_key is the value returned by wgetch(). + * fkey in/out (on input, it is true if curses_key is a function key, + * and on output, it is true if the result is a function key). + */ +int +dlg_lookup_key(WINDOW *win, int curses_key, int *fkey) +{ + LIST_BINDINGS *p; + int n; + + /* + * Ignore mouse clicks, since they are already encoded properly. + */ +#ifdef KEY_MOUSE + if (*fkey != 0 && curses_key == KEY_MOUSE) { + ; + } else +#endif + /* + * Ignore resize events, since they are already encoded properly. + */ +#ifdef KEY_RESIZE + if (*fkey != 0 && curses_key == KEY_RESIZE) { + ; + } else +#endif + if (*fkey == 0 || curses_key < KEY_MAX) { + for (p = all_bindings; p != 0; p = p->link) { + if (p->win == win || p->win == 0) { + int function_key = (*fkey != 0); + for (n = 0; p->binding[n].is_function_key >= 0; ++n) { + if (p->buttons + && !function_key + && p->binding[n].curses_key == (int) dlg_toupper(curses_key)) { + *fkey = 0; + return p->binding[n].dialog_key; + } + if (p->binding[n].curses_key == curses_key + && p->binding[n].is_function_key == function_key) { + *fkey = p->binding[n].dialog_key; + return *fkey; + } + } + } + } + } + return curses_key; +} + +/* + * Test a dialog internal keycode to see if it corresponds to one of the push + * buttons on the widget such as "OK". + * + * This is only useful if there are user-defined key bindings, since there are + * no built-in bindings that map directly to DLGK_OK, etc. + * + * See also dlg_ok_buttoncode(). + */ +int +dlg_result_key(int dialog_key, int fkey GCC_UNUSED, int *resultp) +{ + int done = FALSE; + +#ifdef HAVE_RC_FILE + if (fkey) { + switch ((DLG_KEYS_ENUM) dialog_key) { + case DLGK_OK: + *resultp = DLG_EXIT_OK; + done = TRUE; + break; + case DLGK_CANCEL: + if (!dialog_vars.nocancel) { + *resultp = DLG_EXIT_CANCEL; + done = TRUE; + } + break; + case DLGK_EXTRA: + if (dialog_vars.extra_button) { + *resultp = DLG_EXIT_EXTRA; + done = TRUE; + } + break; + case DLGK_HELP: + if (dialog_vars.help_button) { + *resultp = DLG_EXIT_HELP; + done = TRUE; + } + break; + case DLGK_ESC: + *resultp = DLG_EXIT_ESC; + done = TRUE; + break; + default: + break; + } + } else +#endif + if (dialog_key == ESC) { + *resultp = DLG_EXIT_ESC; + done = TRUE; + } + return done; +} + +#ifdef HAVE_RC_FILE +typedef struct { + const char *name; + int code; +} CODENAME; + +#define CURSES_NAME(upper) { #upper, KEY_ ## upper } +#define COUNT_CURSES sizeof(curses_names)/sizeof(curses_names[0]) +static const CODENAME curses_names[] = +{ + CURSES_NAME(DOWN), + CURSES_NAME(UP), + CURSES_NAME(LEFT), + CURSES_NAME(RIGHT), + CURSES_NAME(HOME), + CURSES_NAME(BACKSPACE), + CURSES_NAME(F0), + CURSES_NAME(DL), + CURSES_NAME(IL), + CURSES_NAME(DC), + CURSES_NAME(IC), + CURSES_NAME(EIC), + CURSES_NAME(CLEAR), + CURSES_NAME(EOS), + CURSES_NAME(EOL), + CURSES_NAME(SF), + CURSES_NAME(SR), + CURSES_NAME(NPAGE), + CURSES_NAME(PPAGE), + CURSES_NAME(STAB), + CURSES_NAME(CTAB), + CURSES_NAME(CATAB), + CURSES_NAME(ENTER), + CURSES_NAME(PRINT), + CURSES_NAME(LL), + CURSES_NAME(A1), + CURSES_NAME(A3), + CURSES_NAME(B2), + CURSES_NAME(C1), + CURSES_NAME(C3), + CURSES_NAME(BTAB), + CURSES_NAME(BEG), + CURSES_NAME(CANCEL), + CURSES_NAME(CLOSE), + CURSES_NAME(COMMAND), + CURSES_NAME(COPY), + CURSES_NAME(CREATE), + CURSES_NAME(END), + CURSES_NAME(EXIT), + CURSES_NAME(FIND), + CURSES_NAME(HELP), + CURSES_NAME(MARK), + CURSES_NAME(MESSAGE), + CURSES_NAME(MOVE), + CURSES_NAME(NEXT), + CURSES_NAME(OPEN), + CURSES_NAME(OPTIONS), + CURSES_NAME(PREVIOUS), + CURSES_NAME(REDO), + CURSES_NAME(REFERENCE), + CURSES_NAME(REFRESH), + CURSES_NAME(REPLACE), + CURSES_NAME(RESTART), + CURSES_NAME(RESUME), + CURSES_NAME(SAVE), + CURSES_NAME(SBEG), + CURSES_NAME(SCANCEL), + CURSES_NAME(SCOMMAND), + CURSES_NAME(SCOPY), + CURSES_NAME(SCREATE), + CURSES_NAME(SDC), + CURSES_NAME(SDL), + CURSES_NAME(SELECT), + CURSES_NAME(SEND), + CURSES_NAME(SEOL), + CURSES_NAME(SEXIT), + CURSES_NAME(SFIND), + CURSES_NAME(SHELP), + CURSES_NAME(SHOME), + CURSES_NAME(SIC), + CURSES_NAME(SLEFT), + CURSES_NAME(SMESSAGE), + CURSES_NAME(SMOVE), + CURSES_NAME(SNEXT), + CURSES_NAME(SOPTIONS), + CURSES_NAME(SPREVIOUS), + CURSES_NAME(SPRINT), + CURSES_NAME(SREDO), + CURSES_NAME(SREPLACE), + CURSES_NAME(SRIGHT), + CURSES_NAME(SRSUME), + CURSES_NAME(SSAVE), + CURSES_NAME(SSUSPEND), + CURSES_NAME(SUNDO), + CURSES_NAME(SUSPEND), + CURSES_NAME(UNDO), +}; + +#define DIALOG_NAME(upper) { #upper, DLGK_ ## upper } +#define COUNT_DIALOG sizeof(dialog_names)/sizeof(dialog_names[0]) +static const CODENAME dialog_names[] = +{ + DIALOG_NAME(OK), + DIALOG_NAME(CANCEL), + DIALOG_NAME(EXTRA), + DIALOG_NAME(HELP), + DIALOG_NAME(ESC), + DIALOG_NAME(PAGE_FIRST), + DIALOG_NAME(PAGE_LAST), + DIALOG_NAME(PAGE_NEXT), + DIALOG_NAME(PAGE_PREV), + DIALOG_NAME(ITEM_FIRST), + DIALOG_NAME(ITEM_LAST), + DIALOG_NAME(ITEM_NEXT), + DIALOG_NAME(ITEM_PREV), + DIALOG_NAME(FIELD_FIRST), + DIALOG_NAME(FIELD_LAST), + DIALOG_NAME(FIELD_NEXT), + DIALOG_NAME(FIELD_PREV), + DIALOG_NAME(GRID_UP), + DIALOG_NAME(GRID_DOWN), + DIALOG_NAME(GRID_LEFT), + DIALOG_NAME(GRID_RIGHT), + DIALOG_NAME(DELETE_LEFT), + DIALOG_NAME(DELETE_RIGHT), + DIALOG_NAME(DELETE_ALL), + DIALOG_NAME(ENTER), + DIALOG_NAME(BEGIN), + DIALOG_NAME(FINAL), + DIALOG_NAME(SELECT) +}; + +static char * +skip_white(char *s) +{ + while (*s != '\0' && isspace(UCH(*s))) + ++s; + return s; +} + +static char * +skip_black(char *s) +{ + while (*s != '\0' && !isspace(UCH(*s))) + ++s; + return s; +} + +/* + * Find a user-defined binding, given the curses key code. + */ +static DLG_KEYS_BINDING * +find_binding(char *widget, int curses_key) +{ + LIST_BINDINGS *p; + DLG_KEYS_BINDING *result = 0; + + for (p = all_bindings; p != 0; p = p->link) { + if (p->win == 0 + && !dlg_strcmp(p->name, widget) + && p->binding->curses_key == curses_key) { + result = p->binding; + break; + } + } + return result; +} + +/* + * Built-in bindings have a nonzero "win" member, and the associated binding + * table can have more than one entry. We keep those last, since lookups will + * find the user-defined bindings first and use those. + * + * Sort "*" (all-widgets) entries past named widgets, since those are less + * specific. + */ +static int +compare_bindings(LIST_BINDINGS * a, LIST_BINDINGS * b) +{ + int result = 0; + if (a->win == b->win) { + if (!strcmp(a->name, b->name)) { + result = a->binding[0].curses_key - b->binding[0].curses_key; + } else if (!strcmp(b->name, "*")) { + result = -1; + } else if (!strcmp(a->name, "*")) { + result = 1; + } else { + result = dlg_strcmp(a->name, b->name); + } + } else if (b->win) { + result = -1; + } else { + result = 1; + } + return result; +} + +/* + * Find a user-defined binding, given the curses key code. If it does not + * exist, create a new one, inserting it into the linked list, keeping it + * sorted to simplify lookups for user-defined bindings that can override + * the built-in bindings. + */ +static DLG_KEYS_BINDING * +make_binding(char *widget, int curses_key, int is_function, int dialog_key) +{ + LIST_BINDINGS *entry = 0; + DLG_KEYS_BINDING *data = 0; + char *name; + LIST_BINDINGS *p, *q; + DLG_KEYS_BINDING *result = find_binding(widget, curses_key); + + if (result == 0 + && (entry = dlg_calloc(LIST_BINDINGS, 1)) != 0 + && (data = dlg_calloc(DLG_KEYS_BINDING, 2)) != 0 + && (name = dlg_strclone(widget)) != 0) { + + entry->name = name; + entry->binding = data; + + data[0].is_function_key = is_function; + data[0].curses_key = curses_key; + data[0].dialog_key = dialog_key; + + data[1] = end_keys_binding; + + for (p = all_bindings, q = 0; p != 0; q = p, p = p->link) { + if (compare_bindings(entry, p) < 0) { + break; + } + } + if (q != 0) { + q->link = entry; + } else { + all_bindings = entry; + } + if (p != 0) { + entry->link = p; + } + result = data; + } else if (entry != 0) { + free(entry); + if (data) + free(data); + } + + return result; +} + +/* + * Parse the parameters of the "bindkeys" configuration-file entry. This + * expects widget name which may be "*", followed by curses key definition and + * then dialog key definition. + * + * The curses key "should" be one of the names (ignoring case) from + * curses_names[], but may also be a single control character (prefix "^" or + * "~" depending on whether it is C0 or C1), or an escaped single character. + * Binding a printable character with dialog is possible but not useful. + * + * The dialog key must be one of the names from dialog_names[]. + */ +int +dlg_parse_bindkey(char *params) +{ + char *p = skip_white(params); + char *q; + bool escaped = FALSE; + int modified = 0; + int result = FALSE; + unsigned xx; + char *widget; + int is_function = FALSE; + int curses_key; + int dialog_key; + + curses_key = -1; + dialog_key = -1; + widget = p; + + p = skip_black(p); + if (p != widget && *p != '\0') { + *p++ = '\0'; + q = p; + while (*p != '\0' && curses_key < 0) { + if (escaped) { + escaped = FALSE; + curses_key = *p; + } else if (*p == '\\') { + escaped = TRUE; + } else if (modified) { + if (*p == '?') { + curses_key = ((modified == '^') + ? 127 + : 255); + } else { + curses_key = ((modified == '^') + ? (*p & 0x1f) + : ((*p & 0x1f) | 0x80)); + } + } else if (*p == '^') { + modified = *p; + } else if (*p == '~') { + modified = *p; + } else if (isspace(UCH(*p))) { + break; + } + ++p; + } + if (!isspace(UCH(*p))) { + ; + } else { + *p++ = '\0'; + if (curses_key < 0) { + char fprefix[2]; + char check[2]; + int keynumber; + if (sscanf(q, "%[Ff]%d%c", fprefix, &keynumber, check) == 2) { + curses_key = KEY_F(keynumber); + is_function = TRUE; + } else { + for (xx = 0; xx < COUNT_CURSES; ++xx) { + if (!dlg_strcmp(curses_names[xx].name, q)) { + curses_key = curses_names[xx].code; + is_function = TRUE; + break; + } + } + } + } + } + q = skip_white(p); + p = skip_black(q); + if (p != q) { + for (xx = 0; xx < COUNT_DIALOG; ++xx) { + if (!dlg_strcmp(dialog_names[xx].name, q)) { + dialog_key = dialog_names[xx].code; + break; + } + } + } + if (*widget != '\0' + && curses_key >= 0 + && dialog_key >= 0 + && make_binding(widget, curses_key, is_function, dialog_key) != 0) { + result = TRUE; + } + } + return result; +} + +static void +dump_curses_key(FILE *fp, int curses_key) +{ + if (curses_key > KEY_MIN) { + unsigned n; + bool found = FALSE; + for (n = 0; n < COUNT_CURSES; ++n) { + if (curses_names[n].code == curses_key) { + fprintf(fp, "%s", curses_names[n].name); + found = TRUE; + break; + } + } + if (!found) { + if (curses_key >= KEY_F(0)) { + fprintf(fp, "F%d", curses_key - KEY_F(0)); + } else { + fprintf(fp, "curses%d", curses_key); + } + } + } else if (curses_key >= 0 && curses_key < 32) { + fprintf(fp, "^%c", curses_key + 64); + } else if (curses_key == 127) { + fprintf(fp, "^?"); + } else if (curses_key >= 128 && curses_key < 160) { + fprintf(fp, "~%c", curses_key - 64); + } else if (curses_key == 255) { + fprintf(fp, "~?"); + } else { + fprintf(fp, "\\%c", curses_key); + } +} + +static void +dump_dialog_key(FILE *fp, int dialog_key) +{ + unsigned n; + bool found = FALSE; + for (n = 0; n < COUNT_DIALOG; ++n) { + if (dialog_names[n].code == dialog_key) { + fputs(dialog_names[n].name, fp); + found = TRUE; + break; + } + } + if (!found) { + fprintf(fp, "dialog%d", dialog_key); + } +} + +static void +dump_one_binding(FILE *fp, const char *widget, DLG_KEYS_BINDING * binding) +{ + fprintf(fp, "bindkey %s ", widget); + dump_curses_key(fp, binding->curses_key); + fputc(' ', fp); + dump_dialog_key(fp, binding->dialog_key); + fputc('\n', fp); +} + +void +dlg_dump_keys(FILE *fp) +{ + LIST_BINDINGS *p; + const char *last = ""; + unsigned n; + unsigned count = 0; + + for (p = all_bindings; p != 0; p = p->link) { + if (p->win == 0) { + ++count; + } + } + if (count != 0) { + for (p = all_bindings, n = 0; p != 0; p = p->link) { + if (p->win == 0) { + if (dlg_strcmp(last, p->name)) { + fprintf(fp, "\n# key bindings for %s widgets\n", + !strcmp(p->name, "*") ? "all" : p->name); + last = p->name; + } + dump_one_binding(fp, p->name, p->binding); + } + } + } +} +#endif /* HAVE_RC_FILE */ |