Subject: Re: bug#45292: Acknowledgement (28.0.50; first key typed ignores current input method (in magit commit buffer))

From: Stefan Monnier <[email-masked]>
Date: Wed, 23 Dec 2020 18:32:20 -0500

> Digged into it further. Here's what I found:
>
> 1. quail-input-method is used to translate keys according current keymap.
>
> 2. At the time of the first keystroke ("j" in my example) quail-input-method
> sees incorrect buffer (verified this by calling and printing buffer-name
> from inside quail-input-method). It sees "magit: test-repo" on the first
> keystroke, and "COMMIT_EDITMSG" on subsequent keystrokes. And since "magit:
> test-repo" is read-only, no translation is done and key is returned as-is.
>
> 3. So apparently record_asynch_buffer_change() was crucial to update the current buffer.

Here's what's happening:
1- after hitting `c c`, Magit launches `git` in the background
2- at this point we're entering `read_char` and the current buffer is the
   Magit buffer.
3- soon after, git launches the editor, which Magit has set to emacsclient
4- emacsclient contacts us
5- while still in `read_char` is waiting in `sit_for`, we process
   emacsclient which sets up the git-commit buffer,
   displays it and select it as the main window.
6- `sit_for` carefully preserves the current buffer so after step 5,
   we're still in the Magit buffer even though the selected windows is
   not the git-commit one.
7- we hit `j` in the git-commit buffer/window but it's read while in
   cvs-commit
8- boom!

I installed the patch below which fixes this problem.

        Stefan

diff --git a/src/dispnew.c b/src/dispnew.c
index bcea26a66a..534002584e 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -6062,6 +6062,8 @@ sit_for (Lisp_Object timeout, bool reading, int display_option)
   intmax_t sec;
   int nsec;
   bool do_display = display_option > 0;
+  bool curbuf_eq_winbuf
+    = (current_buffer == XBUFFER (XWINDOW (selected_window)->contents));
 
   swallow_events (do_display);
 
@@ -6116,6 +6118,13 @@ sit_for (Lisp_Object timeout, bool reading, int display_option)
   wait_reading_process_output (sec, nsec, reading ? -1 : 1, do_display,
 			       Qnil, NULL, 0);
 
+  if (reading && curbuf_eq_winbuf)
+    /* Timers and process filters/sentinels may have changed the selected
+       window (e.g. in response to a connection from emacsclient), in which
+       case we should follow it (unless we weren't in the selected-window's
+       buffer to start with).  */
+    set_buffer_internal (XBUFFER (XWINDOW (selected_window)->contents));
+
   return detect_input_pending () ? Qnil : Qt;
 }