1217309Snwhitehorn/* 2251843Sbapt * $Id: dlg_keys.c,v 1.34 2011/10/14 00:41:08 tom Exp $ 3217309Snwhitehorn * 4251843Sbapt * dlg_keys.c -- runtime binding support for dialog 5217309Snwhitehorn * 6251843Sbapt * Copyright 2006-2009,2011 Thomas E. Dickey 7217309Snwhitehorn * 8217309Snwhitehorn * This program is free software; you can redistribute it and/or modify 9217309Snwhitehorn * it under the terms of the GNU Lesser General Public License, version 2.1 10217309Snwhitehorn * as published by the Free Software Foundation. 11217309Snwhitehorn * 12217309Snwhitehorn * This program is distributed in the hope that it will be useful, but 13217309Snwhitehorn * WITHOUT ANY WARRANTY; without even the implied warranty of 14217309Snwhitehorn * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15217309Snwhitehorn * Lesser General Public License for more details. 16217309Snwhitehorn * 17217309Snwhitehorn * You should have received a copy of the GNU Lesser General Public 18217309Snwhitehorn * License along with this program; if not, write to 19217309Snwhitehorn * Free Software Foundation, Inc. 20217309Snwhitehorn * 51 Franklin St., Fifth Floor 21217309Snwhitehorn * Boston, MA 02110, USA. 22217309Snwhitehorn */ 23217309Snwhitehorn 24217309Snwhitehorn#include <dialog.h> 25217309Snwhitehorn#include <dlg_keys.h> 26217309Snwhitehorn 27217309Snwhitehorn#define LIST_BINDINGS struct _list_bindings 28217309Snwhitehorn 29217309SnwhitehornLIST_BINDINGS { 30217309Snwhitehorn LIST_BINDINGS *link; 31217309Snwhitehorn WINDOW *win; /* window on which widget gets input */ 32217309Snwhitehorn const char *name; /* widget name */ 33217309Snwhitehorn bool buttons; /* true only for dlg_register_buttons() */ 34217309Snwhitehorn DLG_KEYS_BINDING *binding; /* list of bindings */ 35217309Snwhitehorn}; 36217309Snwhitehorn 37251843Sbapt#define WILDNAME "*" 38217309Snwhitehornstatic LIST_BINDINGS *all_bindings; 39217309Snwhitehornstatic const DLG_KEYS_BINDING end_keys_binding = END_KEYS_BINDING; 40217309Snwhitehorn 41217309Snwhitehorn/* 42217309Snwhitehorn * For a given named widget's window, associate a binding table. 43217309Snwhitehorn */ 44217309Snwhitehornvoid 45217309Snwhitehorndlg_register_window(WINDOW *win, const char *name, DLG_KEYS_BINDING * binding) 46217309Snwhitehorn{ 47217309Snwhitehorn LIST_BINDINGS *p, *q; 48217309Snwhitehorn 49217309Snwhitehorn for (p = all_bindings, q = 0; p != 0; q = p, p = p->link) { 50217309Snwhitehorn if (p->win == win && !strcmp(p->name, name)) { 51217309Snwhitehorn p->binding = binding; 52217309Snwhitehorn return; 53217309Snwhitehorn } 54217309Snwhitehorn } 55217309Snwhitehorn /* add built-in bindings at the end of the list (see compare_bindings). */ 56217309Snwhitehorn if ((p = dlg_calloc(LIST_BINDINGS, 1)) != 0) { 57217309Snwhitehorn p->win = win; 58217309Snwhitehorn p->name = name; 59217309Snwhitehorn p->binding = binding; 60217309Snwhitehorn if (q != 0) 61217309Snwhitehorn q->link = p; 62217309Snwhitehorn else 63217309Snwhitehorn all_bindings = p; 64217309Snwhitehorn } 65251843Sbapt#if defined(HAVE_DLG_TRACE) && defined(HAVE_RC_FILE) 66251843Sbapt /* 67251843Sbapt * Trace the binding information assigned to this window. For most widgets 68251843Sbapt * there is only one binding table. forms have two, so the trace will be 69251843Sbapt * longer. Since compiled-in bindings are only visible when the widget is 70251843Sbapt * registered, there is no other way to see what bindings are available, 71251843Sbapt * than by running dialog and tracing it. 72251843Sbapt */ 73251843Sbapt dlg_trace_msg("# dlg_register_window %s\n", name); 74251843Sbapt dlg_dump_window_keys(dialog_state.trace_output, win); 75251843Sbapt#endif 76217309Snwhitehorn} 77217309Snwhitehorn 78217309Snwhitehorn/* 79217309Snwhitehorn * Unlike dlg_lookup_key(), this looks for either widget-builtin or rc-file 80217309Snwhitehorn * definitions, depending on whether 'win' is null. 81217309Snwhitehorn */ 82217309Snwhitehornstatic int 83217309Snwhitehornkey_is_bound(WINDOW *win, const char *name, int curses_key, int function_key) 84217309Snwhitehorn{ 85217309Snwhitehorn LIST_BINDINGS *p; 86217309Snwhitehorn 87217309Snwhitehorn for (p = all_bindings; p != 0; p = p->link) { 88217309Snwhitehorn if (p->win == win && !dlg_strcmp(p->name, name)) { 89217309Snwhitehorn int n; 90217309Snwhitehorn for (n = 0; p->binding[n].is_function_key >= 0; ++n) { 91217309Snwhitehorn if (p->binding[n].curses_key == curses_key 92217309Snwhitehorn && p->binding[n].is_function_key == function_key) { 93217309Snwhitehorn return TRUE; 94217309Snwhitehorn } 95217309Snwhitehorn } 96217309Snwhitehorn } 97217309Snwhitehorn } 98217309Snwhitehorn return FALSE; 99217309Snwhitehorn} 100217309Snwhitehorn 101217309Snwhitehorn/* 102217309Snwhitehorn * Call this function after dlg_register_window(), for the list of button 103217309Snwhitehorn * labels associated with the widget. 104217309Snwhitehorn * 105217309Snwhitehorn * Ensure that dlg_lookup_key() will not accidentally translate a key that 106217309Snwhitehorn * we would like to use for a button abbreviation to some other key, e.g., 107217309Snwhitehorn * h/j/k/l for navigation into a cursor key. Do this by binding the key 108217309Snwhitehorn * to itself. 109217309Snwhitehorn * 110217309Snwhitehorn * See dlg_char_to_button(). 111217309Snwhitehorn */ 112217309Snwhitehornvoid 113217309Snwhitehorndlg_register_buttons(WINDOW *win, const char *name, const char **buttons) 114217309Snwhitehorn{ 115217309Snwhitehorn int n; 116217309Snwhitehorn LIST_BINDINGS *p; 117217309Snwhitehorn DLG_KEYS_BINDING *q; 118217309Snwhitehorn 119217309Snwhitehorn if (buttons == 0) 120217309Snwhitehorn return; 121217309Snwhitehorn 122217309Snwhitehorn for (n = 0; buttons[n] != 0; ++n) { 123217309Snwhitehorn int curses_key = dlg_button_to_char(buttons[n]); 124217309Snwhitehorn 125217309Snwhitehorn /* ignore multibyte characters */ 126217309Snwhitehorn if (curses_key >= KEY_MIN) 127217309Snwhitehorn continue; 128217309Snwhitehorn 129217309Snwhitehorn /* if it is not bound in the widget, skip it (no conflicts) */ 130217309Snwhitehorn if (!key_is_bound(win, name, curses_key, FALSE)) 131217309Snwhitehorn continue; 132217309Snwhitehorn 133217309Snwhitehorn#ifdef HAVE_RC_FILE 134217309Snwhitehorn /* if it is bound in the rc-file, skip it */ 135217309Snwhitehorn if (key_is_bound(0, name, curses_key, FALSE)) 136217309Snwhitehorn continue; 137217309Snwhitehorn#endif 138217309Snwhitehorn 139217309Snwhitehorn if ((p = dlg_calloc(LIST_BINDINGS, 1)) != 0) { 140217309Snwhitehorn if ((q = dlg_calloc(DLG_KEYS_BINDING, 2)) != 0) { 141217309Snwhitehorn q[0].is_function_key = 0; 142217309Snwhitehorn q[0].curses_key = curses_key; 143217309Snwhitehorn q[0].dialog_key = curses_key; 144217309Snwhitehorn q[1] = end_keys_binding; 145217309Snwhitehorn 146217309Snwhitehorn p->win = win; 147217309Snwhitehorn p->name = name; 148217309Snwhitehorn p->buttons = TRUE; 149217309Snwhitehorn p->binding = q; 150217309Snwhitehorn 151217309Snwhitehorn /* put these at the beginning, to override the widget's table */ 152217309Snwhitehorn p->link = all_bindings; 153217309Snwhitehorn all_bindings = p; 154217309Snwhitehorn } else { 155217309Snwhitehorn free(p); 156217309Snwhitehorn } 157217309Snwhitehorn } 158217309Snwhitehorn } 159217309Snwhitehorn} 160217309Snwhitehorn 161217309Snwhitehorn/* 162217309Snwhitehorn * Remove the bindings for a given window. 163217309Snwhitehorn */ 164217309Snwhitehornvoid 165217309Snwhitehorndlg_unregister_window(WINDOW *win) 166217309Snwhitehorn{ 167217309Snwhitehorn LIST_BINDINGS *p, *q; 168217309Snwhitehorn 169217309Snwhitehorn for (p = all_bindings, q = 0; p != 0; p = p->link) { 170217309Snwhitehorn if (p->win == win) { 171217309Snwhitehorn if (q != 0) { 172217309Snwhitehorn q->link = p->link; 173217309Snwhitehorn } else { 174217309Snwhitehorn all_bindings = p->link; 175217309Snwhitehorn } 176217309Snwhitehorn /* the user-defined and buttons-bindings all are length=1 */ 177217309Snwhitehorn if (p->binding[1].is_function_key < 0) 178217309Snwhitehorn free(p->binding); 179217309Snwhitehorn free(p); 180217309Snwhitehorn dlg_unregister_window(win); 181217309Snwhitehorn break; 182217309Snwhitehorn } 183217309Snwhitehorn q = p; 184217309Snwhitehorn } 185217309Snwhitehorn} 186217309Snwhitehorn 187217309Snwhitehorn/* 188217309Snwhitehorn * Call this after wgetch(), using the same window pointer and passing 189217309Snwhitehorn * the curses-key. 190217309Snwhitehorn * 191217309Snwhitehorn * If there is no binding associated with the widget, it simply returns 192217309Snwhitehorn * the given curses-key. 193217309Snwhitehorn * 194217309Snwhitehorn * Parameters: 195217309Snwhitehorn * win is the window on which the wgetch() was done. 196217309Snwhitehorn * curses_key is the value returned by wgetch(). 197217309Snwhitehorn * fkey in/out (on input, it is true if curses_key is a function key, 198217309Snwhitehorn * and on output, it is true if the result is a function key). 199217309Snwhitehorn */ 200217309Snwhitehornint 201217309Snwhitehorndlg_lookup_key(WINDOW *win, int curses_key, int *fkey) 202217309Snwhitehorn{ 203217309Snwhitehorn LIST_BINDINGS *p; 204251843Sbapt DLG_KEYS_BINDING *q; 205217309Snwhitehorn 206217309Snwhitehorn /* 207217309Snwhitehorn * Ignore mouse clicks, since they are already encoded properly. 208217309Snwhitehorn */ 209217309Snwhitehorn#ifdef KEY_MOUSE 210217309Snwhitehorn if (*fkey != 0 && curses_key == KEY_MOUSE) { 211217309Snwhitehorn ; 212217309Snwhitehorn } else 213217309Snwhitehorn#endif 214217309Snwhitehorn /* 215217309Snwhitehorn * Ignore resize events, since they are already encoded properly. 216217309Snwhitehorn */ 217217309Snwhitehorn#ifdef KEY_RESIZE 218217309Snwhitehorn if (*fkey != 0 && curses_key == KEY_RESIZE) { 219217309Snwhitehorn ; 220217309Snwhitehorn } else 221217309Snwhitehorn#endif 222217309Snwhitehorn if (*fkey == 0 || curses_key < KEY_MAX) { 223251843Sbapt const char *name = WILDNAME; 224251843Sbapt if (win != 0) { 225251843Sbapt for (p = all_bindings; p != 0; p = p->link) { 226251843Sbapt if (p->win == win) { 227251843Sbapt name = p->name; 228251843Sbapt break; 229251843Sbapt } 230251843Sbapt } 231251843Sbapt } 232217309Snwhitehorn for (p = all_bindings; p != 0; p = p->link) { 233251843Sbapt if (p->win == win || (p->win == 0 && !strcmp(p->name, name))) { 234217309Snwhitehorn int function_key = (*fkey != 0); 235251843Sbapt for (q = p->binding; q->is_function_key >= 0; ++q) { 236217309Snwhitehorn if (p->buttons 237217309Snwhitehorn && !function_key 238251843Sbapt && q->curses_key == (int) dlg_toupper(curses_key)) { 239217309Snwhitehorn *fkey = 0; 240251843Sbapt return q->dialog_key; 241217309Snwhitehorn } 242251843Sbapt if (q->curses_key == curses_key 243251843Sbapt && q->is_function_key == function_key) { 244251843Sbapt *fkey = q->dialog_key; 245217309Snwhitehorn return *fkey; 246217309Snwhitehorn } 247217309Snwhitehorn } 248217309Snwhitehorn } 249217309Snwhitehorn } 250217309Snwhitehorn } 251217309Snwhitehorn return curses_key; 252217309Snwhitehorn} 253217309Snwhitehorn 254217309Snwhitehorn/* 255217309Snwhitehorn * Test a dialog internal keycode to see if it corresponds to one of the push 256217309Snwhitehorn * buttons on the widget such as "OK". 257217309Snwhitehorn * 258217309Snwhitehorn * This is only useful if there are user-defined key bindings, since there are 259217309Snwhitehorn * no built-in bindings that map directly to DLGK_OK, etc. 260217309Snwhitehorn * 261217309Snwhitehorn * See also dlg_ok_buttoncode(). 262217309Snwhitehorn */ 263217309Snwhitehornint 264217309Snwhitehorndlg_result_key(int dialog_key, int fkey GCC_UNUSED, int *resultp) 265217309Snwhitehorn{ 266217309Snwhitehorn int done = FALSE; 267217309Snwhitehorn 268217309Snwhitehorn#ifdef HAVE_RC_FILE 269217309Snwhitehorn if (fkey) { 270217309Snwhitehorn switch ((DLG_KEYS_ENUM) dialog_key) { 271217309Snwhitehorn case DLGK_OK: 272217309Snwhitehorn *resultp = DLG_EXIT_OK; 273217309Snwhitehorn done = TRUE; 274217309Snwhitehorn break; 275217309Snwhitehorn case DLGK_CANCEL: 276217309Snwhitehorn if (!dialog_vars.nocancel) { 277217309Snwhitehorn *resultp = DLG_EXIT_CANCEL; 278217309Snwhitehorn done = TRUE; 279217309Snwhitehorn } 280217309Snwhitehorn break; 281217309Snwhitehorn case DLGK_EXTRA: 282217309Snwhitehorn if (dialog_vars.extra_button) { 283217309Snwhitehorn *resultp = DLG_EXIT_EXTRA; 284217309Snwhitehorn done = TRUE; 285217309Snwhitehorn } 286217309Snwhitehorn break; 287217309Snwhitehorn case DLGK_HELP: 288217309Snwhitehorn if (dialog_vars.help_button) { 289217309Snwhitehorn *resultp = DLG_EXIT_HELP; 290217309Snwhitehorn done = TRUE; 291217309Snwhitehorn } 292217309Snwhitehorn break; 293217309Snwhitehorn case DLGK_ESC: 294217309Snwhitehorn *resultp = DLG_EXIT_ESC; 295217309Snwhitehorn done = TRUE; 296217309Snwhitehorn break; 297217309Snwhitehorn default: 298217309Snwhitehorn break; 299217309Snwhitehorn } 300217309Snwhitehorn } else 301217309Snwhitehorn#endif 302217309Snwhitehorn if (dialog_key == ESC) { 303217309Snwhitehorn *resultp = DLG_EXIT_ESC; 304217309Snwhitehorn done = TRUE; 305217309Snwhitehorn } else if (dialog_key == ERR) { 306217309Snwhitehorn *resultp = DLG_EXIT_ERROR; 307217309Snwhitehorn done = TRUE; 308217309Snwhitehorn } 309217309Snwhitehorn 310217309Snwhitehorn return done; 311217309Snwhitehorn} 312217309Snwhitehorn 313217309Snwhitehorn#ifdef HAVE_RC_FILE 314217309Snwhitehorntypedef struct { 315217309Snwhitehorn const char *name; 316217309Snwhitehorn int code; 317217309Snwhitehorn} CODENAME; 318217309Snwhitehorn 319251843Sbapt#define ASCII_NAME(name,code) { #name, code } 320217309Snwhitehorn#define CURSES_NAME(upper) { #upper, KEY_ ## upper } 321217309Snwhitehorn#define COUNT_CURSES sizeof(curses_names)/sizeof(curses_names[0]) 322217309Snwhitehornstatic const CODENAME curses_names[] = 323217309Snwhitehorn{ 324251843Sbapt ASCII_NAME(ESC, '\033'), 325251843Sbapt ASCII_NAME(CR, '\r'), 326251843Sbapt ASCII_NAME(LF, '\n'), 327251843Sbapt ASCII_NAME(FF, '\f'), 328251843Sbapt ASCII_NAME(TAB, '\t'), 329251843Sbapt ASCII_NAME(DEL, '\177'), 330251843Sbapt 331217309Snwhitehorn CURSES_NAME(DOWN), 332217309Snwhitehorn CURSES_NAME(UP), 333217309Snwhitehorn CURSES_NAME(LEFT), 334217309Snwhitehorn CURSES_NAME(RIGHT), 335217309Snwhitehorn CURSES_NAME(HOME), 336217309Snwhitehorn CURSES_NAME(BACKSPACE), 337217309Snwhitehorn CURSES_NAME(F0), 338217309Snwhitehorn CURSES_NAME(DL), 339217309Snwhitehorn CURSES_NAME(IL), 340217309Snwhitehorn CURSES_NAME(DC), 341217309Snwhitehorn CURSES_NAME(IC), 342217309Snwhitehorn CURSES_NAME(EIC), 343217309Snwhitehorn CURSES_NAME(CLEAR), 344217309Snwhitehorn CURSES_NAME(EOS), 345217309Snwhitehorn CURSES_NAME(EOL), 346217309Snwhitehorn CURSES_NAME(SF), 347217309Snwhitehorn CURSES_NAME(SR), 348217309Snwhitehorn CURSES_NAME(NPAGE), 349217309Snwhitehorn CURSES_NAME(PPAGE), 350217309Snwhitehorn CURSES_NAME(STAB), 351217309Snwhitehorn CURSES_NAME(CTAB), 352217309Snwhitehorn CURSES_NAME(CATAB), 353217309Snwhitehorn CURSES_NAME(ENTER), 354217309Snwhitehorn CURSES_NAME(PRINT), 355217309Snwhitehorn CURSES_NAME(LL), 356217309Snwhitehorn CURSES_NAME(A1), 357217309Snwhitehorn CURSES_NAME(A3), 358217309Snwhitehorn CURSES_NAME(B2), 359217309Snwhitehorn CURSES_NAME(C1), 360217309Snwhitehorn CURSES_NAME(C3), 361217309Snwhitehorn CURSES_NAME(BTAB), 362217309Snwhitehorn CURSES_NAME(BEG), 363217309Snwhitehorn CURSES_NAME(CANCEL), 364217309Snwhitehorn CURSES_NAME(CLOSE), 365217309Snwhitehorn CURSES_NAME(COMMAND), 366217309Snwhitehorn CURSES_NAME(COPY), 367217309Snwhitehorn CURSES_NAME(CREATE), 368217309Snwhitehorn CURSES_NAME(END), 369217309Snwhitehorn CURSES_NAME(EXIT), 370217309Snwhitehorn CURSES_NAME(FIND), 371217309Snwhitehorn CURSES_NAME(HELP), 372217309Snwhitehorn CURSES_NAME(MARK), 373217309Snwhitehorn CURSES_NAME(MESSAGE), 374217309Snwhitehorn CURSES_NAME(MOVE), 375217309Snwhitehorn CURSES_NAME(NEXT), 376217309Snwhitehorn CURSES_NAME(OPEN), 377217309Snwhitehorn CURSES_NAME(OPTIONS), 378217309Snwhitehorn CURSES_NAME(PREVIOUS), 379217309Snwhitehorn CURSES_NAME(REDO), 380217309Snwhitehorn CURSES_NAME(REFERENCE), 381217309Snwhitehorn CURSES_NAME(REFRESH), 382217309Snwhitehorn CURSES_NAME(REPLACE), 383217309Snwhitehorn CURSES_NAME(RESTART), 384217309Snwhitehorn CURSES_NAME(RESUME), 385217309Snwhitehorn CURSES_NAME(SAVE), 386217309Snwhitehorn CURSES_NAME(SBEG), 387217309Snwhitehorn CURSES_NAME(SCANCEL), 388217309Snwhitehorn CURSES_NAME(SCOMMAND), 389217309Snwhitehorn CURSES_NAME(SCOPY), 390217309Snwhitehorn CURSES_NAME(SCREATE), 391217309Snwhitehorn CURSES_NAME(SDC), 392217309Snwhitehorn CURSES_NAME(SDL), 393217309Snwhitehorn CURSES_NAME(SELECT), 394217309Snwhitehorn CURSES_NAME(SEND), 395217309Snwhitehorn CURSES_NAME(SEOL), 396217309Snwhitehorn CURSES_NAME(SEXIT), 397217309Snwhitehorn CURSES_NAME(SFIND), 398217309Snwhitehorn CURSES_NAME(SHELP), 399217309Snwhitehorn CURSES_NAME(SHOME), 400217309Snwhitehorn CURSES_NAME(SIC), 401217309Snwhitehorn CURSES_NAME(SLEFT), 402217309Snwhitehorn CURSES_NAME(SMESSAGE), 403217309Snwhitehorn CURSES_NAME(SMOVE), 404217309Snwhitehorn CURSES_NAME(SNEXT), 405217309Snwhitehorn CURSES_NAME(SOPTIONS), 406217309Snwhitehorn CURSES_NAME(SPREVIOUS), 407217309Snwhitehorn CURSES_NAME(SPRINT), 408217309Snwhitehorn CURSES_NAME(SREDO), 409217309Snwhitehorn CURSES_NAME(SREPLACE), 410217309Snwhitehorn CURSES_NAME(SRIGHT), 411217309Snwhitehorn CURSES_NAME(SRSUME), 412217309Snwhitehorn CURSES_NAME(SSAVE), 413217309Snwhitehorn CURSES_NAME(SSUSPEND), 414217309Snwhitehorn CURSES_NAME(SUNDO), 415217309Snwhitehorn CURSES_NAME(SUSPEND), 416217309Snwhitehorn CURSES_NAME(UNDO), 417217309Snwhitehorn}; 418217309Snwhitehorn 419217309Snwhitehorn#define DIALOG_NAME(upper) { #upper, DLGK_ ## upper } 420217309Snwhitehorn#define COUNT_DIALOG sizeof(dialog_names)/sizeof(dialog_names[0]) 421217309Snwhitehornstatic const CODENAME dialog_names[] = 422217309Snwhitehorn{ 423217309Snwhitehorn DIALOG_NAME(OK), 424217309Snwhitehorn DIALOG_NAME(CANCEL), 425217309Snwhitehorn DIALOG_NAME(EXTRA), 426217309Snwhitehorn DIALOG_NAME(HELP), 427217309Snwhitehorn DIALOG_NAME(ESC), 428217309Snwhitehorn DIALOG_NAME(PAGE_FIRST), 429217309Snwhitehorn DIALOG_NAME(PAGE_LAST), 430217309Snwhitehorn DIALOG_NAME(PAGE_NEXT), 431217309Snwhitehorn DIALOG_NAME(PAGE_PREV), 432217309Snwhitehorn DIALOG_NAME(ITEM_FIRST), 433217309Snwhitehorn DIALOG_NAME(ITEM_LAST), 434217309Snwhitehorn DIALOG_NAME(ITEM_NEXT), 435217309Snwhitehorn DIALOG_NAME(ITEM_PREV), 436217309Snwhitehorn DIALOG_NAME(FIELD_FIRST), 437217309Snwhitehorn DIALOG_NAME(FIELD_LAST), 438217309Snwhitehorn DIALOG_NAME(FIELD_NEXT), 439217309Snwhitehorn DIALOG_NAME(FIELD_PREV), 440251843Sbapt DIALOG_NAME(FORM_FIRST), 441251843Sbapt DIALOG_NAME(FORM_LAST), 442251843Sbapt DIALOG_NAME(FORM_NEXT), 443251843Sbapt DIALOG_NAME(FORM_PREV), 444217309Snwhitehorn DIALOG_NAME(GRID_UP), 445217309Snwhitehorn DIALOG_NAME(GRID_DOWN), 446217309Snwhitehorn DIALOG_NAME(GRID_LEFT), 447217309Snwhitehorn DIALOG_NAME(GRID_RIGHT), 448217309Snwhitehorn DIALOG_NAME(DELETE_LEFT), 449217309Snwhitehorn DIALOG_NAME(DELETE_RIGHT), 450217309Snwhitehorn DIALOG_NAME(DELETE_ALL), 451217309Snwhitehorn DIALOG_NAME(ENTER), 452217309Snwhitehorn DIALOG_NAME(BEGIN), 453217309Snwhitehorn DIALOG_NAME(FINAL), 454251843Sbapt DIALOG_NAME(SELECT), 455251843Sbapt DIALOG_NAME(HELPFILE), 456251843Sbapt DIALOG_NAME(TRACE) 457217309Snwhitehorn}; 458217309Snwhitehorn 459217309Snwhitehornstatic char * 460217309Snwhitehornskip_white(char *s) 461217309Snwhitehorn{ 462217309Snwhitehorn while (*s != '\0' && isspace(UCH(*s))) 463217309Snwhitehorn ++s; 464217309Snwhitehorn return s; 465217309Snwhitehorn} 466217309Snwhitehorn 467217309Snwhitehornstatic char * 468217309Snwhitehornskip_black(char *s) 469217309Snwhitehorn{ 470217309Snwhitehorn while (*s != '\0' && !isspace(UCH(*s))) 471217309Snwhitehorn ++s; 472217309Snwhitehorn return s; 473217309Snwhitehorn} 474217309Snwhitehorn 475217309Snwhitehorn/* 476217309Snwhitehorn * Find a user-defined binding, given the curses key code. 477217309Snwhitehorn */ 478217309Snwhitehornstatic DLG_KEYS_BINDING * 479217309Snwhitehornfind_binding(char *widget, int curses_key) 480217309Snwhitehorn{ 481217309Snwhitehorn LIST_BINDINGS *p; 482217309Snwhitehorn DLG_KEYS_BINDING *result = 0; 483217309Snwhitehorn 484217309Snwhitehorn for (p = all_bindings; p != 0; p = p->link) { 485217309Snwhitehorn if (p->win == 0 486217309Snwhitehorn && !dlg_strcmp(p->name, widget) 487217309Snwhitehorn && p->binding->curses_key == curses_key) { 488217309Snwhitehorn result = p->binding; 489217309Snwhitehorn break; 490217309Snwhitehorn } 491217309Snwhitehorn } 492217309Snwhitehorn return result; 493217309Snwhitehorn} 494217309Snwhitehorn 495217309Snwhitehorn/* 496217309Snwhitehorn * Built-in bindings have a nonzero "win" member, and the associated binding 497217309Snwhitehorn * table can have more than one entry. We keep those last, since lookups will 498217309Snwhitehorn * find the user-defined bindings first and use those. 499217309Snwhitehorn * 500217309Snwhitehorn * Sort "*" (all-widgets) entries past named widgets, since those are less 501217309Snwhitehorn * specific. 502217309Snwhitehorn */ 503217309Snwhitehornstatic int 504217309Snwhitehorncompare_bindings(LIST_BINDINGS * a, LIST_BINDINGS * b) 505217309Snwhitehorn{ 506217309Snwhitehorn int result = 0; 507217309Snwhitehorn if (a->win == b->win) { 508217309Snwhitehorn if (!strcmp(a->name, b->name)) { 509217309Snwhitehorn result = a->binding[0].curses_key - b->binding[0].curses_key; 510251843Sbapt } else if (!strcmp(b->name, WILDNAME)) { 511217309Snwhitehorn result = -1; 512251843Sbapt } else if (!strcmp(a->name, WILDNAME)) { 513217309Snwhitehorn result = 1; 514217309Snwhitehorn } else { 515217309Snwhitehorn result = dlg_strcmp(a->name, b->name); 516217309Snwhitehorn } 517217309Snwhitehorn } else if (b->win) { 518217309Snwhitehorn result = -1; 519217309Snwhitehorn } else { 520217309Snwhitehorn result = 1; 521217309Snwhitehorn } 522217309Snwhitehorn return result; 523217309Snwhitehorn} 524217309Snwhitehorn 525217309Snwhitehorn/* 526217309Snwhitehorn * Find a user-defined binding, given the curses key code. If it does not 527217309Snwhitehorn * exist, create a new one, inserting it into the linked list, keeping it 528217309Snwhitehorn * sorted to simplify lookups for user-defined bindings that can override 529217309Snwhitehorn * the built-in bindings. 530217309Snwhitehorn */ 531217309Snwhitehornstatic DLG_KEYS_BINDING * 532217309Snwhitehornmake_binding(char *widget, int curses_key, int is_function, int dialog_key) 533217309Snwhitehorn{ 534217309Snwhitehorn LIST_BINDINGS *entry = 0; 535217309Snwhitehorn DLG_KEYS_BINDING *data = 0; 536217309Snwhitehorn char *name; 537217309Snwhitehorn LIST_BINDINGS *p, *q; 538217309Snwhitehorn DLG_KEYS_BINDING *result = find_binding(widget, curses_key); 539217309Snwhitehorn 540217309Snwhitehorn if (result == 0 541217309Snwhitehorn && (entry = dlg_calloc(LIST_BINDINGS, 1)) != 0 542217309Snwhitehorn && (data = dlg_calloc(DLG_KEYS_BINDING, 2)) != 0 543217309Snwhitehorn && (name = dlg_strclone(widget)) != 0) { 544217309Snwhitehorn 545217309Snwhitehorn entry->name = name; 546217309Snwhitehorn entry->binding = data; 547217309Snwhitehorn 548217309Snwhitehorn data[0].is_function_key = is_function; 549217309Snwhitehorn data[0].curses_key = curses_key; 550217309Snwhitehorn data[0].dialog_key = dialog_key; 551217309Snwhitehorn 552217309Snwhitehorn data[1] = end_keys_binding; 553217309Snwhitehorn 554217309Snwhitehorn for (p = all_bindings, q = 0; p != 0; q = p, p = p->link) { 555217309Snwhitehorn if (compare_bindings(entry, p) < 0) { 556217309Snwhitehorn break; 557217309Snwhitehorn } 558217309Snwhitehorn } 559217309Snwhitehorn if (q != 0) { 560217309Snwhitehorn q->link = entry; 561217309Snwhitehorn } else { 562217309Snwhitehorn all_bindings = entry; 563217309Snwhitehorn } 564217309Snwhitehorn if (p != 0) { 565217309Snwhitehorn entry->link = p; 566217309Snwhitehorn } 567217309Snwhitehorn result = data; 568217309Snwhitehorn } else if (entry != 0) { 569217309Snwhitehorn free(entry); 570217309Snwhitehorn if (data) 571217309Snwhitehorn free(data); 572217309Snwhitehorn } 573217309Snwhitehorn 574217309Snwhitehorn return result; 575217309Snwhitehorn} 576217309Snwhitehorn 577217309Snwhitehorn/* 578217309Snwhitehorn * Parse the parameters of the "bindkeys" configuration-file entry. This 579217309Snwhitehorn * expects widget name which may be "*", followed by curses key definition and 580217309Snwhitehorn * then dialog key definition. 581217309Snwhitehorn * 582217309Snwhitehorn * The curses key "should" be one of the names (ignoring case) from 583217309Snwhitehorn * curses_names[], but may also be a single control character (prefix "^" or 584217309Snwhitehorn * "~" depending on whether it is C0 or C1), or an escaped single character. 585217309Snwhitehorn * Binding a printable character with dialog is possible but not useful. 586217309Snwhitehorn * 587217309Snwhitehorn * The dialog key must be one of the names from dialog_names[]. 588217309Snwhitehorn */ 589217309Snwhitehornint 590217309Snwhitehorndlg_parse_bindkey(char *params) 591217309Snwhitehorn{ 592217309Snwhitehorn char *p = skip_white(params); 593217309Snwhitehorn char *q; 594217309Snwhitehorn bool escaped = FALSE; 595217309Snwhitehorn int modified = 0; 596217309Snwhitehorn int result = FALSE; 597217309Snwhitehorn unsigned xx; 598217309Snwhitehorn char *widget; 599217309Snwhitehorn int is_function = FALSE; 600217309Snwhitehorn int curses_key; 601217309Snwhitehorn int dialog_key; 602217309Snwhitehorn 603217309Snwhitehorn curses_key = -1; 604217309Snwhitehorn dialog_key = -1; 605217309Snwhitehorn widget = p; 606217309Snwhitehorn 607217309Snwhitehorn p = skip_black(p); 608217309Snwhitehorn if (p != widget && *p != '\0') { 609217309Snwhitehorn *p++ = '\0'; 610251843Sbapt p = skip_white(p); 611217309Snwhitehorn q = p; 612217309Snwhitehorn while (*p != '\0' && curses_key < 0) { 613217309Snwhitehorn if (escaped) { 614217309Snwhitehorn escaped = FALSE; 615217309Snwhitehorn curses_key = *p; 616217309Snwhitehorn } else if (*p == '\\') { 617217309Snwhitehorn escaped = TRUE; 618217309Snwhitehorn } else if (modified) { 619217309Snwhitehorn if (*p == '?') { 620217309Snwhitehorn curses_key = ((modified == '^') 621217309Snwhitehorn ? 127 622217309Snwhitehorn : 255); 623217309Snwhitehorn } else { 624217309Snwhitehorn curses_key = ((modified == '^') 625217309Snwhitehorn ? (*p & 0x1f) 626217309Snwhitehorn : ((*p & 0x1f) | 0x80)); 627217309Snwhitehorn } 628217309Snwhitehorn } else if (*p == '^') { 629217309Snwhitehorn modified = *p; 630217309Snwhitehorn } else if (*p == '~') { 631217309Snwhitehorn modified = *p; 632217309Snwhitehorn } else if (isspace(UCH(*p))) { 633217309Snwhitehorn break; 634217309Snwhitehorn } 635217309Snwhitehorn ++p; 636217309Snwhitehorn } 637217309Snwhitehorn if (!isspace(UCH(*p))) { 638217309Snwhitehorn ; 639217309Snwhitehorn } else { 640217309Snwhitehorn *p++ = '\0'; 641217309Snwhitehorn if (curses_key < 0) { 642217309Snwhitehorn char fprefix[2]; 643217309Snwhitehorn char check[2]; 644217309Snwhitehorn int keynumber; 645217309Snwhitehorn if (sscanf(q, "%[Ff]%d%c", fprefix, &keynumber, check) == 2) { 646217309Snwhitehorn curses_key = KEY_F(keynumber); 647217309Snwhitehorn is_function = TRUE; 648217309Snwhitehorn } else { 649217309Snwhitehorn for (xx = 0; xx < COUNT_CURSES; ++xx) { 650217309Snwhitehorn if (!dlg_strcmp(curses_names[xx].name, q)) { 651217309Snwhitehorn curses_key = curses_names[xx].code; 652251843Sbapt is_function = (curses_key >= KEY_MIN); 653217309Snwhitehorn break; 654217309Snwhitehorn } 655217309Snwhitehorn } 656217309Snwhitehorn } 657217309Snwhitehorn } 658217309Snwhitehorn } 659217309Snwhitehorn q = skip_white(p); 660217309Snwhitehorn p = skip_black(q); 661217309Snwhitehorn if (p != q) { 662217309Snwhitehorn for (xx = 0; xx < COUNT_DIALOG; ++xx) { 663217309Snwhitehorn if (!dlg_strcmp(dialog_names[xx].name, q)) { 664217309Snwhitehorn dialog_key = dialog_names[xx].code; 665217309Snwhitehorn break; 666217309Snwhitehorn } 667217309Snwhitehorn } 668217309Snwhitehorn } 669217309Snwhitehorn if (*widget != '\0' 670217309Snwhitehorn && curses_key >= 0 671217309Snwhitehorn && dialog_key >= 0 672217309Snwhitehorn && make_binding(widget, curses_key, is_function, dialog_key) != 0) { 673217309Snwhitehorn result = TRUE; 674217309Snwhitehorn } 675217309Snwhitehorn } 676217309Snwhitehorn return result; 677217309Snwhitehorn} 678217309Snwhitehorn 679217309Snwhitehornstatic void 680217309Snwhitehorndump_curses_key(FILE *fp, int curses_key) 681217309Snwhitehorn{ 682217309Snwhitehorn if (curses_key > KEY_MIN) { 683217309Snwhitehorn unsigned n; 684217309Snwhitehorn bool found = FALSE; 685217309Snwhitehorn for (n = 0; n < COUNT_CURSES; ++n) { 686217309Snwhitehorn if (curses_names[n].code == curses_key) { 687217309Snwhitehorn fprintf(fp, "%s", curses_names[n].name); 688217309Snwhitehorn found = TRUE; 689217309Snwhitehorn break; 690217309Snwhitehorn } 691217309Snwhitehorn } 692217309Snwhitehorn if (!found) { 693217309Snwhitehorn if (curses_key >= KEY_F(0)) { 694217309Snwhitehorn fprintf(fp, "F%d", curses_key - KEY_F(0)); 695217309Snwhitehorn } else { 696217309Snwhitehorn fprintf(fp, "curses%d", curses_key); 697217309Snwhitehorn } 698217309Snwhitehorn } 699217309Snwhitehorn } else if (curses_key >= 0 && curses_key < 32) { 700217309Snwhitehorn fprintf(fp, "^%c", curses_key + 64); 701217309Snwhitehorn } else if (curses_key == 127) { 702217309Snwhitehorn fprintf(fp, "^?"); 703217309Snwhitehorn } else if (curses_key >= 128 && curses_key < 160) { 704217309Snwhitehorn fprintf(fp, "~%c", curses_key - 64); 705217309Snwhitehorn } else if (curses_key == 255) { 706217309Snwhitehorn fprintf(fp, "~?"); 707217309Snwhitehorn } else { 708217309Snwhitehorn fprintf(fp, "\\%c", curses_key); 709217309Snwhitehorn } 710217309Snwhitehorn} 711217309Snwhitehorn 712217309Snwhitehornstatic void 713217309Snwhitehorndump_dialog_key(FILE *fp, int dialog_key) 714217309Snwhitehorn{ 715217309Snwhitehorn unsigned n; 716217309Snwhitehorn bool found = FALSE; 717217309Snwhitehorn for (n = 0; n < COUNT_DIALOG; ++n) { 718217309Snwhitehorn if (dialog_names[n].code == dialog_key) { 719217309Snwhitehorn fputs(dialog_names[n].name, fp); 720217309Snwhitehorn found = TRUE; 721217309Snwhitehorn break; 722217309Snwhitehorn } 723217309Snwhitehorn } 724217309Snwhitehorn if (!found) { 725217309Snwhitehorn fprintf(fp, "dialog%d", dialog_key); 726217309Snwhitehorn } 727217309Snwhitehorn} 728217309Snwhitehorn 729217309Snwhitehornstatic void 730217309Snwhitehorndump_one_binding(FILE *fp, const char *widget, DLG_KEYS_BINDING * binding) 731217309Snwhitehorn{ 732217309Snwhitehorn fprintf(fp, "bindkey %s ", widget); 733217309Snwhitehorn dump_curses_key(fp, binding->curses_key); 734217309Snwhitehorn fputc(' ', fp); 735217309Snwhitehorn dump_dialog_key(fp, binding->dialog_key); 736217309Snwhitehorn fputc('\n', fp); 737217309Snwhitehorn} 738217309Snwhitehorn 739251843Sbapt/* 740251843Sbapt * Dump bindings for the given window. If it is a null, then this dumps the 741251843Sbapt * initial bindings which were loaded from the rc-file that are used as 742251843Sbapt * overall defaults. 743251843Sbapt */ 744217309Snwhitehornvoid 745251843Sbaptdlg_dump_window_keys(FILE *fp, WINDOW *win) 746217309Snwhitehorn{ 747251843Sbapt if (fp != 0) { 748251843Sbapt LIST_BINDINGS *p; 749251843Sbapt DLG_KEYS_BINDING *q; 750251843Sbapt const char *last = ""; 751217309Snwhitehorn 752251843Sbapt for (p = all_bindings; p != 0; p = p->link) { 753251843Sbapt if (p->win == win) { 754217309Snwhitehorn if (dlg_strcmp(last, p->name)) { 755217309Snwhitehorn fprintf(fp, "\n# key bindings for %s widgets\n", 756251843Sbapt !strcmp(p->name, WILDNAME) ? "all" : p->name); 757217309Snwhitehorn last = p->name; 758217309Snwhitehorn } 759251843Sbapt for (q = p->binding; q->is_function_key >= 0; ++q) { 760251843Sbapt dump_one_binding(fp, p->name, q); 761251843Sbapt } 762217309Snwhitehorn } 763217309Snwhitehorn } 764217309Snwhitehorn } 765217309Snwhitehorn} 766251843Sbapt 767251843Sbapt/* 768251843Sbapt * Dump all of the bindings which are not specific to a given widget, i.e., 769251843Sbapt * the "win" member is null. 770251843Sbapt */ 771251843Sbaptvoid 772251843Sbaptdlg_dump_keys(FILE *fp) 773251843Sbapt{ 774251843Sbapt if (fp != 0) { 775251843Sbapt LIST_BINDINGS *p; 776251843Sbapt unsigned count = 0; 777251843Sbapt 778251843Sbapt for (p = all_bindings; p != 0; p = p->link) { 779251843Sbapt if (p->win == 0) { 780251843Sbapt ++count; 781251843Sbapt } 782251843Sbapt } 783251843Sbapt if (count != 0) { 784251843Sbapt dlg_dump_window_keys(fp, 0); 785251843Sbapt } 786251843Sbapt } 787251843Sbapt} 788217309Snwhitehorn#endif /* HAVE_RC_FILE */ 789