]> granicus.if.org Git - nethack/commitdiff
Rudimentary key rebinding in game options
authorPasi Kallinen <paxed@alt.org>
Thu, 4 Aug 2022 11:00:47 +0000 (14:00 +0300)
committerPasi Kallinen <paxed@alt.org>
Thu, 4 Aug 2022 11:42:45 +0000 (14:42 +0300)
Currently shown only in the full options list, as it's not
quite complete. (For example, it doesn't handle movement commands,
or the getpos keys)

doc/fixes3-7-0.txt
include/extern.h
include/optlist.h
src/cmd.c
src/options.c

index 01ddfb0df62d556d3e2fbf0e61419e2d05bc6b17..f4654e37fd5b0b194bb583921b728870acd874c4 100644 (file)
@@ -1764,6 +1764,7 @@ some quest nemeses release a cloud of poisonous gas when they die
 taming magic acting on an already tame creature might make it become tamer
 eliminate scimitar skill and have scimitars use saber skill
 simplified configuration options menu
+rudimentary key rebinding in game options
 
 
 Platform- and/or Interface-Specific New Features
index 40817593d4ddd9bbff0d6e1d5c01e16a40df0160..c9508c9ae64ef07fc33411b7ee4980c1cb5f6600 100644 (file)
@@ -264,6 +264,8 @@ extern void savech_extcmd(const char *, boolean);
 extern char extcmd_initiator(void);
 extern int doextcmd(void);
 extern struct ext_func_tab *extcmds_getentry(int);
+extern int count_bind_keys(void);
+extern void handler_rebind_keys(void);
 extern int extcmds_match(const char *, int, int **);
 extern const char *key2extcmddesc(uchar);
 extern boolean bind_specialkey(uchar, const char *);
index 18d59f645f8898163785e4ce270471d6e012fd4d..fdbbc12e7d0c5bba46224c55066b55492ee5276c 100644 (file)
@@ -132,6 +132,8 @@ opt_##a,
                  + sizeof "kick" + sizeof "force" + 20),
                 opt_out, set_in_game, Yes, Yes, No, Yes, NoAlias,
                 "action to take when encountering locked door or chest")
+    NHOPTO("bind keys", Advanced, o_bind_keys, BUFSZ, opt_in,
+           set_in_game, No, Yes, No, NoAlias, "edit key binds")
 #if defined(MICRO) && !defined(AMIGA)
     NHOPTB(BIOS, Advanced, 0, opt_in, set_in_config, Off, Yes, No, No, NoAlias,
                 &iflags.BIOS)
index 7f3efa76078ff5b89fb6d825dafe367d3d93e5ca..ac742d95e71040a2a715683215bce951446f6f68 100644 (file)
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -161,6 +161,7 @@ static char *parse(void);
 static void show_direction_keys(winid, char, boolean);
 static boolean help_dir(char, uchar, const char *);
 
+static void handler_rebind_keys_add(boolean);
 static boolean bind_key_fn(uchar, int (*)(void));
 static void commands_init(void);
 static boolean keylist_func_has_key(const struct ext_func_tab *, boolean *);
@@ -2826,6 +2827,187 @@ extcmds_getentry(int i)
     return &extcmdlist[i];
 }
 
