aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRaffael Stocker2024-03-04 19:06:07 +0100
committerEli Zaretskii2024-03-14 10:01:06 +0200
commite7b1743b798cab338e0fa7b98dfb20c0ba7204b1 (patch)
tree20f0ac8ef16258964c66b4f8f1a907f1263d3ef9 /src
parent1b94f800ae34de5f4e72682a81de1d42bdda9276 (diff)
downloademacs-e7b1743b798cab338e0fa7b98dfb20c0ba7204b1.tar.gz
emacs-e7b1743b798cab338e0fa7b98dfb20c0ba7204b1.zip
Fix resetting keyboard hook state on MS-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.
Diffstat (limited to 'src')
-rw-r--r--src/w32.c5
-rw-r--r--src/w32console.c25
-rw-r--r--src/w32fns.c84
-rw-r--r--src/w32term.h3
-rw-r--r--src/w32xfns.c12
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)
10392 } 10392 }
10393} 10393}
10394 10394
10395/* from w32fns.c */
10396extern void remove_w32_kbdhook (void);
10397
10395void 10398void
10396term_ntproc (int ignored) 10399term_ntproc (int ignored)
10397{ 10400{
10398 (void)ignored; 10401 (void)ignored;
10399 10402
10403 remove_w32_kbdhook ();
10404
10400 term_timers (); 10405 term_timers ();
10401 10406
10402 /* shutdown the socket interface if necessary */ 10407 /* 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)
659 return char_attr; 659 return char_attr;
660} 660}
661 661
662/* The IME window is needed to receive the session notifications
663 required to reset the low level keyboard hook state. */
664
665static BOOL CALLBACK
666find_ime_window (HWND hwnd, LPARAM arg)
667{
668 char window_class[32];
669
670 GetClassName (hwnd, window_class, sizeof (window_class));
671 if (strcmp (window_class, "IME") == 0)
672 {
673 *(HWND *) arg = hwnd;
674 return FALSE;
675 }
676 /* keep looking */
677 return TRUE;
678}
679
662void 680void
663initialize_w32_display (struct terminal *term, int *width, int *height) 681initialize_w32_display (struct terminal *term, int *width, int *height)
664{ 682{
@@ -818,11 +836,14 @@ initialize_w32_display (struct terminal *term, int *width, int *height)
818 else 836 else
819 w32_console_unicode_input = 0; 837 w32_console_unicode_input = 0;
820 838
821 /* Setup w32_display_info structure for this frame. */ 839 /* Setup w32_display_info structure for this frame. */
822 w32_initialize_display_info (build_string ("Console")); 840 w32_initialize_display_info (build_string ("Console"));
823 841
842 HWND hwnd = NULL;
843 EnumThreadWindows (GetCurrentThreadId (), find_ime_window, (LPARAM) &hwnd);
844
824 /* Set up the keyboard hook. */ 845 /* Set up the keyboard hook. */
825 setup_w32_kbdhook (); 846 setup_w32_kbdhook (hwnd);
826} 847}
827 848
828 849
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 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
49#ifdef WINDOWSNT 49#ifdef WINDOWSNT
50#include <mbstring.h> 50#include <mbstring.h>
51#include <mbctype.h> /* for _getmbcp */ 51#include <mbctype.h> /* for _getmbcp */
52#include <wtsapi32.h> /* for WTS(Un)RegisterSessionNotification */
52#endif /* WINDOWSNT */ 53#endif /* WINDOWSNT */
53 54
54#if CYGWIN 55#if CYGWIN
@@ -204,6 +205,10 @@ typedef HRESULT (WINAPI * SetWindowTheme_Proc)
204typedef HRESULT (WINAPI * DwmSetWindowAttribute_Proc) 205typedef HRESULT (WINAPI * DwmSetWindowAttribute_Proc)
205 (HWND hwnd, DWORD dwAttribute, IN LPCVOID pvAttribute, DWORD cbAttribute); 206 (HWND hwnd, DWORD dwAttribute, IN LPCVOID pvAttribute, DWORD cbAttribute);
206 207
208typedef BOOL (WINAPI * WTSRegisterSessionNotification_Proc)
209 (HWND hwnd, DWORD dwFlags);
210typedef BOOL (WINAPI * WTSUnRegisterSessionNotification_Proc) (HWND hwnd);
211
207TrackMouseEvent_Proc track_mouse_event_fn = NULL; 212TrackMouseEvent_Proc track_mouse_event_fn = NULL;
208ImmGetCompositionString_Proc get_composition_string_fn = NULL; 213ImmGetCompositionString_Proc get_composition_string_fn = NULL;
209ImmGetContext_Proc get_ime_context_fn = NULL; 214ImmGetContext_Proc get_ime_context_fn = NULL;
@@ -220,6 +225,8 @@ IsDebuggerPresent_Proc is_debugger_present = NULL;
220SetThreadDescription_Proc set_thread_description = NULL; 225SetThreadDescription_Proc set_thread_description = NULL;
221SetWindowTheme_Proc SetWindowTheme_fn = NULL; 226SetWindowTheme_Proc SetWindowTheme_fn = NULL;
222DwmSetWindowAttribute_Proc DwmSetWindowAttribute_fn = NULL; 227DwmSetWindowAttribute_Proc DwmSetWindowAttribute_fn = NULL;
228WTSUnRegisterSessionNotification_Proc WTSUnRegisterSessionNotification_fn = NULL;
229WTSRegisterSessionNotification_Proc WTSRegisterSessionNotification_fn = NULL;
223 230
224extern AppendMenuW_Proc unicode_append_menu; 231extern AppendMenuW_Proc unicode_append_menu;
225 232
@@ -307,6 +314,7 @@ static struct
307 int hook_count; /* counter, if several windows are created */ 314 int hook_count; /* counter, if several windows are created */
308 HHOOK hook; /* hook handle */ 315 HHOOK hook; /* hook handle */
309 HWND console; /* console window handle */ 316 HWND console; /* console window handle */
317 HWND notified_wnd; /* window that receives session notifications */
310 318
311 int lwindown; /* Left Windows key currently pressed (and hooked) */ 319 int lwindown; /* Left Windows key currently pressed (and hooked) */
312 int rwindown; /* Right Windows key currently pressed (and hooked) */ 320 int rwindown; /* Right Windows key currently pressed (and hooked) */
@@ -2744,7 +2752,7 @@ funhook (int code, WPARAM w, LPARAM l)
2744/* Set up the hook; can be called several times, with matching 2752/* Set up the hook; can be called several times, with matching
2745 remove_w32_kbdhook calls. */ 2753 remove_w32_kbdhook calls. */
2746void 2754void
2747setup_w32_kbdhook (void) 2755setup_w32_kbdhook (HWND hwnd)
2748{ 2756{
2749 kbdhook.hook_count++; 2757 kbdhook.hook_count++;
2750 2758
@@ -2800,6 +2808,15 @@ setup_w32_kbdhook (void)
2800 /* Set the hook. */ 2808 /* Set the hook. */
2801 kbdhook.hook = SetWindowsHookEx (WH_KEYBOARD_LL, funhook, 2809 kbdhook.hook = SetWindowsHookEx (WH_KEYBOARD_LL, funhook,
2802 GetModuleHandle (NULL), 0); 2810 GetModuleHandle (NULL), 0);
2811
2812 /* Register session notifications so we get notified about the
2813 computer being locked. */
2814 kbdhook.notified_wnd = NULL;
2815 if (hwnd != NULL && WTSRegisterSessionNotification_fn != NULL)
2816 {
2817 WTSRegisterSessionNotification_fn (hwnd, NOTIFY_FOR_THIS_SESSION);
2818 kbdhook.notified_wnd = hwnd;
2819 }
2803 } 2820 }
2804} 2821}
2805 2822
@@ -2811,7 +2828,11 @@ remove_w32_kbdhook (void)
2811 if (kbdhook.hook_count == 0 && w32_kbdhook_active) 2828 if (kbdhook.hook_count == 0 && w32_kbdhook_active)
2812 { 2829 {
2813 UnhookWindowsHookEx (kbdhook.hook); 2830 UnhookWindowsHookEx (kbdhook.hook);
2831 if (kbdhook.notified_wnd != NULL
2832 && WTSUnRegisterSessionNotification_fn != NULL)
2833 WTSUnRegisterSessionNotification_fn (kbdhook.notified_wnd);
2814 kbdhook.hook = NULL; 2834 kbdhook.hook = NULL;
2835 kbdhook.notified_wnd = NULL;
2815 } 2836 }
2816} 2837}
2817#endif /* WINDOWSNT */ 2838#endif /* WINDOWSNT */
@@ -2884,13 +2905,12 @@ check_w32_winkey_state (int vkey)
2884 } 2905 }
2885 return 0; 2906 return 0;
2886} 2907}
2887#endif /* WINDOWSNT */
2888 2908
2889/* Reset the keyboard hook state. Locking the workstation with Win-L 2909/* Reset the keyboard hook state. Locking the workstation with Win-L
2890 leaves the Win key(s) "down" from the hook's point of view - the 2910 leaves the Win key(s) "down" from the hook's point of view - the
2891 keyup event is never seen. Thus, this function must be called when 2911 keyup event is never seen. Thus, this function must be called when
2892 the system is locked. */ 2912 the system is locked. */
2893static void 2913void
2894reset_w32_kbdhook_state (void) 2914reset_w32_kbdhook_state (void)
2895{ 2915{
2896 kbdhook.lwindown = 0; 2916 kbdhook.lwindown = 0;
@@ -2900,6 +2920,7 @@ reset_w32_kbdhook_state (void)
2900 kbdhook.suppress_lone = 0; 2920 kbdhook.suppress_lone = 0;
2901 kbdhook.winseen = 0; 2921 kbdhook.winseen = 0;
2902} 2922}
2923#endif /* WINDOWSNT */
2903 2924
2904/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish 2925/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
2905 between left and right keys as advertised. We test for this 2926 between left and right keys as advertised. We test for this
@@ -4129,6 +4150,47 @@ deliver_wm_chars (int do_translate, HWND hwnd, UINT msg, UINT wParam,
4129 return 0; 4150 return 0;
4130} 4151}
4131 4152
4153/* Maybe pass session notification registration to another frame. If
4154 the frame with window handle HWND is deleted, we must pass the
4155 notifications to some other frame, if they have been sent to this
4156 frame before and have not already been passed on. If there is no
4157 other frame, do nothing. */
4158
4159#ifdef WINDOWSNT
4160static void
4161maybe_pass_notification (HWND hwnd)
4162{
4163 if (hwnd == kbdhook.notified_wnd
4164 && kbdhook.hook_count > 0 && w32_kbdhook_active)
4165 {
4166 Lisp_Object tail, frame;
4167 struct frame *f;
4168 bool found_frame = false;
4169
4170 FOR_EACH_FRAME (tail, frame)
4171 {
4172 f = XFRAME (frame);
4173 if (FRAME_W32_P (f) && FRAME_OUTPUT_DATA (f) != NULL
4174 && FRAME_W32_WINDOW (f) != hwnd)
4175 {
4176 found_frame = true;
4177 break;
4178 }
4179 }
4180
4181 if (found_frame && WTSUnRegisterSessionNotification_fn != NULL
4182 && WTSRegisterSessionNotification_fn != NULL)
4183 {
4184 /* There is another frame, pass on the session notification. */
4185 HWND next_wnd = FRAME_W32_WINDOW (f);
4186 WTSUnRegisterSessionNotification_fn (hwnd);
4187 WTSRegisterSessionNotification_fn (next_wnd, NOTIFY_FOR_THIS_SESSION);
4188 kbdhook.notified_wnd = next_wnd;
4189 }
4190 }
4191}
4192#endif /* WINDOWSNT */
4193
4132/* Main window procedure */ 4194/* Main window procedure */
4133 4195
4134static LRESULT CALLBACK 4196static LRESULT CALLBACK
@@ -5301,23 +5363,29 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
5301 5363
5302#ifdef WINDOWSNT 5364#ifdef WINDOWSNT
5303 case WM_CREATE: 5365 case WM_CREATE:
5304 setup_w32_kbdhook (); 5366 setup_w32_kbdhook (hwnd);
5305 goto dflt; 5367 goto dflt;
5306#endif 5368#endif
5307 5369
5308 case WM_DESTROY: 5370 case WM_DESTROY:
5309#ifdef WINDOWSNT 5371#ifdef WINDOWSNT
5372 maybe_pass_notification (hwnd);
5310 remove_w32_kbdhook (); 5373 remove_w32_kbdhook ();
5311#endif 5374#endif
5312 CoUninitialize (); 5375 CoUninitialize ();
5313 return 0; 5376 return 0;
5314 5377
5378#ifdef WINDOWSNT
5315 case WM_WTSSESSION_CHANGE: 5379 case WM_WTSSESSION_CHANGE:
5316 if (wParam == WTS_SESSION_LOCK) 5380 if (wParam == WTS_SESSION_LOCK)
5317 reset_w32_kbdhook_state (); 5381 reset_w32_kbdhook_state ();
5318 goto dflt; 5382 goto dflt;
5383#endif
5319 5384
5320 case WM_CLOSE: 5385 case WM_CLOSE:
5386#ifdef WINDOWSNT
5387 maybe_pass_notification (hwnd);
5388#endif
5321 wmsg.dwModifiers = w32_get_modifiers (); 5389 wmsg.dwModifiers = w32_get_modifiers ();
5322 my_post_msg (&wmsg, hwnd, msg, wParam, lParam); 5390 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5323 return 0; 5391 return 0;
@@ -11335,6 +11403,14 @@ globals_of_w32fns (void)
11335 set_thread_description = (SetThreadDescription_Proc) 11403 set_thread_description = (SetThreadDescription_Proc)
11336 get_proc_addr (hm_kernel32, "SetThreadDescription"); 11404 get_proc_addr (hm_kernel32, "SetThreadDescription");
11337 11405
11406#ifdef WINDOWSNT
11407 HMODULE wtsapi32_lib = LoadLibrary ("wtsapi32.dll");
11408 WTSRegisterSessionNotification_fn = (WTSRegisterSessionNotification_Proc)
11409 get_proc_addr (wtsapi32_lib, "WTSRegisterSessionNotification");
11410 WTSUnRegisterSessionNotification_fn = (WTSUnRegisterSessionNotification_Proc)
11411 get_proc_addr (wtsapi32_lib, "WTSUnRegisterSessionNotification");
11412#endif
11413
11338 /* Support OS dark mode on Windows 10 version 1809 and higher. 11414 /* Support OS dark mode on Windows 10 version 1809 and higher.
11339 See `w32_applytheme' which uses appropriate APIs per version of Windows. 11415 See `w32_applytheme' which uses appropriate APIs per version of Windows.
11340 For future wretches who may need to understand Windows build numbers: 11416 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 @@ extern bool w32_image_rotations_p (void);
779 779
780#ifdef WINDOWSNT 780#ifdef WINDOWSNT
781/* Keyboard hooks. */ 781/* Keyboard hooks. */
782extern void setup_w32_kbdhook (void); 782extern void setup_w32_kbdhook (HWND);
783extern void remove_w32_kbdhook (void); 783extern void remove_w32_kbdhook (void);
784extern void reset_w32_kbdhook_state (void);
784extern int check_w32_winkey_state (int); 785extern int check_w32_winkey_state (int);
785#define w32_kbdhook_active (os_subtype != OS_SUBTYPE_9X) 786#define w32_kbdhook_active (os_subtype != OS_SUBTYPE_9X)
786#else 787#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)
413 413
414 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) 414 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
415 { 415 {
416 if (msg.message == WM_EMACS_FILENOTIFY) 416 switch (msg.message)
417 retval = 1; 417 {
418 case WM_WTSSESSION_CHANGE:
419 if (msg.wParam == WTS_SESSION_LOCK)
420 reset_w32_kbdhook_state ();
421 break;
422 case WM_EMACS_FILENOTIFY:
423 retval = 1;
424 break;
425 }
418 TranslateMessage (&msg); 426 TranslateMessage (&msg);
419 DispatchMessage (&msg); 427 DispatchMessage (&msg);
420 } 428 }