Subject: Re: bug#29272: 26.0.90; "C-h k C-mouse-3" followed by menu selection asks for more keys

From: Alan Mackenzie <[email-masked]>
Date: Sun, 19 Nov 2017 16:19:43 +0000

Hello, Eli.

On Sat, Nov 18, 2017 at 13:27:35 +0200, Eli Zaretskii wrote:
> > Date: Tue, 14 Nov 2017 20:54:49 +0000
> > Cc: [email-masked]
> > From: Alan Mackenzie <[email-masked]>

> > The following patch attempts to catch and filter out obtrusive events.
> > Could you try it out, please, even though it's not perfect (see below).
> > It's based on the emacs-26 branch:

> Thanks, this seems to fix the problem.  I take it that you've verified
> it doesn't re-introduce the original bug?

> > However, the problem is that in C-h k  C-mouse-3
> > <select-something-from-the-menus>, we get a spurious "translation"
> > message in *Help*, looking something like:

> >     <C-down-mouse-3> <file> <new-file> (translated from <mouse-1> <new-file>) at
> >     that spot runs the command find-file (found in global-map), which is an
> >     interactive compiled Lisp function in `files.el'.

> > That was from a Linux tty session using gpm.  In X, I got the message

> >     .... (translated from <C-down-mouse-3> <C-down-mouse-3> ....)

> I only see this in a text-mode frame (in my case it's "<mouse-1>
> <indent-pp-sexp>").  On GUI frame, there's no "translation".

Not on an X-Windows frame - X seems to handle all the mouse-movement and
intermediate click events itself.  On a linux tty with GPM, you do indeed
see these intermediate events.

> > .  I don't believe this glitch has to do with my patch - I think it's
> > been there for some while, but this bug has prevented it being seen
> > before.

> I think you are right, as I see the same problem in Emacs 24.5.

> In any case, this is a much more minor bug than the one I reported, so
> please install your changes on the release branch.  Bonus points if
> you can find where does the "translation" come from.

I claim my prize.  :-)

The following patch (which absolutely requires the patch to bug #29349
"read_key_sequence is only partially recursive.  This is a bug." to work)
fixes the above glitch on Linux tty (and possibly on other platforms).
It works by disregarding the "intermediate" events in UNTRANSLATED when
comparing the processed key sequence with the UNTRANSLATED string of
events:

diff --git a/lisp/help.el b/lisp/help.el
index 212e3679da..f5192e1902 100644
--- a/lisp/help.el
+++ b/lisp/help.el
@@ -583,14 +583,66 @@ where-is
 	  (princ string)))))
   nil)
 
+(defun help--equivalent-sequence-p (key untranslated)
+  "Is KEY a (possibly translated) version of UNTRANSLATED?
+If so return t, otherwise return nil.
+
+KEY is a key sequence, either a string or a vector.  UNTRANSLATED
+is a vector of events which gave rise to KEY, typically the output from
+`this-single-command-raw-keys'.
+
+The idea here is that for menu structure key sequences,
+UNTRANSLATED in certain environments contains things like
+<mouse-movement> and intermediate mouse button presses.  These
+will be disregarded in the comparison between KEY and
+UNTRANSLATED."
+  (let* ((len-key (length key))
+	 (len-unt (length untranslated))
+	 (key-idx 0)
+	 (unt-idx 0)
+	 key-elt unt-elt mods)
+    (cond
+     ((and (stringp key)
+	   (eq len-key len-unt))
+      (while (and (< key-idx len-key)
+		  (eq (aref key key-idx)
+		      (aref untranslated key-idx)))
+	(setq key-idx (1+ key-idx)))
+      (eq key-idx len-key))
+     ((vectorp key)
+      ;; In this while go round one elt of `key' each time round
+      (while
+	  (and (< key-idx len-key)
+	       (< unt-idx len-unt)
+	       (progn
+		 (setq key-elt (aref key key-idx))
+		 ;; In this while, skip an intermediate mouse click, etc.
+		 ;; from `untranslated' each time round.
+		 (while
+		     (and
+		      (< unt-idx len-unt)
+		      (progn
+			(setq unt-elt (aref untranslated unt-idx))
+			(not (eq unt-elt key-elt)))
+		      (progn
+			(setq mods (event-modifiers unt-elt))
+			(or (eq (car-safe unt-elt) 'mouse-movement)
+			    (cl-intersection '(click double triple drag down)
+					     mods))))
+		   (setq unt-idx (1+ unt-idx)))
+		 (eq unt-elt key-elt)))
+	(setq key-idx (1+ key-idx)
+	      unt-idx (1+ unt-idx)))
+      (eq key-idx len-key)))))
+
 (defun help-key-description (key untranslated)
   (let ((string (key-description key)))
     (if (or (not untranslated)
 	    (and (eq (aref untranslated 0) ?\e) (not (eq (aref key 0) ?\e))))
 	string
-      (let ((otherstring (key-description untranslated)))
-	(if (equal string otherstring)
-	    string
+      (if (help--equivalent-sequence-p key untranslated)
+          string
+        (let ((otherstring (key-description untranslated)))
 	  (format "%s (translated from %s)" string otherstring))))))
 
 (defun help--analyze-key (key untranslated)

> Thanks.

-- 
Alan Mackenzie (Nuremberg, Germany).