Subject: bug#31692: Emacs sometimes drops key events

From: Michael Heerdegen <[email-masked]>
Date: Sat, 09 Jun 2018 00:17:47 +0200

Stefan Monnier <[email-masked]> writes:

> As a consequence, instead of
>
>     (throw 'throw-on-input t)
>
> we need to throw like
>
>     (throw throw-on-input t)
>
> and we additionally need to (setq quit-flag nil) before that.

I tried to adapt Eli's patch accordingly.  To avoid confusion, I simply
use the concrete value - the CATCH-SYM - and just return t instead of
throwing:

diff --git a/lisp/subr.el b/lisp/subr.el
index 914112ccef..7734006d87 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -3520,9 +3520,25 @@ while-no-input
   (let ((catch-sym (make-symbol "input")))
     `(with-local-quit
        (catch ',catch-sym
-	 (let ((throw-on-input ',catch-sym))
-	   (or (input-pending-p)
-	       (progn ,@body)))))))
+	 (let ((throw-on-input ',catch-sym)
+               val)
+           (setq val
+	         (or (input-pending-p)
+	             (progn ,@body)))
+           (cond
+            ;; If quit-flag is bound to the CATCH-SYM, it means BODY
+            ;; didn't test quit-flag, and therefore ran to completion
+            ;; even though input arrived before it finished.  In that
+            ;; case, we must reset quit-flag (and return t), because
+            ;; otherwise quit-flag will remain set, and we get Quit to
+            ;; top-level, which has undesirable consequences, such as
+            ;; discarding input etc.
+            ((eq quit-flag ',catch-sym)
+             (setq quit-flag nil)
+             t)
+            ;; This is in case the user actually quits while BODY runs.
+            (quit-flag nil)
+            (t val)))))))
 
 (defmacro condition-case-unless-debug (var bodyform &rest handlers)
   "Like `condition-case' except that it does not prevent debugging.

Michael.