Subject: Re: bug#50067: Context menus

From: Juri Linkov <[email-masked]>
Date: Mon, 27 Sep 2021 18:30:23 +0300

Other programs don't show the keys in context menus.
The Human Interface Guidelines say:

  Show keyboard shortcuts in menu bar menus, not contextual menus.
  Contextual menus are already shortcuts to task-specific commands;
  it's redundant to display keyboard shortcuts too.

This patch hides all keys from the context menus:

diff --git a/lisp/mouse.el b/lisp/mouse.el
index 5f3db46516..2d9b1c8f0b 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -314,7 +314,9 @@ context-menu-map
 it overrides all functions from `context-menu-functions'.
 At the end, it's possible to modify the final menu by specifying
 the function `context-menu-filter-function'."
-  (let* ((menu (make-sparse-keymap (propertize "Context Menu" 'hide t)))
+  (let* ((menu (make-sparse-keymap (propertize "Context Menu"
+                                               'hide t
+                                               'no-keys t)))
          (click (or click last-input-event))
          (fun (mouse-posn-property (event-start click)
                                    'context-menu-function)))
diff --git a/src/keyboard.c b/src/keyboard.c
index 462b415c1d..8c90292137 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -7832,16 +7832,20 @@ parse_menu_item (Lisp_Object item, int inmenubar)
 		filter = item;
 	      else if (EQ (tem, QCkey_sequence))
 		{
-		  tem = XCAR (item);
-		  if (SYMBOLP (tem) || STRINGP (tem) || VECTORP (tem))
-		    /* Be GC protected. Set keyhint to item instead of tem.  */
-		    keyhint = item;
-		}
+		  if (!inhibit_menu_keys)
+		    {
+		      tem = XCAR (item);
+		      if (SYMBOLP (tem) || STRINGP (tem) || VECTORP (tem))
+			/* Be GC protected. Set keyhint to item instead of tem.  */
+			keyhint = item;
+		    }		}
 	      else if (EQ (tem, QCkeys))
 		{
-		  tem = XCAR (item);
-		  if (CONSP (tem) || STRINGP (tem))
-		    ASET (item_properties, ITEM_PROPERTY_KEYEQ, tem);
+		  if (!inhibit_menu_keys){
+		    tem = XCAR (item);
+		    if (CONSP (tem) || STRINGP (tem))
+		      ASET (item_properties, ITEM_PROPERTY_KEYEQ, tem);
+		  }
 		}
 	      else if (EQ (tem, QCbutton) && CONSP (XCAR (item)))
 		{
@@ -7916,6 +7920,7 @@ parse_menu_item (Lisp_Object item, int inmenubar)
   if (inmenubar > 0)
     return 1;
 
+  if (!inhibit_menu_keys)
   { /* This is a command.  See if there is an equivalent key binding.  */
     Lisp_Object keyeq = AREF (item_properties, ITEM_PROPERTY_KEYEQ);
     AUTO_STRING (space_space, "  ");
@@ -12495,6 +12500,11 @@ syms_of_keyboard (void)
                Vwhile_no_input_ignore_events,
                doc: /* Ignored events from while-no-input.  */);
 
+  DEFVAR_BOOL ("inhibit-menu-keys",
+               inhibit_menu_keys,
+               doc: /* If non-nil, inhibit menu keys.  */);
+  inhibit_menu_keys = false;
+
   pdumper_do_now_and_after_load (syms_of_keyboard_for_pdumper);
 }
 
diff --git a/src/menu.c b/src/menu.c
index 1aafa78c3c..e7e7ecca6a 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -1281,13 +1281,18 @@ x_popup_menu_1 (Lisp_Object position, Lisp_Object menu)
       /* We were given a keymap.  Extract menu info from the keymap.  */
       Lisp_Object prompt;
 
-      /* Extract the detailed info to make one pane.  */
-      keymap_panes (&menu, 1);
-
       /* Search for a string appearing directly as an element of the keymap.
 	 That string is the title of the menu.  */
       prompt = Fkeymap_prompt (keymap);
 
+      if (STRINGP (prompt)
+	  && SCHARS (prompt) > 0
+	  && !NILP (Fget_text_property (make_fixnum (0), Qno_keys, prompt)))
+      specbind (Qinhibit_menu_keys, Qt);
+
+      /* Extract the detailed info to make one pane.  */
+      keymap_panes (&menu, 1);
+
 #if defined (USE_GTK) || defined (HAVE_NS)
       if (STRINGP (prompt)
 	  && SCHARS (prompt) > 0
@@ -1583,6 +1588,8 @@ syms_of_menu (void)
   staticpro (&menu_items);
 
   DEFSYM (Qhide, "hide");
+  DEFSYM (Qno_keys, "no-keys");
+  DEFSYM (Qinhibit_menu_keys, "inhibit-menu-keys");
 
   defsubr (&Sx_popup_menu);
   defsubr (&Sx_popup_dialog);