diff options
| author | Raffael Stocker | 2024-03-04 19:06:07 +0100 |
|---|---|---|
| committer | Eli Zaretskii | 2024-03-14 10:01:06 +0200 |
| commit | e7b1743b798cab338e0fa7b98dfb20c0ba7204b1 (patch) | |
| tree | 20f0ac8ef16258964c66b4f8f1a907f1263d3ef9 /src | |
| parent | 1b94f800ae34de5f4e72682a81de1d42bdda9276 (diff) | |
| download | emacs-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.c | 5 | ||||
| -rw-r--r-- | src/w32console.c | 25 | ||||
| -rw-r--r-- | src/w32fns.c | 84 | ||||
| -rw-r--r-- | src/w32term.h | 3 | ||||
| -rw-r--r-- | src/w32xfns.c | 12 |
5 files changed, 120 insertions, 9 deletions
| @@ -10392,11 +10392,16 @@ check_windows_init_file (void) | |||
| 10392 | } | 10392 | } |
| 10393 | } | 10393 | } |
| 10394 | 10394 | ||
| 10395 | /* from w32fns.c */ | ||
| 10396 | extern void remove_w32_kbdhook (void); | ||
| 10397 | |||
| 10395 | void | 10398 | void |
| 10396 | term_ntproc (int ignored) | 10399 | term_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 | |||
| 665 | static BOOL CALLBACK | ||
| 666 | find_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 | |||
| 662 | void | 680 | void |
| 663 | initialize_w32_display (struct terminal *term, int *width, int *height) | 681 | initialize_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) | |||
| 204 | typedef HRESULT (WINAPI * DwmSetWindowAttribute_Proc) | 205 | typedef 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 | ||
| 208 | typedef BOOL (WINAPI * WTSRegisterSessionNotification_Proc) | ||
| 209 | (HWND hwnd, DWORD dwFlags); | ||
| 210 | typedef BOOL (WINAPI * WTSUnRegisterSessionNotification_Proc) (HWND hwnd); | ||
| 211 | |||
| 207 | TrackMouseEvent_Proc track_mouse_event_fn = NULL; | 212 | TrackMouseEvent_Proc track_mouse_event_fn = NULL; |
| 208 | ImmGetCompositionString_Proc get_composition_string_fn = NULL; | 213 | ImmGetCompositionString_Proc get_composition_string_fn = NULL; |
| 209 | ImmGetContext_Proc get_ime_context_fn = NULL; | 214 | ImmGetContext_Proc get_ime_context_fn = NULL; |
| @@ -220,6 +225,8 @@ IsDebuggerPresent_Proc is_debugger_present = NULL; | |||
| 220 | SetThreadDescription_Proc set_thread_description = NULL; | 225 | SetThreadDescription_Proc set_thread_description = NULL; |
| 221 | SetWindowTheme_Proc SetWindowTheme_fn = NULL; | 226 | SetWindowTheme_Proc SetWindowTheme_fn = NULL; |
| 222 | DwmSetWindowAttribute_Proc DwmSetWindowAttribute_fn = NULL; | 227 | DwmSetWindowAttribute_Proc DwmSetWindowAttribute_fn = NULL; |
| 228 | WTSUnRegisterSessionNotification_Proc WTSUnRegisterSessionNotification_fn = NULL; | ||
| 229 | WTSRegisterSessionNotification_Proc WTSRegisterSessionNotification_fn = NULL; | ||
| 223 | 230 | ||
| 224 | extern AppendMenuW_Proc unicode_append_menu; | 231 | extern 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. */ |
| 2746 | void | 2754 | void |
| 2747 | setup_w32_kbdhook (void) | 2755 | setup_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. */ |
| 2893 | static void | 2913 | void |
| 2894 | reset_w32_kbdhook_state (void) | 2914 | reset_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 | ||
| 4160 | static void | ||
| 4161 | maybe_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 | ||
| 4134 | static LRESULT CALLBACK | 4196 | static 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. */ |
| 782 | extern void setup_w32_kbdhook (void); | 782 | extern void setup_w32_kbdhook (HWND); |
| 783 | extern void remove_w32_kbdhook (void); | 783 | extern void remove_w32_kbdhook (void); |
| 784 | extern void reset_w32_kbdhook_state (void); | ||
| 784 | extern int check_w32_winkey_state (int); | 785 | extern 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 | } |