+/* return number of extended commands bound to a non-default key */
+int
+count_bind_keys(void)
+{
+    int nbinds = 0;
+    int i;
+
+    for (i = 0; i < extcmdlist_length; i++)
+        if (extcmdlist[i].key && g.Cmd.commands[extcmdlist[i].key] != &extcmdlist[i])
+            nbinds++;
+    return nbinds;
+}
+
+static void
+display_changed_key_binds(void)
+{
+    winid win;
+    int i;
+    char buf[BUFSZ];
+    char buf2[QBUFSZ];
+
+    win = create_nhwindow(NHW_TEXT);
+    for (i = 0; i < extcmdlist_length; i++) {
+        struct ext_func_tab *ec = &extcmdlist[i];
+
+        if (ec->key && g.Cmd.commands[ec->key]
+            && g.Cmd.commands[ec->key] != ec) {
+            Sprintf(buf, "BIND=%s:%s", key2txt(ec->key, buf2),
+                    g.Cmd.commands[ec->key]->ef_txt);
+            putstr(win, 0, buf);
+        }
+    }
+    display_nhwindow(win, TRUE);
+    destroy_nhwindow(win);
+}
+
+/* interactive key binding */
+static void
+handler_rebind_keys_add(boolean keyfirst)
+{
+    struct ext_func_tab *ec;
+    winid win;
+    anything any;
+    int i, npick;
+    menu_item *picks = (menu_item *) 0;
+    char buf[BUFSZ];
+    char buf2[QBUFSZ];
+    uchar key = '\0';
+
+    if (keyfirst) {
+        pline("Bind which key? ");
+        key = pgetchar();
+
+        if (!key || key == '\027')
+            return;
+    }
+
+    win = create_nhwindow(NHW_MENU);
+    start_menu(win, MENU_BEHAVE_STANDARD);
+    any = cg.zeroany;
+
+    if (key) {
+        if (g.Cmd.commands[key]) {
+            Sprintf(buf, "Key '%s' is currently bound to \"%s\".",
+                    key2txt(key, buf2), g.Cmd.commands[key]->ef_txt);
+        } else {
+            Sprintf(buf, "Key '%s' is not bound to anything.",
+                    key2txt(key, buf2));
+        }
+        add_menu(win, &nul_glyphinfo, &any, '\0', 0, ATR_NONE, 0, buf,
+                 MENU_ITEMFLAGS_NONE);
+        add_menu(win, &nul_glyphinfo, &any, '\0', 0, ATR_NONE, 0, "",
+                 MENU_ITEMFLAGS_NONE);
+    }
+
+    any.a_int = -1;
+    add_menu(win, &nul_glyphinfo, &any, '\0', 0, ATR_NONE, 0, "nothing: unbind the key",
+             MENU_ITEMFLAGS_NONE);
+
+    any.a_int = 0;
+    add_menu(win, &nul_glyphinfo, &any, '\0', 0, ATR_NONE, 0, "",
+             MENU_ITEMFLAGS_NONE);
+
+    for (i = 0; i < extcmdlist_length; i++) {
+        ec = &extcmdlist[i];
+
+        if ((ec->flags & (MOVEMENTCMD|INTERNALCMD|CMD_NOT_AVAILABLE)) != 0)
+            continue;
+
+        any.a_int = (i + 1);
+        Sprintf(buf, "%s: %s", ec->ef_txt, ec->ef_desc);
+        add_menu(win, &nul_glyphinfo, &any, '\0', 0, ATR_NONE, 0, buf,
+             MENU_ITEMFLAGS_NONE);
+    }
+    if (key)
+        Sprintf(buf, "Bind '%s' to what command?", key2txt(key, buf2));
+    else
+        Sprintf(buf, "Bind what command?");
+    end_menu(win, buf);
+    npick = select_menu(win, PICK_ONE, &picks);
+    destroy_nhwindow(win);
+    if (npick > 0) {
+        const struct ext_func_tab *prevec;
+        const char *cmdstr;
+
+        i = picks->item.a_int;
+        free((genericptr_t) picks);
+
+        if (i == -1) {
+            ec = NULL;
+            cmdstr = "nothing";
+            goto bindit;
+        } else {
+            ec = &extcmdlist[i-1];
+            cmdstr = ec->ef_txt;
+        }
+bindit:
+        if (!key) {
+            pline("Bind which key? ");
+            key = pgetchar();
+
+            if (!key || key == '\027')
+                return;
+        }
+
+        prevec = g.Cmd.commands[key];
+
+        if (bind_key(key, cmdstr)) {
+            if (prevec && prevec != ec) {
+                pline("Changed key '%s' from \"%s\" to \"%s\".",
+                      key2txt(key, buf2), prevec->ef_txt, cmdstr);
+            } else if (!prevec) {
+                pline("Bound key '%s' to \"%s\".", key2txt(key, buf2), cmdstr);
+            }
+        } else {
+            pline("Key binding failed?!");
+        }
+    }
+}
+
+void
+handler_rebind_keys(void)
+{
+    winid win;
+    anything any;
+    int i, npick;
+    menu_item *picks = (menu_item *) 0;
+
+redo_rebind:
+
+    win = create_nhwindow(NHW_MENU);
+    start_menu(win, MENU_BEHAVE_STANDARD);
+    any = cg.zeroany;
+
+    any.a_int = 1;
+    add_menu(win, &nul_glyphinfo, &any, '\0', 0, ATR_NONE, 0, "bind key to a command",
+             MENU_ITEMFLAGS_NONE);
+    any.a_int = 2;
+    add_menu(win, &nul_glyphinfo, &any, '\0', 0, ATR_NONE, 0, "bind command to a key",
+             MENU_ITEMFLAGS_NONE);
+    if (count_bind_keys()) {
+        any.a_int = 3;
+        add_menu(win, &nul_glyphinfo, &any, '\0', 0, ATR_NONE, 0, "view changed key binds",
+                 MENU_ITEMFLAGS_NONE);
+    }
+    end_menu(win, "Do what?");
+    npick = select_menu(win, PICK_ONE, &picks);
+    destroy_nhwindow(win);
+    if (npick > 0) {
+        i = picks->item.a_int;
+        free((genericptr_t) picks);
+
+        if (i == 1 || i == 2) {
+            handler_rebind_keys_add((i == 1));
+        } else if (i == 3) {
+            display_changed_key_binds();
+        }
+        goto redo_rebind;
+    }
+}
+
 /* find extended command entries matching findstr.
    if findstr is NULL, returns all available entries.
    returns: number of matching extended commands,
index af149a928c408f0dfd6f81e94ce0f571dae88b52..0d2ad23a8bb2a70752d215b037329371bb8b1188 100644 (file)
@@ -7567,6 +7567,28 @@ optfn_o_autopickup_exceptions(
     return optn_ok;
 }
 
+static int
+optfn_o_bind_keys(
+    int optidx UNUSED, int req, boolean negated UNUSED,
+    char *opts, char *op UNUSED)
+{
+    if (req == do_init) {
+        return optn_ok;
+    }
+    if (req == do_set) {
+    }
+    if (req == get_val) {
+        if (!opts)
+            return optn_err;
+        Sprintf(opts, n_currently_set, count_bind_keys());
+        return optn_ok;
+    }
+    if (req == do_handler) {
+        handler_rebind_keys();
+    }
+    return optn_ok;
+}
+
 static int
 optfn_o_menu_colors(int optidx UNUSED, int req, boolean negated UNUSED,
               char *opts, char *op UNUSED)