]> granicus.if.org Git - nethack/commitdiff
Qt menu sanity
authorPatR <rankin@nethack.org>
Mon, 10 Aug 2020 14:24:16 +0000 (07:24 -0700)
committerPatR <rankin@nethack.org>
Mon, 10 Aug 2020 14:24:16 +0000 (07:24 -0700)
The Qt menu entries which were executing nethack's help command
(the '?' menu) were doing so because their command keystroke was
a meta-character and such characters are being converted to '?'
to indicate an error in conversion to Latin1 character set.  The
old Qt3 code didn't perform any such conversion.

This fix feels fragile because there are two different places
deciding how to disambiguate partial extended commands (the code
for Qt's '#' handling and a new routine in the core).  Qt menus
now send '#' and enough letters to satisfy '#' handling for any
command which uses M-c or has no regular keystroke nor M-c one.
(If it were to send the full extended command name, the letters
after the unambiguous prefix would be left in the input queue to
be processed as subsequent commands.)

There is a fundamental problem that this doesn't address:  if
the player uses BIND directives in the run-time config file, the
Qt menu bindings will break unless the BINDs are all done before
selecting windowtype.  Qt's menu bindings translate a click on
a menu entry into the keystroke used to invoke the corresponding
command, so using BIND to change that after the menus are set up
will result in the wrong commands being executed.

doc/fixes37.0
include/extern.h
src/cmd.c
win/Qt/qt_main.cpp

index 869863efcdb55db09ba633e2fd41722f5d814bfa..ec0cd9f91631abd515a59c9476c5740c8de3866c 100644 (file)
@@ -1,4 +1,4 @@
-NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.279 $ $NHDT-Date: 1597010101 2020/08/09 21:55:01 $
+NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.280 $ $NHDT-Date: 1597069374 2020/08/10 14:22:54 $
 
 General Fixes and Modified Features
 -----------------------------------
@@ -364,6 +364,11 @@ Qt: add 3.6 status fields Stone, Slime, Strngl, Deaf, Lev, Fly, Ride
 Qt: add Attributes, Overview, and Annotate to the "Info" pull down menu
 Qt: rename menu entries game->Save to game->Save-and-exit and game->Quit
        to game->Quit-without-saving
+Qt: menu commands are now working; commands invoked via M-c were having that
+       keystroke changed to '?', bringing up nethack's help menu; now those
+       send #abc with just enough letters to disambiguate from other commands
+       ("Compilation" is one remaining problem; it yields "#version" which
+       brings up '#' menu subset with choices of "version" and "versionshort")
 Qt+QSX: fix control key
 Qt+OSX: rename menu entry "nethack->Preferences..." for invoking nethack's
        'O' command to "Game->Run-time options" and entry "Game->Qt settings"
index 77d4c6d5e40c2616e2a96efce8bcfda122104953..4374310353ab89afc2945841b01041122bdfaf3a 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.7 extern.h        $NHDT-Date: 1596498536 2020/08/03 23:48:56 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.854 $ */
+/* NetHack 3.7 extern.h        $NHDT-Date: 1597069374 2020/08/10 14:22:54 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.855 $ */
 /* Copyright (c) Steve Creps, 1988.                              */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -204,6 +204,7 @@ E void FDECL(random_response, (char *, int));
 E int NDECL(rnd_extcmd_idx);
 E int NDECL(domonability);
 E char FDECL(cmd_from_func, (int NDECL((*))));
+E const char *FDECL(cmdname_from_func, (int NDECL((*)), char *, BOOLEAN_P));
 E boolean FDECL(redraw_cmd, (CHAR_P));
 E const char *FDECL(levltyp_to_name, (int));
 #ifdef USE_TRAMPOLI
index c9ee5115b8eb10d03a5e1b16cce2982317c04204..19ae95498b440f40376676f7a1df74bb6a501258 100644 (file)
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -1,4 +1,4 @@
-/* NetHack 3.7 cmd.c   $NHDT-Date: 1596498153 2020/08/03 23:42:33 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.421 $ */
+/* NetHack 3.7 cmd.c   $NHDT-Date: 1597069374 2020/08/10 14:22:54 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.422 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2013. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -2278,6 +2278,57 @@ int NDECL((*fn));
     return '\0';
 }
 
+/* return extended command name (without leading '#') for command (*fn)() */
+const char *
+cmdname_from_func(fn, outbuf, fullname)
+int NDECL((*fn));
+char outbuf[];
+boolean fullname; /* False: just enough to disambiguate */
+{
+    const struct ext_func_tab *extcmd, *cmdptr = 0;
+    const char *res = 0;
+
+    for (extcmd = extcmdlist; extcmd->ef_txt; ++extcmd)
+        if (extcmd->ef_funct == fn) {
+            cmdptr = extcmd;
+            res = cmdptr->ef_txt;
+            break;
+        }
+
+    if (!res) {
+        /* make sure output buffer doesn't contain junk or stale data;
+           return Null below */
+        outbuf[0] = '\0';
+    } else if (fullname) {
+        /* easy; the entire command name */
+        res = strcpy(outbuf, res);
+    } else {
+        const struct ext_func_tab *matchcmd = extcmdlist;
+        int len = 0;
+
+        /* find the shortest leading substring which is unambiguous */
+        do {
+            if (++len >= (int) strlen(res))
+                break;
+            for (extcmd = matchcmd; extcmd->ef_txt; ++extcmd) {
+                if (extcmd == cmdptr)
+                    continue;
+                if ((extcmd->flags & CMD_NOT_AVAILABLE) != 0
+                    || ((extcmd->flags & WIZMODECMD) != 0 && !wizard))
+                    continue;
+                if (!strncmp(res, extcmd->ef_txt, len)) {
+                    matchcmd = extcmd;
+                    break;
+                }
+            }
+        } while (extcmd->ef_txt);
+        copynchars(outbuf, res, len);
+        debugpline2("shortened %s: \"%s\"", res, outbuf);
+        res = outbuf;
+    }
+    return res;
+}
+
 /*
  * wizard mode sanity_check code
  */
index 82bdf16ec949557ab9b2e4a019539b280f8efe95..32c791a029521dc334ed81c788c66d6e9b307464 100644 (file)
@@ -699,16 +699,24 @@ NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) :
            if (item[i].name) {
                 char actchar[32];
                 char menuitem[BUFSZ];
-                actchar[0] = '\0';
+                actchar[0] = actchar[1] = '\0';
                 if (item[i].funct) {
                     actchar[0] = cmd_from_func(item[i].funct);
-                    actchar[1] = '\0';
+                    /* M-c won't work */
+                    if ((actchar[0] & 0x7f) != actchar[0])
+                        actchar[0] = '\0';
                 }
                 if (actchar[0] && !qt_compact_mode)
-                    Sprintf(menuitem, "%s\t%s", item[i].name,
+                    Sprintf(menuitem, "%.50s\t%.9s", item[i].name,
                             visctrl(actchar[0]));
                 else
                     Sprintf(menuitem, "%s", item[i].name);
+
+                if (item[i].funct && !actchar[0]) {
+                    actchar[0] = '#';
+                    (void) cmdname_from_func(item[i].funct,
+                                             &actchar[1], FALSE);
+                }
                 if (actchar[0]) {
                     QString name = menuitem;
                     QAction *action = item[i].menu->addAction(name);
@@ -919,6 +927,12 @@ public:
 
 void NetHackQtMainWindow::doMenuItem(QAction *action)
 {
+    /* this converts meta characters to '?'; menu processing has been
+       changed to send multi-character "#abc" instead (already needed
+       for commands that didn't have either a regular keystroke or a
+       meta shortcut); it must send just enough to disambiguate from
+       other extended command names, otherwise the remainder would be
+       left in the queue for subsequent handling as additional commands */
     doKeys(action->data().toString());
 }
 
@@ -985,6 +999,8 @@ void NetHackQtMainWindow::doGuidebook(bool)
 
 void NetHackQtMainWindow::doKeys(const QString& k)
 {
+    /* [this should probably be using toLocal8Bit();
+       toAscii() is not offered as an alternative...] */
     keysink.Put(k.toLatin1().constData());
     qApp->exit();
 }