void parse_keybinding(char *ptr) { char *keyptr = NULL, *keycopy = NULL, *funcptr = NULL, *menuptr = NULL; sc *s, *newsc; int i, menu; assert(ptr != NULL); if (*ptr == '\0') { rcfile_error(N_("Missing key name")); return; } keyptr = ptr; ptr = parse_next_word(ptr); keycopy = mallocstrcpy(NULL, keyptr); for (i = 0; i < strlen(keycopy); i++) keycopy[i] = toupper(keycopy[i]); if (keycopy[0] != 'M' && keycopy[0] != '^' && keycopy[0] != 'F' && keycopy[0] != 'K') { rcfile_error( N_("keybindings must begin with \"^\", \"M\", or \"F\"")); return; } funcptr = ptr; ptr = parse_next_word(ptr); if (!strcmp(funcptr, "")) { rcfile_error( N_("Must specify function to bind key to")); return; } menuptr = ptr; ptr = parse_next_word(ptr); if (!strcmp(menuptr, "")) { rcfile_error( /* Note to translators, do not translate the word "all" in the sentence below, everything else is fine */ N_("Must specify menu to bind key to (or \"all\")")); return; } newsc = strtosc(menu, funcptr); if (newsc == NULL) { rcfile_error( N_("Could not map name \"%s\" to a function"), funcptr); return; } menu = strtomenu(menuptr); if (menu < 1) { rcfile_error( N_("Could not map name \"%s\" to a menu"), menuptr); return; } #ifdef DEBUG fprintf(stderr, "newsc now address %d, menu func assigned = %d, menu = %d\n", &newsc, newsc->scfunc, menu); #endif newsc->keystr = keycopy; newsc->menu = menu; newsc->type = strtokeytype(newsc->keystr); assign_keyinfo(newsc); #ifdef DEBUG fprintf(stderr, "s->keystr = \"%s\"\n", newsc->keystr); fprintf(stderr, "s->seq = \"%d\"\n", newsc->seq); #endif if (check_bad_binding(newsc)) { rcfile_error( N_("Sorry, keystr \"%s\" is an illegal binding"), newsc->keystr); return; } /* now let's have some fun. Try and delete the other entries we found for the same menu, then make this new new beginning */ for (s = sclist; s != NULL; s = s->next) { if (((s->menu & newsc->menu)) && s->seq == newsc->seq) { s->menu &= ~newsc->menu; #ifdef DEBUG fprintf(stderr, "replaced menu entry %d\n", s->menu); #endif } } newsc->next = sclist; sclist = newsc; }
/* Bind or unbind a key combo, to or from a function. */ void parse_binding(char *ptr, bool dobind) { char *keyptr = NULL, *keycopy = NULL, *funcptr = NULL, *menuptr = NULL; sc *s, *newsc = NULL; int menu; assert(ptr != NULL); #ifdef DEBUG fprintf(stderr, "Starting the rebinding code...\n"); #endif if (*ptr == '\0') { rcfile_error(N_("Missing key name")); return; } keyptr = ptr; ptr = parse_next_word(ptr); keycopy = mallocstrcpy(NULL, keyptr); if (strlen(keycopy) < 2) { rcfile_error(N_("Key name is too short")); return; } /* Uppercase only the first two or three characters of the key name. */ keycopy[0] = toupper(keycopy[0]); keycopy[1] = toupper(keycopy[1]); if (keycopy[0] == 'M' && keycopy[1] == '-') { if (strlen(keycopy) > 2) keycopy[2] = toupper(keycopy[2]); else { rcfile_error(N_("Key name is too short")); return; } } /* Allow the codes for Insert and Delete to be rebound, but apart * from those two only Control, Meta and Function sequences. */ if (!strcasecmp(keycopy, "Ins") || !strcasecmp(keycopy, "Del")) keycopy[1] = tolower(keycopy[1]); else if (keycopy[0] != '^' && keycopy[0] != 'M' && keycopy[0] != 'F') { rcfile_error(N_("Key name must begin with \"^\", \"M\", or \"F\"")); return; } if (dobind) { funcptr = ptr; ptr = parse_next_word(ptr); if (funcptr[0] == '\0') { rcfile_error(N_("Must specify a function to bind the key to")); return; } } menuptr = ptr; ptr = parse_next_word(ptr); if (menuptr[0] == '\0') { /* TRANSLATORS: Do not translate the word "all". */ rcfile_error(N_("Must specify a menu (or \"all\") in which to bind/unbind the key")); return; } if (dobind) { newsc = strtosc(funcptr); if (newsc == NULL) { rcfile_error(N_("Cannot map name \"%s\" to a function"), funcptr); return; } } menu = strtomenu(menuptr); if (menu < 1) { rcfile_error(N_("Cannot map name \"%s\" to a menu"), menuptr); return; } #ifdef DEBUG if (dobind) fprintf(stderr, "newsc address is now %ld, assigned func = %ld, menu = %x\n", (long)&newsc, (long)newsc->scfunc, menu); else fprintf(stderr, "unbinding \"%s\" from menu %x\n", keycopy, menu); #endif if (dobind) { subnfunc *f; int mask = 0; /* Tally up the menus where the function exists. */ for (f = allfuncs; f != NULL; f = f->next) if (f->scfunc == newsc->scfunc) mask = mask | f->menus; /* Handle the special case of the toggles. */ if (newsc->scfunc == do_toggle_void) mask = MMAIN; /* Now limit the given menu to those where the function exists. */ if (is_universal(newsc->scfunc)) menu = menu & MMOST; else menu = menu & mask; if (!menu) { rcfile_error(N_("Function '%s' does not exist in menu '%s'"), funcptr, menuptr); free(newsc); return; } newsc->keystr = keycopy; newsc->menu = menu; newsc->type = strtokeytype(newsc->keystr); assign_keyinfo(newsc); #ifdef DEBUG fprintf(stderr, "s->keystr = \"%s\"\n", newsc->keystr); fprintf(stderr, "s->seq = \"%d\"\n", newsc->seq); #endif if (check_bad_binding(newsc)) { rcfile_error(N_("Sorry, keystroke \"%s\" may not be rebound"), newsc->keystr); free(newsc); return; } } /* Now find and delete any existing same shortcut in the menu(s). */ for (s = sclist; s != NULL; s = s->next) { if (((s->menu & menu)) && !strcmp(s->keystr, keycopy)) { #ifdef DEBUG fprintf(stderr, "deleting entry from menu %x\n", s->menu); #endif s->menu &= ~menu; } } if (dobind) { /* Add the new shortcut at the start of the list. */ newsc->next = sclist; sclist = newsc; } }