From debbugs-submit-bounces@debbugs.gnu.org Mon Feb 12 14:36:56 2024 Received: (at submit) by debbugs.gnu.org; 12 Feb 2024 19:36:56 +0000 Received: from localhost ([127.0.0.1]:52515 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rZc6p-00057d-3n for submit@debbugs.gnu.org; Mon, 12 Feb 2024 14:36:55 -0500 Received: from lists.gnu.org ([2001:470:142::17]:56002) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rZc6m-00056s-Ed for submit@debbugs.gnu.org; Mon, 12 Feb 2024 14:36:53 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rZc6N-00069Y-Jz for bug-gnu-emacs@gnu.org; Mon, 12 Feb 2024 14:36:28 -0500 Received: from mail-out.m-online.net ([212.18.0.9]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rZc6K-0007k9-Ga for bug-gnu-emacs@gnu.org; Mon, 12 Feb 2024 14:36:26 -0500 Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 4TYZSz3YxMz1r1sg for ; Mon, 12 Feb 2024 20:36:19 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.68]) by mail.m-online.net (Postfix) with ESMTP id 4TYZSz3TMtz1qqlS for ; Mon, 12 Feb 2024 20:36:19 +0100 (CET) X-Virus-Scanned: amavis at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.68]) (amavis, port 10024) with ESMTP id SqAYZKzWCJVT for ; Mon, 12 Feb 2024 20:36:18 +0100 (CET) X-Auth-Info: tSfx832Ou24euc5EdZ/yFyWL4qJpZebs2tDmg6bkzPkIQmpWuyWOt+aGP8rrlTfk Received: from Whiteflame (ppp-212-114-182-193.dynamic.mnet-online.de [212.114.182.193]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA for ; Mon, 12 Feb 2024 20:36:18 +0100 (CET) User-agent: mu4e 1.10.8; emacs 29.2 From: Raffael Stocker To: bug-gnu-emacs@gnu.org Subject: Emacs's keyboard hook state is not reset on session lock (Windows) Date: Mon, 12 Feb 2024 20:04:50 +0100 Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Received-SPF: pass client-ip=212.18.0.9; envelope-from=r.stocker@mnet-mail.de; helo=mail-out.m-online.net X-Spam_score_int: 7 X-Spam_score: 0.7 X-Spam_bar: / X-Spam_report: (0.7 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_SBL_CSS=3.335, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=no autolearn_force=no X-Spam_action: no action X-Spam-Score: 4.5 (++++) X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Hi, when locking the computer using WIN+L on Windows, Emacs is supposed to reset its keyboard hook state. This is done in the function ‘reset_w32_kbdhook_state’ in ‘w32fns.c’, which is called upon [...] Content analysis details: (4.5 points, 10.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 3.6 RCVD_IN_SBL_CSS RBL: Received via a relay in Spamhaus SBL-CSS [212.114.182.193 listed in zen.spamhaus.org] 1.0 SPF_SOFTFAIL SPF: sender does not match SPF record (softfail) -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 T_SCC_BODY_TEXT_LINE No description available. X-Debbugs-Envelope-To: submit X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: 3.5 (+++) X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Hi, when locking the computer using WIN+L on Windows, Emacs is supposed to reset its keyboard hook state. This is done in the function ‘reset_w32_kbdhook_state’ in ‘w32fns.c’, which is called upon [...] Content analysis details: (3.5 points, 10.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 3.6 RCVD_IN_SBL_CSS RBL: Received via a relay in Spamhaus SBL-CSS [212.114.182.193 listed in zen.spamhaus.org] 1.0 SPF_SOFTFAIL SPF: sender does not match SPF record (softfail) -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 T_SCC_BODY_TEXT_LINE No description available. -1.0 MAILING_LIST_MULTI Multiple indicators imply a widely-seen list manager --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hi, when locking the computer using WIN+L on Windows, Emacs is supposed to reset its keyboard hook state. This is done in the function =E2=80=98reset_w32_kbdhook_state=E2=80=99 in =E2=80=98w32fns.c=E2=80=99, wh= ich is called upon receiving the =E2=80=98WM_WTSSESSION_CHANGE=E2=80=99 message with the =E2=80=98WTS_SE= SSION_LOCK=E2=80=99 parameter. However, this message is never received, because to receive it, an application must register for session notifications, which Emacs doesn't do. When Emacs can't reset its state, the handling of the windows key is confused after locking and unlocking the computer, but the issue seems to auto-correct when a windows key is pressed again. I didn't observe any real problem with it, but I have not configured any non-default handling of the windows keys in Emacs. It may be different in those cases. Note that while this bug looks like it might be connected to bug#68914, I believe it's a separate issue. The behaviour described there is neither triggered by this bug nor solved by the attached patch. The attached patch rectifies the situation, but to do so, Emacs must be linked with =E2=80=98wtsapi32.dll=E2=80=99. I am not sure whether there is= a different way of resetting the state that doesn't require the introduction of a new dependency. To receive session notifications, one must provide a window handle, which is fine if Emacs does not run in console mode. I don't know whether it is possible to get these notifications in console Emacs; at least using the console handle didn't work for me. I also noticed that while the keyboard hook is set up in console mode using =E2=80=98setup_w32_kbdhook=E2=80=99, there does not seem to be a corr= esponding call to =E2=80=98remove_w32_kbdhook=E2=80=99. Also, in console mode the ke= yboard hook is always installed, while in GUI Emacs it is only installed when =E2=80=98WINDOWSNT=E2=80=99 is defined. I have zero experience in Windows programming, so it would be highly desirable if someone with more knowledge could comment on the issue and my proposed solution. Regards, Raffael --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=reset_kbdhook.patch Content-Description: session notification patch diff --git a/configure.ac b/configure.ac index 847fdbd54d2..415430de417 100644 --- a/configure.ac +++ b/configure.ac @@ -3090,6 +3090,7 @@ AC_DEFUN fi W32_LIBS="$W32_LIBS -lwinmm -lusp10 -lgdi32 -lcomdlg32" W32_LIBS="$W32_LIBS -lmpr -lwinspool -lole32 -lcomctl32" + W32_LIBS="$W32_LIBS -lwtsapi32" W32_RES_LINK="\$(EMACSRES)" CLIENTRES="emacsclient.res" CLIENTW="emacsclientw\$(EXEEXT)" diff --git a/src/w32console.c b/src/w32console.c index 0936b5f37e6..0bd23f06832 100644 --- a/src/w32console.c +++ b/src/w32console.c @@ -821,8 +821,12 @@ initialize_w32_display (struct terminal *term, int *width, int *height) /* Setup w32_display_info structure for this frame. */ w32_initialize_display_info (build_string ("Console")); +#ifdef WINDOWSNT /* Set up the keyboard hook. */ - setup_w32_kbdhook (); + /* FIXME where can this be cleaned up, that is, where can we call + remove_w32_kbdhook? */ + setup_w32_kbdhook (NULL); +#endif } diff --git a/src/w32fns.c b/src/w32fns.c index 8d4bd00b91c..1d5a591466c 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -49,6 +49,7 @@ #define _WIN32_WINNT 0x0600 #ifdef WINDOWSNT #include #include /* for _getmbcp */ +#include /* for WTS(Un)RegisterSessionNotificationEx */ #endif /* WINDOWSNT */ #if CYGWIN @@ -2744,7 +2745,7 @@ funhook (int code, WPARAM w, LPARAM l) /* Set up the hook; can be called several times, with matching remove_w32_kbdhook calls. */ void -setup_w32_kbdhook (void) +setup_w32_kbdhook (HWND hwnd) { kbdhook.hook_count++; @@ -2800,17 +2801,22 @@ setup_w32_kbdhook (void) /* Set the hook. */ kbdhook.hook = SetWindowsHookEx (WH_KEYBOARD_LL, funhook, GetModuleHandle (NULL), 0); + if (hwnd != NULL) + WTSRegisterSessionNotificationEx (WTS_CURRENT_SERVER, hwnd, + NOTIFY_FOR_THIS_SESSION); } } /* Remove the hook. */ void -remove_w32_kbdhook (void) +remove_w32_kbdhook (HWND hwnd) { kbdhook.hook_count--; if (kbdhook.hook_count == 0 && w32_kbdhook_active) { UnhookWindowsHookEx (kbdhook.hook); + if (hwnd != NULL) + WTSUnRegisterSessionNotificationEx (WTS_CURRENT_SERVER, hwnd); kbdhook.hook = NULL; } } @@ -5301,13 +5307,13 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) #ifdef WINDOWSNT case WM_CREATE: - setup_w32_kbdhook (); + setup_w32_kbdhook (hwnd); goto dflt; #endif case WM_DESTROY: #ifdef WINDOWSNT - remove_w32_kbdhook (); + remove_w32_kbdhook (hwnd); #endif CoUninitialize (); return 0; diff --git a/src/w32term.h b/src/w32term.h index 29ace0b2797..374c8055ed8 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -779,8 +779,8 @@ #define FILE_NOTIFICATIONS_SIZE 16384 #ifdef WINDOWSNT /* Keyboard hooks. */ -extern void setup_w32_kbdhook (void); -extern void remove_w32_kbdhook (void); +extern void setup_w32_kbdhook (HWND); +extern void remove_w32_kbdhook (HWND); extern int check_w32_winkey_state (int); #define w32_kbdhook_active (os_subtype != OS_SUBTYPE_9X) #else --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Mon Feb 12 15:45:45 2024 Received: (at 69083) by debbugs.gnu.org; 12 Feb 2024 20:45:45 +0000 Received: from localhost ([127.0.0.1]:57765 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rZdBQ-0004w7-IB for submit@debbugs.gnu.org; Mon, 12 Feb 2024 15:45:45 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:58636) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rZdBO-0004vW-7u for 69083@debbugs.gnu.org; Mon, 12 Feb 2024 15:45:43 -0500 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rZcqL-0007ea-Hm; Mon, 12 Feb 2024 15:23:57 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From: Date; bh=zxwqDLcxDEsjgYZ8/HwbpyQj1N/pkcH5SrRfTxAbzFg=; b=i5T1AG+ObMdHGbL2hhB4 NQnBjPdkKuG2IEm9rQ6vAw1KGXjrvTj2U7ekF3HUuenNChw34q5pYJS9cLtnfHtyztjTWTVUPJHnM liwt0aHo1WEu7e0D5QS2GzTWQg+WmElpv0FUJd6YRPJUWVA2u+yX+BZxvhDgvZZz9kXC3GJ8unyqi iHI1KEmqfXoEBc+sm8ehJQgrLJn6eNYcXIEWkXq7Y9+rxmLehAG3gVnhEL/wB/kwqTWHJ8LwnKR8o vDYOrG5W+H630NSsaEWc9jmXpGm+Dm5NtZl5IpfBkMYT1HKF9QV2NzzFtFdvlggckqmBdh/xR642r T4n2zjS4lfUrBA==; Date: Mon, 12 Feb 2024 22:23:54 +0200 Message-Id: <86cyt1qvmt.fsf@gnu.org> From: Eli Zaretskii To: Raffael Stocker In-Reply-To: (message from Raffael Stocker on Mon, 12 Feb 2024 20:04:50 +0100) Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) References: MIME-version: 1.0 Content-type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 69083 Cc: 69083@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: Raffael Stocker > Date: Mon, 12 Feb 2024 20:04:50 +0100 > > when locking the computer using WIN+L on Windows, Emacs is supposed to > reset its keyboard hook state. This is done in the function > ‘reset_w32_kbdhook_state’ in ‘w32fns.c’, which is called upon receiving > the ‘WM_WTSSESSION_CHANGE’ message with the ‘WTS_SESSION_LOCK’ > parameter. However, this message is never received, because to receive > it, an application must register for session notifications, which Emacs > doesn't do. > > When Emacs can't reset its state, the handling of the windows key is > confused after locking and unlocking the computer, but the issue seems > to auto-correct when a windows key is pressed again. I didn't observe > any real problem with it, but I have not configured any non-default > handling of the windows keys in Emacs. It may be different in those > cases. > > Note that while this bug looks like it might be connected to bug#68914, > I believe it's a separate issue. The behaviour described there is > neither triggered by this bug nor solved by the attached patch. > > The attached patch rectifies the situation, but to do so, Emacs must be > linked with ‘wtsapi32.dll’. I am not sure whether there is a different > way of resetting the state that doesn't require the introduction of a > new dependency. We can use that DLL, but we cannot link against it, because that would make the DLL a prerequisite for running Emacs, and then it will be impossible to start Emacs on Windows versions before XP, where that DLL was introduced. So we need to load that DLL at run time via LoadLibrary, and only register for session notifications if the DLL is available, by calling the DLL functions through function pointers -- this way, the Emacs executable doesn't have a static link-time dependency on the DLL. You will find many examples of this technique in w32.c and in other w32*.c files in Emacs. (I'm a bit surprised that Remote Desktop Services need to be used for this purpose. Are you sure there's no other way for Emacs to know that the system is going to be locked? Where did you read about the need to reset the keyboard hook state in that case, and the way to do it?) > To receive session notifications, one must provide a window handle, > which is fine if Emacs does not run in console mode. I don't know > whether it is possible to get these notifications in console Emacs; at > least using the console handle didn't work for me. Please try the technique used by the function find_child_console which is defined in w32proc.c. > I also noticed that while the keyboard hook is set up in console mode > using ‘setup_w32_kbdhook’, there does not seem to be a corresponding > call to ‘remove_w32_kbdhook’. Doesn't Windows remove the hook when the process exits? > Also, in console mode the keyboard hook is always installed, while > in GUI Emacs it is only installed when ‘WINDOWSNT’ is defined. That's because w32console.c is not compiled into the Cygwin build (which does not define WINDOWSNT), whereas w32fns.c is. > @@ -2800,17 +2801,22 @@ setup_w32_kbdhook (void) > /* Set the hook. */ > kbdhook.hook = SetWindowsHookEx (WH_KEYBOARD_LL, funhook, > GetModuleHandle (NULL), 0); > + if (hwnd != NULL) > + WTSRegisterSessionNotificationEx (WTS_CURRENT_SERVER, hwnd, > + NOTIFY_FOR_THIS_SESSION); Do we really need to use WTSRegisterSessionNotificationEx? Can't we use WTSRegisterSessionNotification instead? AFAIK, the latter is available since Windows XP, whereas the former only since Vista. Thanks. From debbugs-submit-bounces@debbugs.gnu.org Wed Feb 14 15:58:50 2024 Received: (at 69083) by debbugs.gnu.org; 14 Feb 2024 20:58:50 +0000 Received: from localhost ([127.0.0.1]:53255 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1raMLB-0003Yf-SA for submit@debbugs.gnu.org; Wed, 14 Feb 2024 15:58:50 -0500 Received: from mail-out.m-online.net ([212.18.0.9]:53003) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1raML8-0003YV-Td for 69083@debbugs.gnu.org; Wed, 14 Feb 2024 15:58:48 -0500 Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 4TZrBq365Cz1qsPZ; Wed, 14 Feb 2024 21:58:27 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.68]) by mail.m-online.net (Postfix) with ESMTP id 4TZrBq1tBnz1qqlW; Wed, 14 Feb 2024 21:58:27 +0100 (CET) X-Virus-Scanned: amavis at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.68]) (amavis, port 10024) with ESMTP id s5Wecemvidn9; Wed, 14 Feb 2024 21:58:25 +0100 (CET) X-Auth-Info: swj2Jo+6+H9jcdyJvNGXPJNkF6MHP4A5ILBd8okrMpJXsGDlEdaKqi5oUXoVzNS3 Received: from Whiteflame (ppp-212-114-182-219.dynamic.mnet-online.de [212.114.182.219]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA; Wed, 14 Feb 2024 21:58:25 +0100 (CET) References: <86cyt1qvmt.fsf@gnu.org> User-agent: mu4e 1.10.8; emacs 29.2 From: Raffael Stocker To: Eli Zaretskii Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) Date: Wed, 14 Feb 2024 21:20:35 +0100 In-reply-to: <86cyt1qvmt.fsf@gnu.org> Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: 0.7 (/) X-Debbugs-Envelope-To: 69083 Cc: 69083@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.3 (/) --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Eli Zaretskii writes: > So we need to load that DLL at run time via LoadLibrary, ... I have added that. > (I'm a bit surprised that Remote Desktop Services need to be used for > this purpose. Are you sure there's no other way for Emacs to know > that the system is going to be locked? Where did you read about the > need to reset the keyboard hook state in that case, and the way to do > it?) For me, the need to reset the hook state is implied by the existence of the =E2=80=98reset_w32_kbdhook_state=E2=80=99 function defined in =E2=80=98= w32fns.c=E2=80=99 and its call site. This function has been there since 2016, but was never called, because the =E2=80=98WM_WTSSESSION_CHANGE=E2=80=99 message wasn't r= eceived. >From [0]: MS> This message is sent only to applications that have registered to MS> receive this message by calling WTSRegisterSessionNotification. This seems to be the only way to find out it's being locked; at least I couldn't find anything indicating otherwise on the Microsoft website and a quick web search didn't turn up anything either. >> To receive session notifications, one must provide a window handle, >> which is fine if Emacs does not run in console mode. I don't know >> whether it is possible to get these notifications in console Emacs; at >> least using the console handle didn't work for me. > > Please try the technique used by the function find_child_console which > is defined in w32proc.c. Unfortunately, this didn't work for me. I tried calling =E2=80=98EnumWindows(find_child_console, ...)=E2=80=99 with a =E2=80=98chil= d_process=E2=80=99 instance containing the current process id as returned by =E2=80=98GetCurrentProcess= Id=E2=80=99, but I don't seem to get a useful window handle. I must be doing something wrong here. OTOH, [1] says: MS> Note For Windows 8 and later, EnumWindows enumerates only top-level MS> windows of desktop apps. Does this mean that =E2=80=98EnumWindows=E2=80=99 it doesn't work for conso= le windows or is this remark irrelevant here? I am not familiar with the Windows terminology. Come to think of it, don't I need the window handle of the console window that Emacs is running in, which would imply that a handle for Emacs' pid doesn't exist? I was starting Emacs in cmd.exe using =E2=80=98e= macs -Q -nw=E2=80=99, so I would probably have to find the pid of the =E2=80=98c= md=E2=80=99 process first, right? >> I also noticed that while the keyboard hook is set up in console mode >> using =E2=80=98setup_w32_kbdhook=E2=80=99, there does not seem to be a c= orresponding >> call to =E2=80=98remove_w32_kbdhook=E2=80=99. > > Doesn't Windows remove the hook when the process exits? According to [2] we have to remove the hook: MS> Before terminating, an application must call the UnhookWindowsHookEx MS> function function to free system resources associated with the hook. >> Also, in console mode the keyboard hook is always installed, while >> in GUI Emacs it is only installed when =E2=80=98WINDOWSNT=E2=80=99 is de= fined. > > That's because w32console.c is not compiled into the Cygwin build > (which does not define WINDOWSNT), whereas w32fns.c is. Ok, that makes sense, I have removed my superfluous #ifdef. > Do we really need to use WTSRegisterSessionNotificationEx? Can't we > use WTSRegisterSessionNotification instead? AFAIK, the latter is > available since Windows XP, whereas the former only since Vista. Yes, =E2=80=98WTSRegisterSessionNotification=E2=80=99 works, too. However,= [3] says that the minimum supported client here is Windows Vista, as with the =E2=80=98-Ex=E2=80=99 version. I attached my current patch version. Regards, Raffael [0] https://learn.microsoft.com/en-us/windows/win32/termserv/wm-wtssession-= change [1] https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-= enumwindows [2] https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-= setwindowshookexa [3] https://learn.microsoft.com/en-us/windows/win32/api/wtsapi32/nf-wtsapi3= 2-wtsregistersessionnotification --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=reset_kbdhook_1.patch Content-Description: reset kbdhook patch diff --git a/src/w32console.c b/src/w32console.c index 0936b5f37e6..2161e738252 100644 --- a/src/w32console.c +++ b/src/w32console.c @@ -822,7 +822,9 @@ initialize_w32_display (struct terminal *term, int *width, int *height) w32_initialize_display_info (build_string ("Console")); /* Set up the keyboard hook. */ - setup_w32_kbdhook (); + /* FIXME where can this be cleaned up, that is, where can we call + remove_w32_kbdhook? */ + setup_w32_kbdhook (NULL); } diff --git a/src/w32fns.c b/src/w32fns.c index 8d4bd00b91c..1f2a68c2fed 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -49,6 +49,7 @@ #define _WIN32_WINNT 0x0600 #ifdef WINDOWSNT #include #include /* for _getmbcp */ +#include /* for WTS(Un)RegisterSessionNotificationEx */ #endif /* WINDOWSNT */ #if CYGWIN @@ -204,6 +205,10 @@ DECLARE_HANDLE(HMONITOR); typedef HRESULT (WINAPI * DwmSetWindowAttribute_Proc) (HWND hwnd, DWORD dwAttribute, IN LPCVOID pvAttribute, DWORD cbAttribute); +typedef BOOL (WINAPI * WTSRegisterSessionNotification_Proc) + (HWND hwnd, DWORD dwFlags); +typedef BOOL (WINAPI * WTSUnRegisterSessionNotification_Proc) (HWND hwnd); + TrackMouseEvent_Proc track_mouse_event_fn = NULL; ImmGetCompositionString_Proc get_composition_string_fn = NULL; ImmGetContext_Proc get_ime_context_fn = NULL; @@ -2744,7 +2749,7 @@ funhook (int code, WPARAM w, LPARAM l) /* Set up the hook; can be called several times, with matching remove_w32_kbdhook calls. */ void -setup_w32_kbdhook (void) +setup_w32_kbdhook (HWND hwnd) { kbdhook.hook_count++; @@ -2800,17 +2805,35 @@ setup_w32_kbdhook (void) /* Set the hook. */ kbdhook.hook = SetWindowsHookEx (WH_KEYBOARD_LL, funhook, GetModuleHandle (NULL), 0); + if (hwnd != NULL) + { + HMODULE wtsapi32_lib = LoadLibrary ("wtsapi32.dll"); + WTSRegisterSessionNotification_Proc WTSRegisterSessionNotification_fn + = (WTSRegisterSessionNotification_Proc) + get_proc_addr (wtsapi32_lib, "WTSRegisterSessionNotification"); + if (WTSRegisterSessionNotification_fn != NULL) + WTSRegisterSessionNotification_fn (hwnd, NOTIFY_FOR_THIS_SESSION); + } } } /* Remove the hook. */ void -remove_w32_kbdhook (void) +remove_w32_kbdhook (HWND hwnd) { kbdhook.hook_count--; if (kbdhook.hook_count == 0 && w32_kbdhook_active) { UnhookWindowsHookEx (kbdhook.hook); + if (hwnd != NULL) + { + HMODULE wtsapi32_lib = GetModuleHandle ("wtsapi32.dll"); + WTSUnRegisterSessionNotification_Proc WTSUnRegisterSessionNotification_fn + = (WTSUnRegisterSessionNotification_Proc) + get_proc_addr (wtsapi32_lib, "WTSUnRegisterSessionNotification"); + if (WTSUnRegisterSessionNotification_fn != NULL) + WTSUnRegisterSessionNotification_fn (hwnd); + } kbdhook.hook = NULL; } } @@ -5301,13 +5324,13 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) #ifdef WINDOWSNT case WM_CREATE: - setup_w32_kbdhook (); + setup_w32_kbdhook (hwnd); goto dflt; #endif case WM_DESTROY: #ifdef WINDOWSNT - remove_w32_kbdhook (); + remove_w32_kbdhook (hwnd); #endif CoUninitialize (); return 0; diff --git a/src/w32term.h b/src/w32term.h index 29ace0b2797..374c8055ed8 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -779,8 +779,8 @@ #define FILE_NOTIFICATIONS_SIZE 16384 #ifdef WINDOWSNT /* Keyboard hooks. */ -extern void setup_w32_kbdhook (void); -extern void remove_w32_kbdhook (void); +extern void setup_w32_kbdhook (HWND); +extern void remove_w32_kbdhook (HWND); extern int check_w32_winkey_state (int); #define w32_kbdhook_active (os_subtype != OS_SUBTYPE_9X) #else --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Thu Feb 15 01:39:13 2024 Received: (at 69083) by debbugs.gnu.org; 15 Feb 2024 06:39:13 +0000 Received: from localhost ([127.0.0.1]:53856 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1raVOq-00036x-Op for submit@debbugs.gnu.org; Thu, 15 Feb 2024 01:39:13 -0500 Received: from eggs.gnu.org ([209.51.188.92]:44260) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1raVOo-00036i-2H for 69083@debbugs.gnu.org; Thu, 15 Feb 2024 01:39:10 -0500 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1raVMH-0001Xs-0p; Thu, 15 Feb 2024 01:36:33 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From: Date; bh=8YmV262C+Y51OKb3Ai/gpjyGfRI7XAUv9IBzP1SdJZU=; b=PTR9pmC4n5K2S64YL7jo UdSBa/UHUSdS/7/KHdalgFzLL4uLz0hT+9sgon1rEmat0luwuCSaRmaKExSc06EUNIdtjXaZHT2DY 4aQhYi2qRPy2RR27b0sUcDyexqPLQnu/xu5WnlOJ7kR4dj3fjfTZk5TWEGTDlPjnkqmg5hAAQ6G5L KLVXEbwQAaQSOAQohMCVTn5GKtX2PQ8cd+h/8A+EN2YwIqiLqhV10v8GFz1rijDOjZmV2MJ08wmYI cfEWZsfBeoI/aeZMV2LezQ8V5n/uElj0UVSixnMzPWSPBbpSme6JNQscI/i4Jcvvzz8IzMVO0Fx7v mvNJ8+bcQBOeEw==; Date: Thu, 15 Feb 2024 08:36:29 +0200 Message-Id: <861q9exmhe.fsf@gnu.org> From: Eli Zaretskii To: Raffael Stocker In-Reply-To: (message from Raffael Stocker on Wed, 14 Feb 2024 21:20:35 +0100) Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) References: <86cyt1qvmt.fsf@gnu.org> MIME-version: 1.0 Content-type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -4.2 (----) X-Debbugs-Envelope-To: 69083 Cc: 69083@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -5.2 (-----) > From: Raffael Stocker > Cc: 69083@debbugs.gnu.org > Date: Wed, 14 Feb 2024 21:20:35 +0100 > > > So we need to load that DLL at run time via LoadLibrary, ... > > I have added that. Thanks. I suggest one optimization: instead of probing whether LoadLibrary succeeds in two places, do it only once, where you call WTSRegisterSessionNotification, and at that time also record the function pointer for WTSUnRegisterSessionNotification; then use the 2nd function pointer, if non-NULL, to call the unregister API. > > (I'm a bit surprised that Remote Desktop Services need to be used for > > this purpose. Are you sure there's no other way for Emacs to know > > that the system is going to be locked? Where did you read about the > > need to reset the keyboard hook state in that case, and the way to do > > it?) > > For me, the need to reset the hook state is implied by the existence of > the ‘reset_w32_kbdhook_state’ function defined in ‘w32fns.c’ and its > call site. This function has been there since 2016, but was never > called, because the ‘WM_WTSSESSION_CHANGE’ message wasn't received. > >From [0]: > > MS> This message is sent only to applications that have registered to > MS> receive this message by calling WTSRegisterSessionNotification. > > This seems to be the only way to find out it's being locked; at least I > couldn't find anything indicating otherwise on the Microsoft website and > a quick web search didn't turn up anything either. This URL: https://stackoverflow.com/questions/8606300/how-to-detect-windows-is-locked seems to indicate that WTSRegisterSessionNotification requires elevation on Windows 10/11. Did you get the UAC prompt when calling that API? Are you running with admin privileges when you test this code? Triggering UAC prompts when starting Emacs would be a nuisance to our users. > >> To receive session notifications, one must provide a window handle, > >> which is fine if Emacs does not run in console mode. I don't know > >> whether it is possible to get these notifications in console Emacs; at > >> least using the console handle didn't work for me. > > > > Please try the technique used by the function find_child_console which > > is defined in w32proc.c. > > Unfortunately, this didn't work for me. I tried calling > ‘EnumWindows(find_child_console, ...)’ with a ‘child_process’ instance > containing the current process id as returned by ‘GetCurrentProcessId’, > but I don't seem to get a useful window handle. What do you mean? What is the result of using find_child_console? does the condition in find_child_console, which looks at the process_id of all windows, never match the process ID of the Emacs session running with -nw? Or what else goes wrong? > I must be doing something wrong here. OTOH, [1] says: > > MS> Note For Windows 8 and later, EnumWindows enumerates only top-level > MS> windows of desktop apps. > > Does this mean that ‘EnumWindows’ it doesn't work for console windows or > is this remark irrelevant here? I am not familiar with the Windows > terminology. I think it does work with console windows, since that's what Emacs uses it for (the sub-processes Emacs runs are almost always console processes). > Come to think of it, don't I need the window handle of the console > window that Emacs is running in, which would imply that a handle for > Emacs' pid doesn't exist? I was starting Emacs in cmd.exe using ‘emacs > -Q -nw’, so I would probably have to find the pid of the ‘cmd’ process > first, right? Maybe, I don't know. But first, I'd like to understand what goes wrong when you are looking for a window for which GetWindowThreadProcessId returns the PID of Emacs. > > Do we really need to use WTSRegisterSessionNotificationEx? Can't we > > use WTSRegisterSessionNotification instead? AFAIK, the latter is > > available since Windows XP, whereas the former only since Vista. > > Yes, ‘WTSRegisterSessionNotification’ works, too. However, [3] says > that the minimum supported client here is Windows Vista, as with the > ‘-Ex’ version. That's a lie. The MS docs frequently pretend that old versions of Windows don't exist, and this is one such case. From debbugs-submit-bounces@debbugs.gnu.org Tue Feb 20 14:30:19 2024 Received: (at 69083) by debbugs.gnu.org; 20 Feb 2024 19:30:19 +0000 Received: from localhost ([127.0.0.1]:46582 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rcVoo-0002Cb-LU for submit@debbugs.gnu.org; Tue, 20 Feb 2024 14:30:19 -0500 Received: from mail-out.m-online.net ([212.18.0.10]:41605) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rcVoi-0002CL-Sd for 69083@debbugs.gnu.org; Tue, 20 Feb 2024 14:30:16 -0500 Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 4TfTxn1vlYz1s94n; Tue, 20 Feb 2024 20:29:48 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.68]) by mail.m-online.net (Postfix) with ESMTP id 4TfTxm64Zqz1qqlW; Tue, 20 Feb 2024 20:29:48 +0100 (CET) X-Virus-Scanned: amavis at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.68]) (amavis, port 10024) with ESMTP id DZoXOjh4GzOS; Tue, 20 Feb 2024 20:29:47 +0100 (CET) X-Auth-Info: 0ZVOo3kQrM0X3uQXzMBI+ARJZgeO5W2G1FUduyMSkGxNZxdsiN4jxnw5y/sGef1K Received: from Whiteflame (ppp-212-114-182-230.dynamic.mnet-online.de [212.114.182.230]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA; Tue, 20 Feb 2024 20:29:47 +0100 (CET) References: <86cyt1qvmt.fsf@gnu.org> <861q9exmhe.fsf@gnu.org> User-agent: mu4e 1.10.8; emacs 29.2 From: Raffael Stocker To: Eli Zaretskii Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) Date: Tue, 20 Feb 2024 19:51:21 +0100 In-reply-to: <861q9exmhe.fsf@gnu.org> Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Score: -2.6 (--) X-Debbugs-Envelope-To: 69083 Cc: 69083@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.6 (---) Eli Zaretskii writes: >> From: Raffael Stocker >> Cc: 69083@debbugs.gnu.org >> Date: Wed, 14 Feb 2024 21:20:35 +0100 >>=20 >> > So we need to load that DLL at run time via LoadLibrary, ... >>=20 >> I have added that. > > Thanks. I suggest one optimization: instead of probing whether > LoadLibrary succeeds in two places, do it only once, where you call > WTSRegisterSessionNotification, and at that time also record the > function pointer for WTSUnRegisterSessionNotification; then use the > 2nd function pointer, if non-NULL, to call the unregister API. Yes, I can do that. I will leave the initialisation in the setup_w32_kbdhook function as the branch with the call to LoadLibrary should be executed only once. I experimented a bit today and found that the remove_w32_kbdhook function is not actually getting called when Emacs is being killed. It is only called when the Emacs window receives a WM_DESTROY message. But we get relevant WM_* messages, when - creating second frame with =E2=80=98C-x 5 2=E2=80=99 and closing it us= ing =E2=80=98C-x 5 0=E2=80=99: WM_EMACS_DESTROYWINDOW, then WM_DESTROY - creating second frame with =E2=80=98C-x 5 2=E2=80=99 and closing it by= clicking =E2=80=98X=E2=80=99 in frame decoration: WM_CLOSE, then WM_EMACS_DESTROYWINDOW, then WM_DESTROY - closing the last frame by clicking =E2=80=98X=E2=80=99 in frame decora= tion: WM_CLOSE - killing Emacs with =E2=80=98C-x C-c=E2=80=99: nothing At least, if Emacs is not run as daemon. Then, the WM_DESTROY is only handled when there is still another frame, and in this case =E2=80=98remove_w32_kbdhook=E2=80=99 will not remove the hook as kbdhook.ho= ok_count > 1. If Emacs is run as daemon, it cleans up the keyboard hook when closing the last window. Is there a better place where the remove_w32_kbdhook call could go such that cleanup can always happen? Or should we just not care? > This URL: > > https://stackoverflow.com/questions/8606300/how-to-detect-windows-is-lo= cked > > seems to indicate that WTSRegisterSessionNotification requires > elevation on Windows 10/11. Did you get the UAC prompt when calling > that API? Are you running with admin privileges when you test this > code? Triggering UAC prompts when starting Emacs would be a nuisance > to our users. I have read this post, but it seems to be wrong. I don't have any elevated privileges and it works without showing any prompt, at least on Windows 10. I'll try to have my colleague test it as well, she runs Windows 11. >> Unfortunately, this didn't work for me. I tried calling >> =E2=80=98EnumWindows(find_child_console, ...)=E2=80=99 with a =E2=80=98c= hild_process=E2=80=99 instance >> containing the current process id as returned by =E2=80=98GetCurrentProc= essId=E2=80=99, >> but I don't seem to get a useful window handle. > > What do you mean? What is the result of using find_child_console? > does the condition in find_child_console, which looks at the > process_id of all windows, never match the process ID of the Emacs > session running with -nw? Or what else goes wrong? I'm not quite sure myself what I mean. I will experiment with this a bit more and try to find out what's happening. Regards, Raffael From debbugs-submit-bounces@debbugs.gnu.org Wed Feb 21 07:38:25 2024 Received: (at 69083) by debbugs.gnu.org; 21 Feb 2024 12:38:25 +0000 Received: from localhost ([127.0.0.1]:48004 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rclrl-0006zf-4b for submit@debbugs.gnu.org; Wed, 21 Feb 2024 07:38:25 -0500 Received: from eggs.gnu.org ([209.51.188.92]:52420) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rclrf-0006zO-E8 for 69083@debbugs.gnu.org; Wed, 21 Feb 2024 07:38:23 -0500 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rclrD-0007cS-1Y; Wed, 21 Feb 2024 07:37:51 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From: Date; bh=NCVDmmfyQ0+FK5Q1IfZQFNaCoFSanqGKBQwYFYgIo30=; b=XGy6Hu7NCkR68Mu7qq0U 1CwC0QWKVNcmWerGPCOPKlIFW+WcU9uEh00G3o5ZssI7djg/IPrLAmdIvSO8F1PgR0Mw4pltdfsmz LI1yueH41yZyOlaJa+Xem6AajZJQBJtus6oCsD1em2bhfGC7+A7VC7AfvALC+VwT0V0KScmflOKGi viZaMGk4yvFs0nttuFHQE0AcMR6yVvVXqFKJezmQSR13ak/6h1Nrkdl4mESfphMpWVsHHaaUnf/PX PBp8LW/637xY1ihu3Qqq2nC6cE87NOc5jSg9aQqi2T3LEjQBJyiJYrTVWQJZHOhVMATYLLxlOHJaB gmy24nSVh8vo3Q==; Date: Wed, 21 Feb 2024 14:37:46 +0200 Message-Id: <86v86im1r9.fsf@gnu.org> From: Eli Zaretskii To: Raffael Stocker In-Reply-To: (message from Raffael Stocker on Tue, 20 Feb 2024 19:51:21 +0100) Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) References: <86cyt1qvmt.fsf@gnu.org> <861q9exmhe.fsf@gnu.org> MIME-version: 1.0 Content-type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -4.2 (----) X-Debbugs-Envelope-To: 69083 Cc: 69083@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -5.2 (-----) > From: Raffael Stocker > Cc: 69083@debbugs.gnu.org > Date: Tue, 20 Feb 2024 19:51:21 +0100 > > I experimented a bit today and found that the remove_w32_kbdhook > function is not actually getting called when Emacs is being killed. It > is only called when the Emacs window receives a WM_DESTROY message. But > we get relevant WM_* messages, when > > - creating second frame with ‘C-x 5 2’ and closing it using ‘C-x 5 0’: > WM_EMACS_DESTROYWINDOW, then WM_DESTROY > - creating second frame with ‘C-x 5 2’ and closing it by clicking ‘X’ > in frame decoration: > WM_CLOSE, then WM_EMACS_DESTROYWINDOW, then WM_DESTROY > - closing the last frame by clicking ‘X’ in frame decoration: WM_CLOSE > - killing Emacs with ‘C-x C-c’: nothing > > At least, if Emacs is not run as daemon. Then, the WM_DESTROY is only > handled when there is still another frame, and in this case > ‘remove_w32_kbdhook’ will not remove the hook as kbdhook.hook_count > 1. > > If Emacs is run as daemon, it cleans up the keyboard hook when closing > the last window. > > Is there a better place where the remove_w32_kbdhook call could go such > that cleanup can always happen? I think that place is term_ntproc. > > This URL: > > > > https://stackoverflow.com/questions/8606300/how-to-detect-windows-is-locked > > > > seems to indicate that WTSRegisterSessionNotification requires > > elevation on Windows 10/11. Did you get the UAC prompt when calling > > that API? Are you running with admin privileges when you test this > > code? Triggering UAC prompts when starting Emacs would be a nuisance > > to our users. > > I have read this post, but it seems to be wrong. I don't have any > elevated privileges and it works without showing any prompt, at least on > Windows 10. I'll try to have my colleague test it as well, she runs > Windows 11. Is your user a member of the local Administrators group? Did you try running this code as a "normal" user, not an admin? > >> Unfortunately, this didn't work for me. I tried calling > >> ‘EnumWindows(find_child_console, ...)’ with a ‘child_process’ instance > >> containing the current process id as returned by ‘GetCurrentProcessId’, > >> but I don't seem to get a useful window handle. > > > > What do you mean? What is the result of using find_child_console? > > does the condition in find_child_console, which looks at the > > process_id of all windows, never match the process ID of the Emacs > > session running with -nw? Or what else goes wrong? > > I'm not quite sure myself what I mean. I will experiment with this > a bit more and try to find out what's happening. Thanks. From debbugs-submit-bounces@debbugs.gnu.org Wed Feb 21 09:19:05 2024 Received: (at 69083) by debbugs.gnu.org; 21 Feb 2024 14:19:05 +0000 Received: from localhost ([127.0.0.1]:48050 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rcnR8-0001JO-Q2 for submit@debbugs.gnu.org; Wed, 21 Feb 2024 09:19:05 -0500 Received: from mail-out.m-online.net ([212.18.0.9]:42468) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rcnQt-0001IZ-2b for 69083@debbugs.gnu.org; Wed, 21 Feb 2024 09:19:01 -0500 Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 4Tfyzz0xHxz1qsPr; Wed, 21 Feb 2024 15:18:22 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.68]) by mail.m-online.net (Postfix) with ESMTP id 4Tfyzy6qtrz1qqlW; Wed, 21 Feb 2024 15:18:22 +0100 (CET) X-Virus-Scanned: amavis at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.68]) (amavis, port 10024) with ESMTP id fWSTi2yrGhgo; Wed, 21 Feb 2024 15:18:22 +0100 (CET) X-Auth-Info: bz4tka8Kn35PJ9/DO+ZTbx1OltTUVIxSkLRTZL1gP6g6DoF7NHMVfQJHB6ol9ehH Received: from Whiteflame (ppp-212-114-182-230.dynamic.mnet-online.de [212.114.182.230]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA; Wed, 21 Feb 2024 15:18:22 +0100 (CET) References: <86cyt1qvmt.fsf@gnu.org> <861q9exmhe.fsf@gnu.org> <86v86im1r9.fsf@gnu.org> User-agent: mu4e 1.10.8; emacs 29.2 From: Raffael Stocker To: Eli Zaretskii Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) Date: Wed, 21 Feb 2024 15:13:30 +0100 In-reply-to: <86v86im1r9.fsf@gnu.org> Message-ID: MIME-Version: 1.0 Content-Type: text/plain X-Spam-Score: -1.9 (-) X-Debbugs-Envelope-To: 69083 Cc: 69083@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.6 (---) Eli Zaretskii writes: >> I have read this post, but it seems to be wrong. I don't have any >> elevated privileges and it works without showing any prompt, at least on >> Windows 10. I'll try to have my colleague test it as well, she runs >> Windows 11. > > Is your user a member of the local Administrators group? Did you try > running this code as a "normal" user, not an admin? I did run it as a normal user; my user has no (local or otherwise) admin rights. From debbugs-submit-bounces@debbugs.gnu.org Wed Feb 21 10:04:17 2024 Received: (at 69083) by debbugs.gnu.org; 21 Feb 2024 15:04:17 +0000 Received: from localhost ([127.0.0.1]:49991 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rco8v-0005m3-3Z for submit@debbugs.gnu.org; Wed, 21 Feb 2024 10:04:17 -0500 Received: from eggs.gnu.org ([209.51.188.92]:59934) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rco8s-0005ln-8M for 69083@debbugs.gnu.org; Wed, 21 Feb 2024 10:04:16 -0500 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rco8P-0000Gs-NG; Wed, 21 Feb 2024 10:03:45 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date: mime-version; bh=4kvZ+Iv9MwqzXJcikRiFv4Cfj7Miyz2uSHLnNNLE0Ls=; b=a5ZOv9DjHjFH RswFCHCCBHsq2naXtEBuqlNNFB6wVc1DbMfgQEmo+1JdLWLlW+1o0xsybUZo8U0G2iDeHFCh13w2n uTVzcMbZfNziFgj/DVI0tOJ9F1HyByp8rMyQ+Fl/PTlOwsuz64xUzk5gljlDG4kC2uxXMU20kySQN XZo4BeMwKK1++djlvlFezXk6fL6cTQna2YdU58YNLsbWLjtyX3riDwzJ7Vf8jXl+Z+6JD8BEj/x+5 uGq2o+T7c4SKSeAS6sKlG7ipXs5uJdCqJE2WqtCsGhJPsCdwQe20ujI2+Kx4/oDIUmSA3vRavBPcr rFnZ6C4yTbfOW3XHYsTG5w==; Date: Wed, 21 Feb 2024 17:03:41 +0200 Message-Id: <86o7c9n9ki.fsf@gnu.org> From: Eli Zaretskii To: Raffael Stocker In-Reply-To: (message from Raffael Stocker on Wed, 21 Feb 2024 15:13:30 +0100) Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) References: <86cyt1qvmt.fsf@gnu.org> <861q9exmhe.fsf@gnu.org> <86v86im1r9.fsf@gnu.org> X-Spam-Score: -4.2 (----) X-Debbugs-Envelope-To: 69083 Cc: 69083@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -5.2 (-----) > From: Raffael Stocker > Cc: 69083@debbugs.gnu.org > Date: Wed, 21 Feb 2024 15:13:30 +0100 > > > Eli Zaretskii writes: > >> I have read this post, but it seems to be wrong. I don't have any > >> elevated privileges and it works without showing any prompt, at least on > >> Windows 10. I'll try to have my colleague test it as well, she runs > >> Windows 11. > > > > Is your user a member of the local Administrators group? Did you try > > running this code as a "normal" user, not an admin? > > I did run it as a normal user; my user has no (local or otherwise) admin > rights. Then it's possible that members of Administrators will get a UAC. We shall see, I guess. From debbugs-submit-bounces@debbugs.gnu.org Mon Feb 26 16:09:34 2024 Received: (at 69083) by debbugs.gnu.org; 26 Feb 2024 21:09:34 +0000 Received: from localhost ([127.0.0.1]:38863 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1reiE9-0007jn-Dn for submit@debbugs.gnu.org; Mon, 26 Feb 2024 16:09:34 -0500 Received: from mail-out.m-online.net ([212.18.0.10]:46309) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1reiE6-0007ja-Ot for 69083@debbugs.gnu.org; Mon, 26 Feb 2024 16:09:31 -0500 Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 4TkCrN2PX2z1syC3; Mon, 26 Feb 2024 22:08:04 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.68]) by mail.m-online.net (Postfix) with ESMTP id 4TkCrN002Nz1qqlS; Mon, 26 Feb 2024 22:08:03 +0100 (CET) X-Virus-Scanned: amavis at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.68]) (amavis, port 10024) with ESMTP id Nizch24jIfLo; Mon, 26 Feb 2024 22:08:03 +0100 (CET) X-Auth-Info: rN/PZsdlIi76GnHlTZsj959t670HXxQq5C7epjs7ckuHMkpJJia6+8MIJLVEjFUp Received: from Whiteflame (ppp-212-114-182-86.dynamic.mnet-online.de [212.114.182.86]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA; Mon, 26 Feb 2024 22:08:02 +0100 (CET) References: <86cyt1qvmt.fsf@gnu.org> <861q9exmhe.fsf@gnu.org> <86v86im1r9.fsf@gnu.org> User-agent: mu4e 1.10.8; emacs 29.2 From: Raffael Stocker To: Eli Zaretskii Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) Date: Mon, 26 Feb 2024 21:50:43 +0100 In-reply-to: <86v86im1r9.fsf@gnu.org> Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: 2.9 (++) X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Eli Zaretskii writes: >> Is there a better place where the remove_w32_kbdhook call could go such >> that cleanup can always happen? > > I think that place is term_ntproc. I have added a call to ‘remove_w32_kbdhook’ there, but also left it with the WM_DESTROY message. The cleanup now always happens and the setup/remove calls are correctly nested when using multiple [...] Content analysis details: (2.9 points, 10.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [212.18.0.10 listed in wl.mailspike.net] 3.6 RCVD_IN_SBL_CSS RBL: Received via a relay in Spamhaus SBL-CSS [212.114.182.86 listed in zen.spamhaus.org] -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at https://www.dnswl.org/, low trust [212.18.0.10 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 RCVD_IN_MSPIKE_WL Mailspike good senders -0.0 T_SCC_BODY_TEXT_LINE No description available. X-Debbugs-Envelope-To: 69083 Cc: 69083@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: 1.9 (+) X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Eli Zaretskii writes: >> Is there a better place where the remove_w32_kbdhook call could go such >> that cleanup can always happen? > > I think that place is term_ntproc. I have added a call to ‘remove_w32_kbdhook’ there, but also left it with the WM_DESTROY message. The cleanup now always happens and the setup/remove calls are correctly nested when using multiple [...] Content analysis details: (1.9 points, 10.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [212.18.0.10 listed in wl.mailspike.net] 3.6 RCVD_IN_SBL_CSS RBL: Received via a relay in Spamhaus SBL-CSS [212.114.182.86 listed in zen.spamhaus.org] -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at https://www.dnswl.org/, low trust [212.18.0.10 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 0.0 RCVD_IN_MSPIKE_WL Mailspike good senders -0.0 T_SCC_BODY_TEXT_LINE No description available. -1.0 MAILING_LIST_MULTI Multiple indicators imply a widely-seen list manager --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Eli Zaretskii writes: >> Is there a better place where the remove_w32_kbdhook call could go such >> that cleanup can always happen? > > I think that place is term_ntproc. I have added a call to =E2=80=98remove_w32_kbdhook=E2=80=99 there, but also= left it with the WM_DESTROY message. The cleanup now always happens and the setup/remove calls are correctly nested when using multiple frames. >> >> Unfortunately, this didn't work for me. I tried calling >> >> =E2=80=98EnumWindows(find_child_console, ...)=E2=80=99 with a =E2=80= =98child_process=E2=80=99 instance >> >> containing the current process id as returned by =E2=80=98GetCurrentP= rocessId=E2=80=99, >> >> but I don't seem to get a useful window handle. >> > >> > What do you mean? What is the result of using find_child_console? >> > does the condition in find_child_console, which looks at the >> > process_id of all windows, never match the process ID of the Emacs >> > session running with -nw? Or what else goes wrong? I figured this out now. The =E2=80=98find_child_console=E2=80=99 function = looks for a =E2=80=98ConsoleWindowClass=E2=80=99 window, but the Emacs process itself o= nly has =E2=80=98Emacs Clipboard=E2=80=99 and =E2=80=98IME=E2=80=99 windows. The l= atter seems to be the one I need. I added a function =E2=80=98find_ime_window=E2=80=99 in =E2=80=98w32= console.c=E2=80=99 that checks for this window when called through =E2=80=98EnumThreadWindows=E2=80= =99. I can now register for session notifications using this window. To handle the notifications, I added some code to =E2=80=98drain_message_qu= eue=E2=80=99, calling =E2=80=98reset_w32_kbdhook_state=E2=80=99 from there. This now cor= rectly resets the hook state in console Emacs. I added =E2=80=98WINDOWSNT=E2=80=99 #ifdefs around calls to and the definit= ion of =E2=80=98reset_w32_kbdhook_state=E2=80=99, as with the setup/remove functio= ns. I also cleaned up the =E2=80=98remove_w32_kbdhook=E2=80=99 function to use the pre= viously obtained function pointer. I believe the attached version should now tick all the important boxes. Regards, Raffael --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=reset_kbdhook_2.patch Content-Description: reset_kbdhook_state patch diff --git a/src/w32.c b/src/w32.c index df5465c2135..6744b45bde7 100644 --- a/src/w32.c +++ b/src/w32.c @@ -10392,11 +10392,17 @@ check_windows_init_file (void) } } +/* from w32fns.c */ +extern void +remove_w32_kbdhook (void); + void term_ntproc (int ignored) { (void)ignored; + remove_w32_kbdhook (); + term_timers (); /* shutdown the socket interface if necessary */ diff --git a/src/w32console.c b/src/w32console.c index 0936b5f37e6..bcee9e18fe6 100644 --- a/src/w32console.c +++ b/src/w32console.c @@ -659,6 +659,24 @@ w32_face_attributes (struct frame *f, int face_id) return char_attr; } +/* The IME window is needed to receive the session notifications + required to reset the low level keyboard hook state. */ + +static BOOL CALLBACK +find_ime_window (HWND hwnd, LPARAM arg) +{ + char window_class[32]; + + GetClassName (hwnd, window_class, sizeof (window_class)); + if (strcmp (window_class, "IME") == 0) + { + *(HWND *) arg = hwnd; + return FALSE; + } + /* keep looking */ + return TRUE; +} + void initialize_w32_display (struct terminal *term, int *width, int *height) { @@ -821,8 +839,11 @@ initialize_w32_display (struct terminal *term, int *width, int *height) /* Setup w32_display_info structure for this frame. */ w32_initialize_display_info (build_string ("Console")); - /* Set up the keyboard hook. */ - setup_w32_kbdhook (); + HWND hwnd = NULL; + EnumThreadWindows (GetCurrentThreadId (), find_ime_window, (LPARAM) &hwnd); + + /* Set up the keyboard hook. */ + setup_w32_kbdhook (hwnd); } diff --git a/src/w32fns.c b/src/w32fns.c index 8d4bd00b91c..168763f7215 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -49,6 +49,7 @@ #define _WIN32_WINNT 0x0600 #ifdef WINDOWSNT #include #include /* for _getmbcp */ +#include /* for WTS(Un)RegisterSessionNotification */ #endif /* WINDOWSNT */ #if CYGWIN @@ -204,6 +205,10 @@ DECLARE_HANDLE(HMONITOR); typedef HRESULT (WINAPI * DwmSetWindowAttribute_Proc) (HWND hwnd, DWORD dwAttribute, IN LPCVOID pvAttribute, DWORD cbAttribute); +typedef BOOL (WINAPI * WTSRegisterSessionNotification_Proc) + (HWND hwnd, DWORD dwFlags); +typedef BOOL (WINAPI * WTSUnRegisterSessionNotification_Proc) (HWND hwnd); + TrackMouseEvent_Proc track_mouse_event_fn = NULL; ImmGetCompositionString_Proc get_composition_string_fn = NULL; ImmGetContext_Proc get_ime_context_fn = NULL; @@ -220,6 +225,7 @@ DECLARE_HANDLE(HMONITOR); SetThreadDescription_Proc set_thread_description = NULL; SetWindowTheme_Proc SetWindowTheme_fn = NULL; DwmSetWindowAttribute_Proc DwmSetWindowAttribute_fn = NULL; +WTSUnRegisterSessionNotification_Proc WTSUnRegisterSessionNotification_fn = NULL; extern AppendMenuW_Proc unicode_append_menu; @@ -307,6 +313,7 @@ #define WS_EX_NOACTIVATE 0x08000000L int hook_count; /* counter, if several windows are created */ HHOOK hook; /* hook handle */ HWND console; /* console window handle */ + HWND window; /* window handle used for session notification */ int lwindown; /* Left Windows key currently pressed (and hooked) */ int rwindown; /* Right Windows key currently pressed (and hooked) */ @@ -2744,7 +2751,7 @@ funhook (int code, WPARAM w, LPARAM l) /* Set up the hook; can be called several times, with matching remove_w32_kbdhook calls. */ void -setup_w32_kbdhook (void) +setup_w32_kbdhook (HWND hwnd) { kbdhook.hook_count++; @@ -2800,6 +2807,21 @@ setup_w32_kbdhook (void) /* Set the hook. */ kbdhook.hook = SetWindowsHookEx (WH_KEYBOARD_LL, funhook, GetModuleHandle (NULL), 0); + + /* Register session notifications so we get notified about the + computer being locked. */ + if (hwnd != NULL) + { + kbdhook.window = hwnd; + HMODULE wtsapi32_lib = LoadLibrary ("wtsapi32.dll"); + WTSRegisterSessionNotification_Proc WTSRegisterSessionNotification_fn + = (WTSRegisterSessionNotification_Proc) + get_proc_addr (wtsapi32_lib, "WTSRegisterSessionNotification"); + WTSUnRegisterSessionNotification_fn = (WTSUnRegisterSessionNotification_Proc) + get_proc_addr (wtsapi32_lib, "WTSUnRegisterSessionNotification"); + if (WTSRegisterSessionNotification_fn != NULL) + WTSRegisterSessionNotification_fn (hwnd, NOTIFY_FOR_THIS_SESSION); + } } } @@ -2811,6 +2833,9 @@ remove_w32_kbdhook (void) if (kbdhook.hook_count == 0 && w32_kbdhook_active) { UnhookWindowsHookEx (kbdhook.hook); + if (kbdhook.window != NULL + && WTSUnRegisterSessionNotification_fn != NULL) + WTSUnRegisterSessionNotification_fn (kbdhook.window); kbdhook.hook = NULL; } } @@ -2884,13 +2909,12 @@ check_w32_winkey_state (int vkey) } return 0; } -#endif /* WINDOWSNT */ /* Reset the keyboard hook state. Locking the workstation with Win-L leaves the Win key(s) "down" from the hook's point of view - the keyup event is never seen. Thus, this function must be called when the system is locked. */ -static void +void reset_w32_kbdhook_state (void) { kbdhook.lwindown = 0; @@ -2900,6 +2924,7 @@ reset_w32_kbdhook_state (void) kbdhook.suppress_lone = 0; kbdhook.winseen = 0; } +#endif /* WINDOWSNT */ /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish between left and right keys as advertised. We test for this @@ -5301,7 +5326,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) #ifdef WINDOWSNT case WM_CREATE: - setup_w32_kbdhook (); + setup_w32_kbdhook (hwnd); goto dflt; #endif @@ -5312,10 +5337,12 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) CoUninitialize (); return 0; +#ifdef WINDOWSNT case WM_WTSSESSION_CHANGE: if (wParam == WTS_SESSION_LOCK) reset_w32_kbdhook_state (); goto dflt; +#endif case WM_CLOSE: wmsg.dwModifiers = w32_get_modifiers (); diff --git a/src/w32term.h b/src/w32term.h index 29ace0b2797..3120c8bd71f 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -779,8 +779,9 @@ #define FILE_NOTIFICATIONS_SIZE 16384 #ifdef WINDOWSNT /* Keyboard hooks. */ -extern void setup_w32_kbdhook (void); +extern void setup_w32_kbdhook (HWND); extern void remove_w32_kbdhook (void); +extern void reset_w32_kbdhook_state (void); extern int check_w32_winkey_state (int); #define w32_kbdhook_active (os_subtype != OS_SUBTYPE_9X) #else diff --git a/src/w32xfns.c b/src/w32xfns.c index fa7d5fbdb61..3d7a1514f72 100644 --- a/src/w32xfns.c +++ b/src/w32xfns.c @@ -413,8 +413,16 @@ drain_message_queue (void) while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { - if (msg.message == WM_EMACS_FILENOTIFY) - retval = 1; + switch (msg.message) + { + case WM_WTSSESSION_CHANGE: + if (msg.wParam == WTS_SESSION_LOCK) + reset_w32_kbdhook_state (); + break; + case WM_EMACS_FILENOTIFY: + retval = 1; + break; + } TranslateMessage (&msg); DispatchMessage (&msg); } --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Tue Feb 27 02:45:23 2024 Received: (at 69083) by debbugs.gnu.org; 27 Feb 2024 07:45:23 +0000 Received: from localhost ([127.0.0.1]:58636 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1res9S-0006FD-LT for submit@debbugs.gnu.org; Tue, 27 Feb 2024 02:45:23 -0500 Received: from eggs.gnu.org ([209.51.188.92]:52594) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1res9Q-0006En-3o for 69083@debbugs.gnu.org; Tue, 27 Feb 2024 02:45:21 -0500 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1res6o-0002Ub-RI; Tue, 27 Feb 2024 02:42:38 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From: Date; bh=eaIUv71jKzysEDqoPKxp4jvJG7KUhtjpB/eK6SKD23E=; b=Xab71CPUNjF4vQs6sAWf x88nC/4PUjz0+FapdTfg+S7cY9HongerBVL4812W1JISzjNPLEIlBuAIqMJ5qvJn4RJkwOgfh8A1o lJIlqSSqEbaQXvV4Mgl3/aD1g6TrMQmP9Vw5N6GZN2U31FMvKNscjPy5bbfLI3hCxBOHfUusM2I9J e7KZJ+N2TwndsLwy8fob61kMo7YXJ0V35NSBL7IdVm7xVIMnKQCJvnkfy0GMvrK9j19+4XjRuuoy8 b71QyDSLKDe+mxkZegZbB3Sp8QEQbFbW+oauJrucaMLbfDasHaAfCRFBThLIMlVxxsa+u5Fec1LHP tE8lpm2eOxWMVw==; Date: Tue, 27 Feb 2024 09:42:34 +0200 Message-Id: <868r36uzdh.fsf@gnu.org> From: Eli Zaretskii To: Raffael Stocker In-Reply-To: (message from Raffael Stocker on Mon, 26 Feb 2024 21:50:43 +0100) Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) References: <86cyt1qvmt.fsf@gnu.org> <861q9exmhe.fsf@gnu.org> <86v86im1r9.fsf@gnu.org> MIME-version: 1.0 Content-type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 69083 Cc: 69083@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: Raffael Stocker > Cc: 69083@debbugs.gnu.org > Date: Mon, 26 Feb 2024 21:50:43 +0100 > > Eli Zaretskii writes: > > >> Is there a better place where the remove_w32_kbdhook call could go such > >> that cleanup can always happen? > > > > I think that place is term_ntproc. > > I have added a call to ‘remove_w32_kbdhook’ there, but also left it with > the WM_DESTROY message. The cleanup now always happens and the > setup/remove calls are correctly nested when using multiple frames. > > >> >> Unfortunately, this didn't work for me. I tried calling > >> >> ‘EnumWindows(find_child_console, ...)’ with a ‘child_process’ instance > >> >> containing the current process id as returned by ‘GetCurrentProcessId’, > >> >> but I don't seem to get a useful window handle. > >> > > >> > What do you mean? What is the result of using find_child_console? > >> > does the condition in find_child_console, which looks at the > >> > process_id of all windows, never match the process ID of the Emacs > >> > session running with -nw? Or what else goes wrong? > > I figured this out now. The ‘find_child_console’ function looks for a > ‘ConsoleWindowClass’ window, but the Emacs process itself only has > ‘Emacs Clipboard’ and ‘IME’ windows. The latter seems to be the one I > need. I added a function ‘find_ime_window’ in ‘w32console.c’ that > checks for this window when called through ‘EnumThreadWindows’. I can > now register for session notifications using this window. > > To handle the notifications, I added some code to ‘drain_message_queue’, > calling ‘reset_w32_kbdhook_state’ from there. This now correctly resets > the hook state in console Emacs. > > I added ‘WINDOWSNT’ #ifdefs around calls to and the definition of > ‘reset_w32_kbdhook_state’, as with the setup/remove functions. I also > cleaned up the ‘remove_w32_kbdhook’ function to use the previously > obtained function pointer. > > I believe the attached version should now tick all the important boxes. Thanks, I have a few minor comments to the patch below. After fixing those nits, would you please submit the result in "git format-patch" format, and include commit log message according to our conventions (see CONTRIBUTE for the details and "git log" to see examples of how we do that in the repository). This will allow me to install the changes quickly and easily. > +/* from w32fns.c */ > +extern void > +remove_w32_kbdhook (void); Please make the prototype a single line, don't break it in two as we do with function definitions. > +/* The IME window is needed to receive the session notifications > + required to reset the low level keyboard hook state. */ ^^ Our style is to leave two SPACEs at the end of a comment. > + /* Register session notifications so we get notified about the > + computer being locked. */ > + if (hwnd != NULL) > + { > + kbdhook.window = hwnd; > + HMODULE wtsapi32_lib = LoadLibrary ("wtsapi32.dll"); > + WTSRegisterSessionNotification_Proc WTSRegisterSessionNotification_fn > + = (WTSRegisterSessionNotification_Proc) > + get_proc_addr (wtsapi32_lib, "WTSRegisterSessionNotification"); > + WTSUnRegisterSessionNotification_fn = (WTSUnRegisterSessionNotification_Proc) > + get_proc_addr (wtsapi32_lib, "WTSUnRegisterSessionNotification"); > + if (WTSRegisterSessionNotification_fn != NULL) > + WTSRegisterSessionNotification_fn (hwnd, NOTIFY_FOR_THIS_SESSION); > + } This code is run every time Emacs creates a new frame, doesn't it? If so, calling LoadLibrary and get_proc_addr each time is a waste of cycles. It is better to make both WTSRegisterSessionNotification_fn and WTSUnRegisterSessionNotification_fn global, and introduce a boolean flag to indicate that this was already done. Then the above code should be run only once per session, and all the other calls should use the function pointers already set up (if non-NULL). Note that the boolean flag and the function pointers need to be reset at startup in globals_of_w32, because we still support the unexec build of Emacs, where global and static variables set during the temacs run as part of the build are recorded in the emacs.exe binary, and will therefore record the values from the build time, which are not necessarily true for the run time of production sessions (which could well be on another system). OTOH, there's something I don't understand here. If this code is run for every frame we create/delete, then what window exactly does the kbdhook.window member record? It sounds like we overwrite that member with another window's handle on each call to setup_w32_kbdhook? And if so, what is the window handle we will pass to WTSUnRegisterSessionNotification in remove_w32_kbdhook? Or is the hwnd argument to setup_w32_kbdhook somehow non-NULL only once, for the main session window or something? I feel that I'm missing something here. Thanks. From debbugs-submit-bounces@debbugs.gnu.org Thu Feb 29 15:23:53 2024 Received: (at 69083) by debbugs.gnu.org; 29 Feb 2024 20:23:53 +0000 Received: from localhost ([127.0.0.1]:35466 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rfmwb-0004Mw-89 for submit@debbugs.gnu.org; Thu, 29 Feb 2024 15:23:53 -0500 Received: from mail-out.m-online.net ([212.18.0.10]:57726) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rfmwY-0004Ml-AL for 69083@debbugs.gnu.org; Thu, 29 Feb 2024 15:23:51 -0500 Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 4Tm2hF5SlNz1sBpm; Thu, 29 Feb 2024 21:22:21 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.68]) by mail.m-online.net (Postfix) with ESMTP id 4Tm2hF3bL9z1qqlY; Thu, 29 Feb 2024 21:22:21 +0100 (CET) X-Virus-Scanned: amavis at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.68]) (amavis, port 10024) with ESMTP id 6w_rIy1GEkPh; Thu, 29 Feb 2024 21:22:20 +0100 (CET) X-Auth-Info: vcitnGZ1PsWvudo8ZnlqcZGTJ31ue9kTVY9lhWrYktdbnYjZdTetftxZPJWzOElj Received: from Whiteflame (ppp-212-114-182-252.dynamic.mnet-online.de [212.114.182.252]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA; Thu, 29 Feb 2024 21:22:20 +0100 (CET) From: Raffael Stocker To: Eli Zaretskii Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) In-Reply-To: <868r36uzdh.fsf@gnu.org> (Eli Zaretskii's message of "Tue, 27 Feb 2024 09:42:34 +0200") References: <86cyt1qvmt.fsf@gnu.org> <861q9exmhe.fsf@gnu.org> <86v86im1r9.fsf@gnu.org> <868r36uzdh.fsf@gnu.org> User-Agent: mu4e 1.12.0; emacs 29.2 Date: Thu, 29 Feb 2024 21:22:13 +0100 Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 69083 Cc: 69083@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) Eli Zaretskii writes: >> + /* Register session notifications so we get notified about the >> + computer being locked. */ >> + if (hwnd !=3D NULL) >> + { >> + kbdhook.window =3D hwnd; >> + HMODULE wtsapi32_lib =3D LoadLibrary ("wtsapi32.dll"); >> + WTSRegisterSessionNotification_Proc WTSRegisterSessionNotification_fn >> + =3D (WTSRegisterSessionNotification_Proc) >> + get_proc_addr (wtsapi32_lib, "WTSRegisterSessionNotification"); >> + WTSUnRegisterSessionNotification_fn =3D (WTSUnRegisterSessionNotific= ation_Proc) >> + get_proc_addr (wtsapi32_lib, "WTSUnRegisterSessionNotification"); >> + if (WTSRegisterSessionNotification_fn !=3D NULL) >> + WTSRegisterSessionNotification_fn (hwnd, NOTIFY_FOR_THIS_SESSION); >> + } > > This code is run every time Emacs creates a new frame, doesn't it? If > so, calling LoadLibrary and get_proc_addr each time is a waste of > cycles. It is better to make both WTSRegisterSessionNotification_fn > and WTSUnRegisterSessionNotification_fn global, and introduce a > boolean flag to indicate that this was already done. Then the above > code should be run only once per session, and all the other calls > should use the function pointers already set up (if non-NULL). The code is run when a first frame is created, because only then =E2=80=98kbdhook.hook_count=E2=80=99 equals 1. If Emacs runs as daemon, th= is can happen several times in a session, when the user deletes all frames and then creates a new one again. > OTOH, there's something I don't understand here. If this code is run > for every frame we create/delete, then what window exactly does the > kbdhook.window member record? It sounds like we overwrite that member > with another window's handle on each call to setup_w32_kbdhook? And > if so, what is the window handle we will pass to > WTSUnRegisterSessionNotification in remove_w32_kbdhook? Or is the > hwnd argument to setup_w32_kbdhook somehow non-NULL only once, for the > main session window or something? I feel that I'm missing something > here. You are right, this is iffy. Setting up the hook for the first frame works well, as the hook is per-process. I thought I could use the same approach here, but the session notifications are per-window. So if the user creates two frames, the session notification is registered for the first one only. If she deletes the first frame (leaving the second one alone), the notification gets unregistered and the hook reset is not called anymore upon session lock. So, I guess the options I have are either somehow juggling window handles, making sure the session notification is always registered for exactly one window handle no matter how many frames are created and deleted (so =E2=80=98reset_w32_kbdhook_state=E2=80=99 is called exactly onc= e for every session lock), or registering the notification for every frame. In the latter case I would either have to find a way to ensure the reset function is only called once, or just not care that it is called for every existing frame. The latter option is simple, but a bit dirty. OTOH, the reset function only sets the state variables to zero, so there shouldn't be a problem with this approach. I'll think about this a bit more, maybe I can come up with a nice solution that doesn't require keeping too much state just for the reset function. I am thinking about registering the notification for the first created frame, and when that is deleted, i.e. receives the =E2=80=98WM_DESTROY=E2=80=99 message, "handing" it over to some other frame= if there is one. I don't know much about the internals of Emacs frame handling. Could =E2=80=98w32_frame_list_z_order=E2=80=99 be used (from the input thre= ad) for something like that? Or is there a better approach? Regards, Raffael From debbugs-submit-bounces@debbugs.gnu.org Fri Mar 01 01:44:27 2024 Received: (at 69083) by debbugs.gnu.org; 1 Mar 2024 06:44:27 +0000 Received: from localhost ([127.0.0.1]:35917 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rfwd8-0007Hd-LH for submit@debbugs.gnu.org; Fri, 01 Mar 2024 01:44:26 -0500 Received: from eggs.gnu.org ([209.51.188.92]:43596) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rfwd5-0007HO-5W for 69083@debbugs.gnu.org; Fri, 01 Mar 2024 01:44:25 -0500 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rfwaS-0007xJ-69; Fri, 01 Mar 2024 01:41:40 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From: Date; bh=9iwTjd7Ajvmr0XFMzrWwSlOx8WiA6s4Qg1WNyhLc664=; b=gZqF7AOZlM26mOrbiOyH IQ2gfSXn3s8MLCkuTYRIp6i2TuAbsLp3xNpB+39e9yedvNRsOnTe1UswzbYltIIKmy9Ya1UtO4BFR UZ048SpePjL1X+j3G9BYSiE/H/7a9MUfKQ7ZC5jzEkdfhrprlDj6jZtZzTsKZIimz4WLn0TYb4LpN eHKlDx0/hVKcYgHYlvrPJph+LL20J/Vb1uEARZzCqjJ+r5cdm0LAwFSj3fSj2vpEstIy26amYxrEJ YH0Opysxiv+OWqne+5zqTdegnS44HKxDn3aOJQhzwxSniPUWwBbIp2nbMPd2OAwpEq1ttkc/skMZJ c0GJMBXaB5W8Ng==; Date: Fri, 01 Mar 2024 08:41:36 +0200 Message-Id: <86bk7ysbbz.fsf@gnu.org> From: Eli Zaretskii To: Raffael Stocker In-Reply-To: (message from Raffael Stocker on Thu, 29 Feb 2024 21:22:13 +0100) Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) References: <86cyt1qvmt.fsf@gnu.org> <861q9exmhe.fsf@gnu.org> <86v86im1r9.fsf@gnu.org> <868r36uzdh.fsf@gnu.org> MIME-version: 1.0 Content-type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 69083 Cc: 69083@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: Raffael Stocker > Cc: 69083@debbugs.gnu.org > Date: Thu, 29 Feb 2024 21:22:13 +0100 > > I'll think about this a bit more, maybe I can come up with a nice > solution that doesn't require keeping too much state just for the reset > function. I am thinking about registering the notification for the > first created frame, and when that is deleted, i.e. receives the > ‘WM_DESTROY’ message, "handing" it over to some other frame if there is > one. This sounds like the simplest approach to me. > I don't know much about the internals of Emacs frame handling. > Could ‘w32_frame_list_z_order’ be used (from the input thread) for > something like that? Or is there a better approach? Why is the order important? Can't you "hand" the registration to some other frame, no matter which one? From debbugs-submit-bounces@debbugs.gnu.org Sun Mar 03 11:44:41 2024 Received: (at 69083) by debbugs.gnu.org; 3 Mar 2024 16:44:41 +0000 Received: from localhost ([127.0.0.1]:41031 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rgox6-00030T-U9 for submit@debbugs.gnu.org; Sun, 03 Mar 2024 11:44:41 -0500 Received: from mail-out.m-online.net ([212.18.0.9]:51959) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rgox3-00030J-NI for 69083@debbugs.gnu.org; Sun, 03 Mar 2024 11:44:39 -0500 Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 4Tnnj33B2Hz1qsP1; Sun, 3 Mar 2024 17:44:07 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.68]) by mail.m-online.net (Postfix) with ESMTP id 4Tnnj31vlVz1qqlS; Sun, 3 Mar 2024 17:44:07 +0100 (CET) X-Virus-Scanned: amavis at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.68]) (amavis, port 10024) with ESMTP id deZavhu7kZIX; Sun, 3 Mar 2024 17:44:04 +0100 (CET) X-Auth-Info: kNiN3781x/UBgexjykr1pAdhFhSMIULTP+/JKkzjj2E2Z70BqsKoTJsMbX+orTzW Received: from Whiteflame (ppp-212-114-182-252.dynamic.mnet-online.de [212.114.182.252]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA; Sun, 3 Mar 2024 17:44:04 +0100 (CET) From: Raffael Stocker To: Eli Zaretskii Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) In-Reply-To: <86bk7ysbbz.fsf@gnu.org> (Eli Zaretskii's message of "Fri, 01 Mar 2024 08:41:36 +0200") References: <86cyt1qvmt.fsf@gnu.org> <861q9exmhe.fsf@gnu.org> <86v86im1r9.fsf@gnu.org> <868r36uzdh.fsf@gnu.org> <86bk7ysbbz.fsf@gnu.org> User-Agent: mu4e 1.12.0; emacs 29.2 Date: Sun, 03 Mar 2024 17:43:56 +0100 Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: -0.7 (/) X-Debbugs-Envelope-To: 69083 Cc: 69083@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Eli Zaretskii writes: >> I'll think about this a bit more, maybe I can come up with a nice >> solution that doesn't require keeping too much state just for the reset >> function. I am thinking about registering the notification for the >> first created frame, and when that is deleted, i.e. receives the >> =E2=80=98WM_DESTROY=E2=80=99 message, "handing" it over to some other fr= ame if there is >> one. > > This sounds like the simplest approach to me. I have implemented this and attached the patch. I have tested it with both console and GUI Emacs (with and without server) and have found no further problems with it. >> I don't know much about the internals of Emacs frame handling. >> Could =E2=80=98w32_frame_list_z_order=E2=80=99 be used (from the input t= hread) for >> something like that? Or is there a better approach? > > Why is the order important? Can't you "hand" the registration to some > other frame, no matter which one? The order is not important, I just didn't know where to look to get a frame; sorry for the noise. I now use =E2=80=98Fnext_frame=E2=80=99. Regards, Raffael --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Fix-resetting-keyboard-hook-state-on-Windows.patch Content-Description: Fix resetting keyboard hook state >From fb9b8daf18a3dc96879d58d9c4e1e3dcfcf8e2e7 Mon Sep 17 00:00:00 2001 From: Raffael Stocker Date: Sun, 3 Mar 2024 17:31:10 +0100 Subject: [PATCH] Fix resetting keyboard hook state on Windows Register session notifications so Emacs is notified when the computer is being locked, as required to reset the low level keyboard hook state (Bug#69083). * src/w32term.h: * src/w32fns.c (setup_w32_kbdhook, remove_w32_kbdhook) (w32_wnd_proc, globals_of_w32fns, maybe_pass_notification): Register and manage session notifications in GUI Emacs. * src/w32console.c (initialize_w32_display, find_ime_window): * src/w32xfns.c (drain_message_queue): Register notifications and reset keyboard hook state in console Emacs. * src/w32.c (term_ntproc): Un-register session notifications when terminating. --- src/w32.c | 5 ++++ src/w32console.c | 25 +++++++++++++++-- src/w32fns.c | 73 +++++++++++++++++++++++++++++++++++++++++++++--- src/w32term.h | 3 +- src/w32xfns.c | 12 ++++++-- 5 files changed, 109 insertions(+), 9 deletions(-) diff --git a/src/w32.c b/src/w32.c index df5465c2135..d34ab70f82d 100644 --- a/src/w32.c +++ b/src/w32.c @@ -10392,11 +10392,16 @@ check_windows_init_file (void) } } +/* from w32fns.c */ +extern void remove_w32_kbdhook (void); + void term_ntproc (int ignored) { (void)ignored; + remove_w32_kbdhook (); + term_timers (); /* shutdown the socket interface if necessary */ diff --git a/src/w32console.c b/src/w32console.c index 0936b5f37e6..7dcbc795cac 100644 --- a/src/w32console.c +++ b/src/w32console.c @@ -659,6 +659,24 @@ w32_face_attributes (struct frame *f, int face_id) return char_attr; } +/* The IME window is needed to receive the session notifications + required to reset the low level keyboard hook state. */ + +static BOOL CALLBACK +find_ime_window (HWND hwnd, LPARAM arg) +{ + char window_class[32]; + + GetClassName (hwnd, window_class, sizeof (window_class)); + if (strcmp (window_class, "IME") == 0) + { + *(HWND *) arg = hwnd; + return FALSE; + } + /* keep looking */ + return TRUE; +} + void initialize_w32_display (struct terminal *term, int *width, int *height) { @@ -818,11 +836,14 @@ initialize_w32_display (struct terminal *term, int *width, int *height) else w32_console_unicode_input = 0; - /* Setup w32_display_info structure for this frame. */ + /* Setup w32_display_info structure for this frame. */ w32_initialize_display_info (build_string ("Console")); + HWND hwnd = NULL; + EnumThreadWindows (GetCurrentThreadId (), find_ime_window, (LPARAM) &hwnd); + /* Set up the keyboard hook. */ - setup_w32_kbdhook (); + setup_w32_kbdhook (hwnd); } diff --git a/src/w32fns.c b/src/w32fns.c index 8d4bd00b91c..32cc466d9eb 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -49,6 +49,7 @@ #define _WIN32_WINNT 0x0600 #ifdef WINDOWSNT #include #include /* for _getmbcp */ +#include /* for WTS(Un)RegisterSessionNotification */ #endif /* WINDOWSNT */ #if CYGWIN @@ -204,6 +205,10 @@ DECLARE_HANDLE(HMONITOR); typedef HRESULT (WINAPI * DwmSetWindowAttribute_Proc) (HWND hwnd, DWORD dwAttribute, IN LPCVOID pvAttribute, DWORD cbAttribute); +typedef BOOL (WINAPI * WTSRegisterSessionNotification_Proc) + (HWND hwnd, DWORD dwFlags); +typedef BOOL (WINAPI * WTSUnRegisterSessionNotification_Proc) (HWND hwnd); + TrackMouseEvent_Proc track_mouse_event_fn = NULL; ImmGetCompositionString_Proc get_composition_string_fn = NULL; ImmGetContext_Proc get_ime_context_fn = NULL; @@ -220,6 +225,8 @@ DECLARE_HANDLE(HMONITOR); SetThreadDescription_Proc set_thread_description = NULL; SetWindowTheme_Proc SetWindowTheme_fn = NULL; DwmSetWindowAttribute_Proc DwmSetWindowAttribute_fn = NULL; +WTSUnRegisterSessionNotification_Proc WTSUnRegisterSessionNotification_fn = NULL; +WTSRegisterSessionNotification_Proc WTSRegisterSessionNotification_fn = NULL; extern AppendMenuW_Proc unicode_append_menu; @@ -307,6 +314,7 @@ #define WS_EX_NOACTIVATE 0x08000000L int hook_count; /* counter, if several windows are created */ HHOOK hook; /* hook handle */ HWND console; /* console window handle */ + HWND notified_wnd; /* window that receives session notifications */ int lwindown; /* Left Windows key currently pressed (and hooked) */ int rwindown; /* Right Windows key currently pressed (and hooked) */ @@ -2744,7 +2752,7 @@ funhook (int code, WPARAM w, LPARAM l) /* Set up the hook; can be called several times, with matching remove_w32_kbdhook calls. */ void -setup_w32_kbdhook (void) +setup_w32_kbdhook (HWND hwnd) { kbdhook.hook_count++; @@ -2800,6 +2808,15 @@ setup_w32_kbdhook (void) /* Set the hook. */ kbdhook.hook = SetWindowsHookEx (WH_KEYBOARD_LL, funhook, GetModuleHandle (NULL), 0); + + /* Register session notifications so we get notified about the + computer being locked. */ + kbdhook.notified_wnd = NULL; + if (hwnd != NULL && WTSRegisterSessionNotification_fn != NULL) + { + WTSRegisterSessionNotification_fn (hwnd, NOTIFY_FOR_THIS_SESSION); + kbdhook.notified_wnd = hwnd; + } } } @@ -2811,7 +2828,11 @@ remove_w32_kbdhook (void) if (kbdhook.hook_count == 0 && w32_kbdhook_active) { UnhookWindowsHookEx (kbdhook.hook); + if (kbdhook.notified_wnd != NULL + && WTSUnRegisterSessionNotification_fn != NULL) + WTSUnRegisterSessionNotification_fn (kbdhook.notified_wnd); kbdhook.hook = NULL; + kbdhook.notified_wnd = NULL; } } #endif /* WINDOWSNT */ @@ -2884,13 +2905,12 @@ check_w32_winkey_state (int vkey) } return 0; } -#endif /* WINDOWSNT */ /* Reset the keyboard hook state. Locking the workstation with Win-L leaves the Win key(s) "down" from the hook's point of view - the keyup event is never seen. Thus, this function must be called when the system is locked. */ -static void +void reset_w32_kbdhook_state (void) { kbdhook.lwindown = 0; @@ -2900,6 +2920,7 @@ reset_w32_kbdhook_state (void) kbdhook.suppress_lone = 0; kbdhook.winseen = 0; } +#endif /* WINDOWSNT */ /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish between left and right keys as advertised. We test for this @@ -4129,6 +4150,36 @@ #define S_TYPES_TO_REPORT_CHARACTER_PAYLOAD_WITH_MODIFIERS "" return 0; } +/* Maybe pass session notification registration to another frame. If + the frame with window handle HWND is deleted, we must pass the + notifications to some other frame, if they have been sent to this + frame before and have not already been passed on. If there is no + other frame, do nothing. */ + +#ifdef WINDOWSNT +static void +maybe_pass_notification (HWND hwnd) +{ + if (hwnd == kbdhook.notified_wnd + && kbdhook.hook_count > 0 && w32_kbdhook_active) + { + Lisp_Object frame = Fnext_frame (Qnil, Qnil); + struct frame *f = XFRAME (frame); + + if (FRAME_OUTPUT_DATA (f) != NULL + && WTSUnRegisterSessionNotification_fn != NULL + && WTSRegisterSessionNotification_fn != NULL) + { + /* There is another frame, pass on the session notification. */ + HWND next_wnd = FRAME_W32_WINDOW (f); + WTSUnRegisterSessionNotification_fn (hwnd); + WTSRegisterSessionNotification_fn (next_wnd, NOTIFY_FOR_THIS_SESSION); + kbdhook.notified_wnd = next_wnd; + } + } +} +#endif /* WINDOWSNT */ + /* Main window procedure */ static LRESULT CALLBACK @@ -5301,23 +5352,29 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) #ifdef WINDOWSNT case WM_CREATE: - setup_w32_kbdhook (); + setup_w32_kbdhook (hwnd); goto dflt; #endif case WM_DESTROY: #ifdef WINDOWSNT + maybe_pass_notification (hwnd); remove_w32_kbdhook (); #endif CoUninitialize (); return 0; +#ifdef WINDOWSNT case WM_WTSSESSION_CHANGE: if (wParam == WTS_SESSION_LOCK) reset_w32_kbdhook_state (); goto dflt; +#endif case WM_CLOSE: +#ifdef WINDOWSNT + maybe_pass_notification (hwnd); +#endif wmsg.dwModifiers = w32_get_modifiers (); my_post_msg (&wmsg, hwnd, msg, wParam, lParam); return 0; @@ -11335,6 +11392,14 @@ globals_of_w32fns (void) set_thread_description = (SetThreadDescription_Proc) get_proc_addr (hm_kernel32, "SetThreadDescription"); +#ifdef WINDOWSNT + HMODULE wtsapi32_lib = LoadLibrary ("wtsapi32.dll"); + WTSRegisterSessionNotification_fn = (WTSRegisterSessionNotification_Proc) + get_proc_addr (wtsapi32_lib, "WTSRegisterSessionNotification"); + WTSUnRegisterSessionNotification_fn = (WTSUnRegisterSessionNotification_Proc) + get_proc_addr (wtsapi32_lib, "WTSUnRegisterSessionNotification"); +#endif + /* Support OS dark mode on Windows 10 version 1809 and higher. See `w32_applytheme' which uses appropriate APIs per version of Windows. For future wretches who may need to understand Windows build numbers: diff --git a/src/w32term.h b/src/w32term.h index 29ace0b2797..3120c8bd71f 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -779,8 +779,9 @@ #define FILE_NOTIFICATIONS_SIZE 16384 #ifdef WINDOWSNT /* Keyboard hooks. */ -extern void setup_w32_kbdhook (void); +extern void setup_w32_kbdhook (HWND); extern void remove_w32_kbdhook (void); +extern void reset_w32_kbdhook_state (void); extern int check_w32_winkey_state (int); #define w32_kbdhook_active (os_subtype != OS_SUBTYPE_9X) #else diff --git a/src/w32xfns.c b/src/w32xfns.c index fa7d5fbdb61..3d7a1514f72 100644 --- a/src/w32xfns.c +++ b/src/w32xfns.c @@ -413,8 +413,16 @@ drain_message_queue (void) while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { - if (msg.message == WM_EMACS_FILENOTIFY) - retval = 1; + switch (msg.message) + { + case WM_WTSSESSION_CHANGE: + if (msg.wParam == WTS_SESSION_LOCK) + reset_w32_kbdhook_state (); + break; + case WM_EMACS_FILENOTIFY: + retval = 1; + break; + } TranslateMessage (&msg); DispatchMessage (&msg); } -- 2.44.0 --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Sun Mar 03 12:26:10 2024 Received: (at 69083) by debbugs.gnu.org; 3 Mar 2024 17:26:10 +0000 Received: from localhost ([127.0.0.1]:41229 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rgpbG-0001Os-Do for submit@debbugs.gnu.org; Sun, 03 Mar 2024 12:26:10 -0500 Received: from eggs.gnu.org ([209.51.188.92]:35208) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rgpbD-0001Nx-4U for 69083@debbugs.gnu.org; Sun, 03 Mar 2024 12:26:08 -0500 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rgpYW-0008Nq-Ju; Sun, 03 Mar 2024 12:23:22 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From: Date; bh=WEslZgsYmuq8ZSVOcf9Yo58RMaieJ00zKwmk1aM/WVU=; b=IZ6qkzePnFwIjk5oSPLh gs4I+H9LHr2mz4ifGZK5ahcijgaogdj73HjSE1gLdIGeNY7jkrHhYm4gdvUlh1zHV4nthDHS7Mhqt HFkrvodgTZahIEiT1M0GvC6miIyo7kUjhGgDUM5DTGVHRdXHdqJ02iPbXT5dNhH3r6w5GFuarbdUb IbOYkfg3fbwewbBM3QBSCwNow2mIjKuz3kOxYxyhJcVZfyytgxoSkcnjHARLqGwYI7UDjOqTfD6hQ XmhvNX2daLd3biSvekm3ldfzWMLz2pTxVbEFGxChclqb0mMWzEuI7UhUusB9fIBFMo9W5p8KiVYhm hoqLHBAqTF1BWg==; Date: Sun, 03 Mar 2024 19:23:05 +0200 Message-Id: <868r2znsau.fsf@gnu.org> From: Eli Zaretskii To: Raffael Stocker In-Reply-To: (message from Raffael Stocker on Sun, 03 Mar 2024 17:43:56 +0100) Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) References: <86cyt1qvmt.fsf@gnu.org> <861q9exmhe.fsf@gnu.org> <86v86im1r9.fsf@gnu.org> <868r36uzdh.fsf@gnu.org> <86bk7ysbbz.fsf@gnu.org> MIME-version: 1.0 Content-type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 69083 Cc: 69083@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: Raffael Stocker > Cc: 69083@debbugs.gnu.org > Date: Sun, 03 Mar 2024 17:43:56 +0100 > > >> I don't know much about the internals of Emacs frame handling. > >> Could ‘w32_frame_list_z_order’ be used (from the input thread) for > >> something like that? Or is there a better approach? > > > > Why is the order important? Can't you "hand" the registration to some > > other frame, no matter which one? > > The order is not important, I just didn't know where to look to get > a frame; sorry for the noise. I now use ‘Fnext_frame’. Unfortunately, I don't think you cannot use Fnext_frame here. The function which calls it, w32_wnd_proc, runs in a separate thread, so it generally cannot access Lisp objects safely. However, it is okay to traverse the list of the frames, as w32_window_to_frame does, see the comment at the beginning of w32_wnd_proc. So I think you could use a similar loop with FOR_EACH_FRAME, and use some frame from there, perhaps the first one? Alternatively, and maybe more safely, you could call maybe_pass_notification from w32_destroy_window, which is called from the main (a.k.a. "Lisp") thread, so then you can use Fnext_frame (actually, I would make next_frame extern instead of static and call it directly). This means the notifications are passed a bit before the frame is actually deleted by the OS, but I think this is okay? Otherwise, I think the patch is fine, at least from reading it. Thanks. From debbugs-submit-bounces@debbugs.gnu.org Sun Mar 03 12:40:19 2024 Received: (at 69083) by debbugs.gnu.org; 3 Mar 2024 17:40:19 +0000 Received: from localhost ([127.0.0.1]:41255 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rgpox-0001nO-6M for submit@debbugs.gnu.org; Sun, 03 Mar 2024 12:40:19 -0500 Received: from eggs.gnu.org ([209.51.188.92]:35754) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rgpou-0001nA-GO for 69083@debbugs.gnu.org; Sun, 03 Mar 2024 12:40:17 -0500 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rgpoK-0004FC-U6; Sun, 03 Mar 2024 12:39:40 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date: mime-version; bh=akIekGLN+KismDUvD3byciab7CdZMq9hQ9nZrBqI+PU=; b=R2YZjIh+Xdim sQFdKFulAxB/MK0QpAz96uxou/GK9evN2SZgcQIyNEA3ig4PBaIpioE4RdMQVElsvThfKrNF6yVyO OxMUAWt6BMqPdn2oooFWaee4GClY1XHAAgNj6YRTUBnwObq5ZJI44D3YOO4cbSu/UWwpKJPqMh+6W s7wDwKNFIDhJyb5wMANM3ClPjsEpLrlKh2i931OQT8wq64GGeSJcpsfUbxzXBEOh/ZRYPZYIwUMTv I4eH3RTbi2ktEMfjVSmEtTexD/xyNHTbuC1nnrf4IwfyyRW54EgmcVNNUKWHaQu+vrd/Ii95eswkb xfwj5B0k7x+HQG96KhUHLA==; Date: Sun, 03 Mar 2024 19:39:38 +0200 Message-Id: <865xy3nrj9.fsf@gnu.org> From: Eli Zaretskii To: r.stocker@mnet-mail.de In-Reply-To: <868r2znsau.fsf@gnu.org> (message from Eli Zaretskii on Sun, 03 Mar 2024 19:23:05 +0200) Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) References: <86cyt1qvmt.fsf@gnu.org> <861q9exmhe.fsf@gnu.org> <86v86im1r9.fsf@gnu.org> <868r36uzdh.fsf@gnu.org> <86bk7ysbbz.fsf@gnu.org> <868r2znsau.fsf@gnu.org> X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 69083 Cc: 69083@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > Cc: 69083@debbugs.gnu.org > Date: Sun, 03 Mar 2024 19:23:05 +0200 > From: Eli Zaretskii > > Unfortunately, I don't think you cannot use Fnext_frame here. The ^^^^^^ That was supposed to be "can", not "cannot"... Sorry. From debbugs-submit-bounces@debbugs.gnu.org Mon Mar 04 13:11:14 2024 Received: (at 69083) by debbugs.gnu.org; 4 Mar 2024 18:11:14 +0000 Received: from localhost ([127.0.0.1]:44858 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rhCmP-0005fm-F1 for submit@debbugs.gnu.org; Mon, 04 Mar 2024 13:11:14 -0500 Received: from mail-out.m-online.net ([212.18.0.9]:42454) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rhCmL-0005fY-PR for 69083@debbugs.gnu.org; Mon, 04 Mar 2024 13:11:12 -0500 Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 4TpRZQ3sP6z1qsNt; Mon, 4 Mar 2024 19:10:38 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.68]) by mail.m-online.net (Postfix) with ESMTP id 4TpRZQ29Y8z1qqlW; Mon, 4 Mar 2024 19:10:38 +0100 (CET) X-Virus-Scanned: amavis at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.68]) (amavis, port 10024) with ESMTP id cLct74YIsXt5; Mon, 4 Mar 2024 19:10:37 +0100 (CET) X-Auth-Info: B7CksHTGNqBUg2zqOc54wZhNmb7QJxbtKPd2XAduhg6D/pUomtN2D/sEjVK5JF4O Received: from Whiteflame (ppp-212-114-182-252.dynamic.mnet-online.de [212.114.182.252]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA; Mon, 4 Mar 2024 19:10:37 +0100 (CET) From: Raffael Stocker To: Eli Zaretskii Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) In-Reply-To: <868r2znsau.fsf@gnu.org> (Eli Zaretskii's message of "Sun, 03 Mar 2024 19:23:05 +0200") References: <86cyt1qvmt.fsf@gnu.org> <861q9exmhe.fsf@gnu.org> <86v86im1r9.fsf@gnu.org> <868r36uzdh.fsf@gnu.org> <86bk7ysbbz.fsf@gnu.org> <868r2znsau.fsf@gnu.org> User-Agent: mu4e 1.12.0; emacs 29.2 Date: Mon, 04 Mar 2024 19:10:33 +0100 Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Spam-Score: -0.0 (/) X-Debbugs-Envelope-To: 69083 Cc: 69083@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.7 (-) --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Eli Zaretskii writes: >> The order is not important, I just didn't know where to look to get >> a frame; sorry for the noise. I now use =E2=80=98Fnext_frame=E2=80=99. > > Unfortunately, I don't think you cannot use Fnext_frame here. The > function which calls it, w32_wnd_proc, runs in a separate thread, so > it generally cannot access Lisp objects safely. However, it is okay > to traverse the list of the frames, as w32_window_to_frame does, see > the comment at the beginning of w32_wnd_proc. So I think you could > use a similar loop with FOR_EACH_FRAME, and use some frame from there, > perhaps the first one? > > Alternatively, and maybe more safely, you could call > maybe_pass_notification from w32_destroy_window, which is called from > the main (a.k.a. "Lisp") thread, so then you can use Fnext_frame > (actually, I would make next_frame extern instead of static and call > it directly). This means the notifications are passed a bit before > the frame is actually deleted by the OS, but I think this is okay? I went with the first option, using FOR_EACH_FRAME, because I am not sure about the safety of modifying the kbdhook struct from the other thread. Regards, Raffael --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Fix-resetting-keyboard-hook-state-on-Windows.patch Content-Description: Fix keyboard hook state reset >From 93e6446d3e75b990230618f9d3331fd5a0818d50 Mon Sep 17 00:00:00 2001 From: Raffael Stocker Date: Mon, 4 Mar 2024 19:06:07 +0100 Subject: [PATCH] Fix resetting keyboard hook state on Windows Register session notifications so Emacs is notified when the computer is being locked, as required to reset the low level keyboard hook state (Bug#69083). * src/w32term.h: * src/w32fns.c (setup_w32_kbdhook, remove_w32_kbdhook) (w32_wnd_proc, globals_of_w32fns, maybe_pass_notification): Register and manage session notifications in GUI Emacs. * src/w32console.c (initialize_w32_display, find_ime_window): * src/w32xfns.c (drain_message_queue): Register notifications and reset keyboard hook state in console Emacs. * src/w32.c (term_ntproc): Un-register session notifications when terminating. --- src/w32.c | 5 +++ src/w32console.c | 25 ++++++++++++-- src/w32fns.c | 84 +++++++++++++++++++++++++++++++++++++++++++++--- src/w32term.h | 3 +- src/w32xfns.c | 12 +++++-- 5 files changed, 120 insertions(+), 9 deletions(-) diff --git a/src/w32.c b/src/w32.c index df5465c2135..d34ab70f82d 100644 --- a/src/w32.c +++ b/src/w32.c @@ -10392,11 +10392,16 @@ check_windows_init_file (void) } } +/* from w32fns.c */ +extern void remove_w32_kbdhook (void); + void term_ntproc (int ignored) { (void)ignored; + remove_w32_kbdhook (); + term_timers (); /* shutdown the socket interface if necessary */ diff --git a/src/w32console.c b/src/w32console.c index 0936b5f37e6..7dcbc795cac 100644 --- a/src/w32console.c +++ b/src/w32console.c @@ -659,6 +659,24 @@ w32_face_attributes (struct frame *f, int face_id) return char_attr; } +/* The IME window is needed to receive the session notifications + required to reset the low level keyboard hook state. */ + +static BOOL CALLBACK +find_ime_window (HWND hwnd, LPARAM arg) +{ + char window_class[32]; + + GetClassName (hwnd, window_class, sizeof (window_class)); + if (strcmp (window_class, "IME") == 0) + { + *(HWND *) arg = hwnd; + return FALSE; + } + /* keep looking */ + return TRUE; +} + void initialize_w32_display (struct terminal *term, int *width, int *height) { @@ -818,11 +836,14 @@ initialize_w32_display (struct terminal *term, int *width, int *height) else w32_console_unicode_input = 0; - /* Setup w32_display_info structure for this frame. */ + /* Setup w32_display_info structure for this frame. */ w32_initialize_display_info (build_string ("Console")); + HWND hwnd = NULL; + EnumThreadWindows (GetCurrentThreadId (), find_ime_window, (LPARAM) &hwnd); + /* Set up the keyboard hook. */ - setup_w32_kbdhook (); + setup_w32_kbdhook (hwnd); } diff --git a/src/w32fns.c b/src/w32fns.c index 8d4bd00b91c..3e4a8c475b7 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -49,6 +49,7 @@ #define _WIN32_WINNT 0x0600 #ifdef WINDOWSNT #include #include /* for _getmbcp */ +#include /* for WTS(Un)RegisterSessionNotification */ #endif /* WINDOWSNT */ #if CYGWIN @@ -204,6 +205,10 @@ DECLARE_HANDLE(HMONITOR); typedef HRESULT (WINAPI * DwmSetWindowAttribute_Proc) (HWND hwnd, DWORD dwAttribute, IN LPCVOID pvAttribute, DWORD cbAttribute); +typedef BOOL (WINAPI * WTSRegisterSessionNotification_Proc) + (HWND hwnd, DWORD dwFlags); +typedef BOOL (WINAPI * WTSUnRegisterSessionNotification_Proc) (HWND hwnd); + TrackMouseEvent_Proc track_mouse_event_fn = NULL; ImmGetCompositionString_Proc get_composition_string_fn = NULL; ImmGetContext_Proc get_ime_context_fn = NULL; @@ -220,6 +225,8 @@ DECLARE_HANDLE(HMONITOR); SetThreadDescription_Proc set_thread_description = NULL; SetWindowTheme_Proc SetWindowTheme_fn = NULL; DwmSetWindowAttribute_Proc DwmSetWindowAttribute_fn = NULL; +WTSUnRegisterSessionNotification_Proc WTSUnRegisterSessionNotification_fn = NULL; +WTSRegisterSessionNotification_Proc WTSRegisterSessionNotification_fn = NULL; extern AppendMenuW_Proc unicode_append_menu; @@ -307,6 +314,7 @@ #define WS_EX_NOACTIVATE 0x08000000L int hook_count; /* counter, if several windows are created */ HHOOK hook; /* hook handle */ HWND console; /* console window handle */ + HWND notified_wnd; /* window that receives session notifications */ int lwindown; /* Left Windows key currently pressed (and hooked) */ int rwindown; /* Right Windows key currently pressed (and hooked) */ @@ -2744,7 +2752,7 @@ funhook (int code, WPARAM w, LPARAM l) /* Set up the hook; can be called several times, with matching remove_w32_kbdhook calls. */ void -setup_w32_kbdhook (void) +setup_w32_kbdhook (HWND hwnd) { kbdhook.hook_count++; @@ -2800,6 +2808,15 @@ setup_w32_kbdhook (void) /* Set the hook. */ kbdhook.hook = SetWindowsHookEx (WH_KEYBOARD_LL, funhook, GetModuleHandle (NULL), 0); + + /* Register session notifications so we get notified about the + computer being locked. */ + kbdhook.notified_wnd = NULL; + if (hwnd != NULL && WTSRegisterSessionNotification_fn != NULL) + { + WTSRegisterSessionNotification_fn (hwnd, NOTIFY_FOR_THIS_SESSION); + kbdhook.notified_wnd = hwnd; + } } } @@ -2811,7 +2828,11 @@ remove_w32_kbdhook (void) if (kbdhook.hook_count == 0 && w32_kbdhook_active) { UnhookWindowsHookEx (kbdhook.hook); + if (kbdhook.notified_wnd != NULL + && WTSUnRegisterSessionNotification_fn != NULL) + WTSUnRegisterSessionNotification_fn (kbdhook.notified_wnd); kbdhook.hook = NULL; + kbdhook.notified_wnd = NULL; } } #endif /* WINDOWSNT */ @@ -2884,13 +2905,12 @@ check_w32_winkey_state (int vkey) } return 0; } -#endif /* WINDOWSNT */ /* Reset the keyboard hook state. Locking the workstation with Win-L leaves the Win key(s) "down" from the hook's point of view - the keyup event is never seen. Thus, this function must be called when the system is locked. */ -static void +void reset_w32_kbdhook_state (void) { kbdhook.lwindown = 0; @@ -2900,6 +2920,7 @@ reset_w32_kbdhook_state (void) kbdhook.suppress_lone = 0; kbdhook.winseen = 0; } +#endif /* WINDOWSNT */ /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish between left and right keys as advertised. We test for this @@ -4129,6 +4150,47 @@ #define S_TYPES_TO_REPORT_CHARACTER_PAYLOAD_WITH_MODIFIERS "" return 0; } +/* Maybe pass session notification registration to another frame. If + the frame with window handle HWND is deleted, we must pass the + notifications to some other frame, if they have been sent to this + frame before and have not already been passed on. If there is no + other frame, do nothing. */ + +#ifdef WINDOWSNT +static void +maybe_pass_notification (HWND hwnd) +{ + if (hwnd == kbdhook.notified_wnd + && kbdhook.hook_count > 0 && w32_kbdhook_active) + { + Lisp_Object tail, frame; + struct frame *f; + bool found_frame = false; + + FOR_EACH_FRAME (tail, frame) + { + f = XFRAME (frame); + if (FRAME_W32_P (f) && FRAME_OUTPUT_DATA (f) != NULL + && FRAME_W32_WINDOW (f) != hwnd) + { + found_frame = true; + break; + } + } + + if (found_frame && WTSUnRegisterSessionNotification_fn != NULL + && WTSRegisterSessionNotification_fn != NULL) + { + /* There is another frame, pass on the session notification. */ + HWND next_wnd = FRAME_W32_WINDOW (f); + WTSUnRegisterSessionNotification_fn (hwnd); + WTSRegisterSessionNotification_fn (next_wnd, NOTIFY_FOR_THIS_SESSION); + kbdhook.notified_wnd = next_wnd; + } + } +} +#endif /* WINDOWSNT */ + /* Main window procedure */ static LRESULT CALLBACK @@ -5301,23 +5363,29 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) #ifdef WINDOWSNT case WM_CREATE: - setup_w32_kbdhook (); + setup_w32_kbdhook (hwnd); goto dflt; #endif case WM_DESTROY: #ifdef WINDOWSNT + maybe_pass_notification (hwnd); remove_w32_kbdhook (); #endif CoUninitialize (); return 0; +#ifdef WINDOWSNT case WM_WTSSESSION_CHANGE: if (wParam == WTS_SESSION_LOCK) reset_w32_kbdhook_state (); goto dflt; +#endif case WM_CLOSE: +#ifdef WINDOWSNT + maybe_pass_notification (hwnd); +#endif wmsg.dwModifiers = w32_get_modifiers (); my_post_msg (&wmsg, hwnd, msg, wParam, lParam); return 0; @@ -11335,6 +11403,14 @@ globals_of_w32fns (void) set_thread_description = (SetThreadDescription_Proc) get_proc_addr (hm_kernel32, "SetThreadDescription"); +#ifdef WINDOWSNT + HMODULE wtsapi32_lib = LoadLibrary ("wtsapi32.dll"); + WTSRegisterSessionNotification_fn = (WTSRegisterSessionNotification_Proc) + get_proc_addr (wtsapi32_lib, "WTSRegisterSessionNotification"); + WTSUnRegisterSessionNotification_fn = (WTSUnRegisterSessionNotification_Proc) + get_proc_addr (wtsapi32_lib, "WTSUnRegisterSessionNotification"); +#endif + /* Support OS dark mode on Windows 10 version 1809 and higher. See `w32_applytheme' which uses appropriate APIs per version of Windows. For future wretches who may need to understand Windows build numbers: diff --git a/src/w32term.h b/src/w32term.h index 29ace0b2797..3120c8bd71f 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -779,8 +779,9 @@ #define FILE_NOTIFICATIONS_SIZE 16384 #ifdef WINDOWSNT /* Keyboard hooks. */ -extern void setup_w32_kbdhook (void); +extern void setup_w32_kbdhook (HWND); extern void remove_w32_kbdhook (void); +extern void reset_w32_kbdhook_state (void); extern int check_w32_winkey_state (int); #define w32_kbdhook_active (os_subtype != OS_SUBTYPE_9X) #else diff --git a/src/w32xfns.c b/src/w32xfns.c index fa7d5fbdb61..3d7a1514f72 100644 --- a/src/w32xfns.c +++ b/src/w32xfns.c @@ -413,8 +413,16 @@ drain_message_queue (void) while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { - if (msg.message == WM_EMACS_FILENOTIFY) - retval = 1; + switch (msg.message) + { + case WM_WTSSESSION_CHANGE: + if (msg.wParam == WTS_SESSION_LOCK) + reset_w32_kbdhook_state (); + break; + case WM_EMACS_FILENOTIFY: + retval = 1; + break; + } TranslateMessage (&msg); DispatchMessage (&msg); } -- 2.44.0 --=-=-=-- From debbugs-submit-bounces@debbugs.gnu.org Thu Mar 14 04:25:58 2024 Received: (at 69083-done) by debbugs.gnu.org; 14 Mar 2024 08:25:58 +0000 Received: from localhost ([127.0.0.1]:48239 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rkgPV-00083G-QM for submit@debbugs.gnu.org; Thu, 14 Mar 2024 04:25:58 -0400 Received: from eggs.gnu.org ([209.51.188.92]:33826) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rkgPT-000833-Pf for 69083-done@debbugs.gnu.org; Thu, 14 Mar 2024 04:25:56 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rkgOm-0005cp-RO; Thu, 14 Mar 2024 04:25:14 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From: Date; bh=63QbSdz9Y7yfWH8aoyJKCxw2bu00Z+nrxs+0M4tTJkM=; b=nISOHu7GKezIMXDjfuM7 rf5vB/s+CMpU3hUBC8WNPfeV4OhVN0d8iz3o8xFmmTWyJ9vDf8MDcaC0E4/4rxTG27dHmIN/jjdFM 8e9SgVbQ0eiawaywucWkxHo0C+1VlpPokvpcclvQIjElUaHOy/hWAKLB5g8zGbDZ6zfsCfL6K9/C3 DQZqMpLlSfJmZtHx0hAEGXhCgrJnMB/co+i0f5KxvOw2WOK6uGPuzpbfh8AjDCX2+0lyMuHYAn24V Mo22kgYWbTEsoXgIL/OwGVztS1Vyd8UpNo5jznYubD/KOhYLcX4cG8lMlM9jGw7ENZwhElCdpw8hT klvvT4p5tG3HMQ==; Date: Thu, 14 Mar 2024 10:25:07 +0200 Message-Id: <86il1pb4po.fsf@gnu.org> From: Eli Zaretskii To: Raffael Stocker In-Reply-To: (message from Raffael Stocker on Mon, 04 Mar 2024 19:10:33 +0100) Subject: Re: bug#69083: Emacs's keyboard hook state is not reset on session lock (Windows) References: <86cyt1qvmt.fsf@gnu.org> <861q9exmhe.fsf@gnu.org> <86v86im1r9.fsf@gnu.org> <868r36uzdh.fsf@gnu.org> <86bk7ysbbz.fsf@gnu.org> <868r2znsau.fsf@gnu.org> MIME-version: 1.0 Content-type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: 69083-done Cc: 69083-done@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: Raffael Stocker > Cc: 69083@debbugs.gnu.org > Date: Mon, 04 Mar 2024 19:10:33 +0100 > > Eli Zaretskii writes: > > >> The order is not important, I just didn't know where to look to get > >> a frame; sorry for the noise. I now use ‘Fnext_frame’. > > > > Unfortunately, I don't think you cannot use Fnext_frame here. The > > function which calls it, w32_wnd_proc, runs in a separate thread, so > > it generally cannot access Lisp objects safely. However, it is okay > > to traverse the list of the frames, as w32_window_to_frame does, see > > the comment at the beginning of w32_wnd_proc. So I think you could > > use a similar loop with FOR_EACH_FRAME, and use some frame from there, > > perhaps the first one? > > > > Alternatively, and maybe more safely, you could call > > maybe_pass_notification from w32_destroy_window, which is called from > > the main (a.k.a. "Lisp") thread, so then you can use Fnext_frame > > (actually, I would make next_frame extern instead of static and call > > it directly). This means the notifications are passed a bit before > > the frame is actually deleted by the OS, but I think this is okay? > > I went with the first option, using FOR_EACH_FRAME, because I am not > sure about the safety of modifying the kbdhook struct from the other > thread. Thanks. I needed to fix this in small ways, to get it to compile with mingw.org's MinGW, and I've now installed the results on the master branch. With that, I'm closing this bug. From unknown Sat Sep 20 08:01:23 2025 Received: (at fakecontrol) by fakecontrolmessage; To: internal_control@debbugs.gnu.org From: Debbugs Internal Request Subject: Internal Control Message-Id: bug archived. Date: Thu, 11 Apr 2024 11:24:39 +0000 User-Agent: Fakemail v42.6.9 # This is a fake control message. # # The action: # bug archived. thanks # This fakemail brought to you by your local debbugs # administrator