aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJussi Lahdenniemi2016-02-26 12:51:24 +0200
committerEli Zaretskii2016-02-26 12:51:24 +0200
commit97d7a0b8db4ce32a8e489dec48634b7e85212eaa (patch)
treee1477561851991fe7be1213747d201d744794286 /src
parent22994735af588be9c2d6d438155b73328aaa0cf3 (diff)
downloademacs-97d7a0b8db4ce32a8e489dec48634b7e85212eaa.tar.gz
emacs-97d7a0b8db4ce32a8e489dec48634b7e85212eaa.zip
Improve the register-hotkey functionality on MS-Windows
* src/w32fns.c (_WIN32_WINNT): Define to 0x0600, needed for keyboard hook functionality. Include w32inevt.h, basetyps.h and unknwn.h. (VK_ANY, WM_WTSSESSION_CHANGE, WTS_SESSION_LOCK): New macros. (kbdhook): A new struct definition. (funhook, setup_w32_kbdhook, remove_w32_kbdhook, hook_w32_key) (check_w32_winkey_state, reset_w32_kbdhook_state): New functions. (modifier_set): Call check_w32_winkey_state if a Win key was pressed and the keyboard hook is active. (w32_wnd_proc): Don't handle Win key combinations if the keyboard hook is active. Only register/unregister the hotkeys if the keyboard hook is not active. When WM_CREATE is received, call setup_w32_kbdhook. When WM_DESTROY is received, call reset_w32_kbdhook_state. (lookup_vk_code): When the keyboard hook is active, map alphanumeric characters to themselves. (w32_parse_and_hook_hot_key): Renamed from w32_parse_hot_key. Map modified keys to VK_ANY if the keyboard hook is active. Register Alt-x and Win-x combinations. (Fw32_shell_execute): Update doc string to reflect new functionality. Bypass the code that posts the WM_EMACS_REGISTER_HOT_KEY message if the keyboard hook is active. (Fw32_unregister_hot_key): Bypass the code that posts the WM_EMACS_UNREGISTER_HOT_KEY message if the keyboard hook is active. (syms_of_w32fns) <w32-pass-lwindow-to-system> <w32-pass-rwindow-to-system, w32-phantom-key-code> <w32-lwindow-modifier, w32-rwindow-modifier>: Update doc strings to reflect the new functionality. * src/w32console.c (initialize_w32_display): Install the low-level keyboard hook. * src/w32inevt.c (key_event): Handle Win-x combinations only if the keyboard hook is not active. If the hook is active, use check_w32_winkey_state instead. * src/w32term.h (setup_w32_kbdhook, remove_w32_kbdhook) (check_w32_winkey_state): Add prototypes. (w32_kbdhook_active): New macro. * doc/emacs/msdos.texi (Windows Keyboard): Update to reflect the new functionality.
Diffstat (limited to 'src')
-rw-r--r--src/w32console.c3
-rw-r--r--src/w32fns.c556
-rw-r--r--src/w32inevt.c20
-rw-r--r--src/w32term.h6
4 files changed, 541 insertions, 44 deletions
diff --git a/src/w32console.c b/src/w32console.c
index 6277f131b50..fdadd48f323 100644
--- a/src/w32console.c
+++ b/src/w32console.c
@@ -759,6 +759,9 @@ initialize_w32_display (struct terminal *term, int *width, int *height)
759 759
760 /* Setup w32_display_info structure for this frame. */ 760 /* Setup w32_display_info structure for this frame. */
761 w32_initialize_display_info (build_string ("Console")); 761 w32_initialize_display_info (build_string ("Console"));
762
763 /* Set up the keyboard hook. */
764 setup_w32_kbdhook ();
762} 765}
763 766
764 767
diff --git a/src/w32fns.c b/src/w32fns.c
index a5018ae9d30..10c8af71073 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -20,6 +20,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20/* Added by Kevin Gallo */ 20/* Added by Kevin Gallo */
21 21
22#include <config.h> 22#include <config.h>
23/* Override API version to get the latest functionality. */
24#undef _WIN32_WINNT
25#define _WIN32_WINNT 0x0600
23 26
24#include <signal.h> 27#include <signal.h>
25#include <stdio.h> 28#include <stdio.h>
@@ -41,6 +44,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
41#include "coding.h" 44#include "coding.h"
42 45
43#include "w32common.h" 46#include "w32common.h"
47#include "w32inevt.h"
44 48
45#ifdef WINDOWSNT 49#ifdef WINDOWSNT
46#include <mbstring.h> 50#include <mbstring.h>
@@ -52,6 +56,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
52#include "w32.h" 56#include "w32.h"
53#endif 57#endif
54 58
59#include <basetyps.h>
60#include <unknwn.h>
55#include <commctrl.h> 61#include <commctrl.h>
56#include <commdlg.h> 62#include <commdlg.h>
57#include <shellapi.h> 63#include <shellapi.h>
@@ -251,6 +257,38 @@ HINSTANCE hinst = NULL;
251static unsigned int sound_type = 0xFFFFFFFF; 257static unsigned int sound_type = 0xFFFFFFFF;
252#define MB_EMACS_SILENT (0xFFFFFFFF - 1) 258#define MB_EMACS_SILENT (0xFFFFFFFF - 1)
253 259
260/* Special virtual key code for indicating "any" key. */
261#define VK_ANY 0xFF
262
263#ifndef WM_WTSSESSION_CHANGE
264/* 32-bit MinGW does not define these constants. */
265# define WM_WTSSESSION_CHANGE 0x02B1
266# define WTS_SESSION_LOCK 0x7
267#endif
268
269/* Keyboard hook state data. */
270static struct
271{
272 int hook_count; /* counter, if several windows are created */
273 HHOOK hook; /* hook handle */
274 HWND console; /* console window handle */
275
276 int lwindown; /* Left Windows key currently pressed (and hooked) */
277 int rwindown; /* Right Windows key currently pressed (and hooked) */
278 int winsdown; /* Number of handled keys currently pressed */
279 int send_win_up; /* Pass through the keyup for this Windows key press? */
280 int suppress_lone; /* Suppress simulated Windows keydown-keyup for this press? */
281 int winseen; /* Windows keys seen during this press? */
282
283 char alt_hooked[256]; /* hook Alt+[this key]? */
284 char lwin_hooked[256]; /* hook left Win+[this key]? */
285 char rwin_hooked[256]; /* hook right Win+[this key]? */
286} kbdhook;
287typedef HWND (WINAPI *GetConsoleWindow_Proc) (void);
288
289/* stdin, from w32console.c */
290extern HANDLE keyboard_handle;
291
254/* Let the user specify a display with a frame. 292/* Let the user specify a display with a frame.
255 nil stands for the selected frame--or, if that is not a w32 frame, 293 nil stands for the selected frame--or, if that is not a w32 frame,
256 the first display on the list. */ 294 the first display on the list. */
@@ -2074,6 +2112,348 @@ my_post_msg (W32Msg * wmsg, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
2074 post_msg (wmsg); 2112 post_msg (wmsg);
2075} 2113}
2076 2114
2115/* The Windows keyboard hook callback. */
2116static LRESULT CALLBACK
2117funhook (int code, WPARAM w, LPARAM l)
2118{
2119 INPUT inputs[2];
2120 HWND focus = GetFocus ();
2121 int console = 0;
2122 KBDLLHOOKSTRUCT const *hs = (KBDLLHOOKSTRUCT*)l;
2123
2124 if (code < 0 || (hs->flags & LLKHF_INJECTED))
2125 return CallNextHookEx (0, code, w, l);
2126
2127 /* The keyboard hook sees keyboard input on all processes (except
2128 elevated ones, when Emacs itself is not elevated). As such,
2129 care must be taken to only filter out keyboard input when Emacs
2130 itself is on the foreground.
2131
2132 GetFocus returns a non-NULL window if another application is active,
2133 and always for a console Emacs process. For a console Emacs, determine
2134 focus by checking if the current foreground window is the process's
2135 console window. */
2136 if (focus == NULL && kbdhook.console != NULL)
2137 {
2138 if (GetForegroundWindow () == kbdhook.console)
2139 {
2140 focus = kbdhook.console;
2141 console = 1;
2142 }
2143 }
2144
2145 /* First, check hooks for the left and right Windows keys. */
2146 if (hs->vkCode == VK_LWIN || hs->vkCode == VK_RWIN)
2147 {
2148 if (focus != NULL && (w == WM_KEYDOWN || w == WM_SYSKEYDOWN))
2149 {
2150 /* The key is being pressed in an Emacs window. */
2151 if (hs->vkCode == VK_LWIN && !kbdhook.lwindown)
2152 {
2153 kbdhook.lwindown = 1;
2154 kbdhook.winseen = 1;
2155 kbdhook.winsdown++;
2156 }
2157 else if (hs->vkCode == VK_RWIN && !kbdhook.rwindown)
2158 {
2159 kbdhook.rwindown = 1;
2160 kbdhook.winseen = 1;
2161 kbdhook.winsdown++;
2162 }
2163 /* Returning 1 here drops the keypress without further processing.
2164 If the keypress was allowed to go through, the normal Windows
2165 hotkeys would take over. */
2166 return 1;
2167 }
2168 else if (kbdhook.winsdown > 0 && (w == WM_KEYUP || w == WM_SYSKEYUP))
2169 {
2170 /* A key that has been captured earlier is being released now. */
2171 if (hs->vkCode == VK_LWIN && kbdhook.lwindown)
2172 {
2173 kbdhook.lwindown = 0;
2174 kbdhook.winsdown--;
2175 }
2176 else if (hs->vkCode == VK_RWIN && kbdhook.rwindown)
2177 {
2178 kbdhook.rwindown = 0;
2179 kbdhook.winsdown--;
2180 }
2181 if (kbdhook.winsdown == 0 && kbdhook.winseen)
2182 {
2183 if (!kbdhook.suppress_lone)
2184 {
2185 /* The Windows key was pressed, then released,
2186 without any other key pressed simultaneously.
2187 Normally, this opens the Start menu, but the user
2188 can prevent this by setting the
2189 w32-pass-[lr]window-to-system variable to
2190 NIL. */
2191 if (hs->vkCode == VK_LWIN && !NILP (Vw32_pass_lwindow_to_system) ||
2192 hs->vkCode == VK_RWIN && !NILP (Vw32_pass_rwindow_to_system))
2193 {
2194 /* Not prevented - Simulate the keypress to the system. */
2195 memset (inputs, 0, sizeof (inputs));
2196 inputs[0].type = INPUT_KEYBOARD;
2197 inputs[0].ki.wVk = hs->vkCode;
2198 inputs[0].ki.wScan = hs->vkCode;
2199 inputs[0].ki.dwFlags = KEYEVENTF_EXTENDEDKEY;
2200 inputs[0].ki.time = 0;
2201 inputs[1].type = INPUT_KEYBOARD;
2202 inputs[1].ki.wVk = hs->vkCode;
2203 inputs[1].ki.wScan = hs->vkCode;
2204 inputs[1].ki.dwFlags
2205 = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP;
2206 inputs[1].ki.time = 0;
2207 SendInput (2, inputs, sizeof (INPUT));
2208 }
2209 else if (focus != NULL)
2210 {
2211 /* When not passed to system, must simulate privately to Emacs. */
2212 PostMessage (focus, WM_SYSKEYDOWN, hs->vkCode, 0);
2213 PostMessage (focus, WM_SYSKEYUP, hs->vkCode, 0);
2214 }
2215 }
2216 }
2217 if (kbdhook.winsdown == 0)
2218 {
2219 /* No Windows keys pressed anymore - clear the state flags. */
2220 kbdhook.suppress_lone = 0;
2221 kbdhook.winseen = 0;
2222 }
2223 if (!kbdhook.send_win_up)
2224 {
2225 /* Swallow this release message, as not to confuse
2226 applications who did not get to see the original
2227 WM_KEYDOWN message either. */
2228 return 1;
2229 }
2230 kbdhook.send_win_up = 0;
2231 }
2232 }
2233 else if (kbdhook.winsdown > 0)
2234 {
2235 /* Some other key was pressed while a captured Win key is down.
2236 This is either an Emacs registered hotkey combination, or a
2237 system hotkey. */
2238 if (kbdhook.lwindown && kbdhook.lwin_hooked[hs->vkCode] ||
2239 kbdhook.rwindown && kbdhook.rwin_hooked[hs->vkCode])
2240 {
2241 /* Hooked Win-x combination, do not pass the keypress to Windows. */
2242 kbdhook.suppress_lone = 1;
2243 }
2244 else if (!kbdhook.suppress_lone)
2245 {
2246 /* Unhooked S-x combination; simulate the combination now
2247 (will be seen by the system). */
2248 memset (inputs, 0, sizeof (inputs));
2249 inputs[0].type = INPUT_KEYBOARD;
2250 inputs[0].ki.wVk = kbdhook.lwindown ? VK_LWIN : VK_RWIN;
2251 inputs[0].ki.wScan = kbdhook.lwindown ? VK_LWIN : VK_RWIN;
2252 inputs[0].ki.dwFlags = KEYEVENTF_EXTENDEDKEY;
2253 inputs[0].ki.time = 0;
2254 inputs[1].type = INPUT_KEYBOARD;
2255 inputs[1].ki.wVk = hs->vkCode;
2256 inputs[1].ki.wScan = hs->scanCode;
2257 inputs[1].ki.dwFlags =
2258 (hs->flags & LLKHF_EXTENDED) ? KEYEVENTF_EXTENDEDKEY : 0;
2259 inputs[1].ki.time = 0;
2260 SendInput (2, inputs, sizeof (INPUT));
2261 /* Stop processing of this Win sequence here; the
2262 corresponding keyup messages will come through the normal
2263 channel when the keys are released. */
2264 kbdhook.suppress_lone = 1;
2265 kbdhook.send_win_up = 1;
2266 /* Swallow the original keypress (as we want the Win key
2267 down message simulated above to precede this real message). */
2268 return 1;
2269 }
2270 }
2271
2272 /* Next, handle the registered Alt-* combinations. */
2273 if ((w == WM_SYSKEYDOWN || w == WM_KEYDOWN)
2274 && kbdhook.alt_hooked[hs->vkCode]
2275 && focus != NULL
2276 && (GetAsyncKeyState (VK_MENU) & 0x8000))
2277 {
2278 /* Prevent the system from getting this Alt-* key - suppress the
2279 message and post as a normal keypress to Emacs. */
2280 if (console)
2281 {
2282 INPUT_RECORD rec;
2283 DWORD n;
2284 rec.EventType = KEY_EVENT;
2285 rec.Event.KeyEvent.bKeyDown = TRUE;
2286 rec.Event.KeyEvent.wVirtualKeyCode = hs->vkCode;
2287 rec.Event.KeyEvent.wVirtualScanCode = hs->scanCode;
2288 rec.Event.KeyEvent.uChar.UnicodeChar = 0;
2289 rec.Event.KeyEvent.dwControlKeyState =
2290 ((GetAsyncKeyState (VK_LMENU) & 0x8000) ? LEFT_ALT_PRESSED : 0)
2291 | ((GetAsyncKeyState (VK_RMENU) & 0x8000) ? RIGHT_ALT_PRESSED : 0)
2292 | ((GetAsyncKeyState (VK_LCONTROL) & 0x8000) ? LEFT_CTRL_PRESSED : 0)
2293 | ((GetAsyncKeyState (VK_RCONTROL) & 0x8000) ? RIGHT_CTRL_PRESSED : 0)
2294 | ((GetAsyncKeyState (VK_SHIFT) & 0x8000) ? SHIFT_PRESSED : 0)
2295 | ((hs->flags & LLKHF_EXTENDED) ? ENHANCED_KEY : 0);
2296 if (w32_console_unicode_input)
2297 WriteConsoleInputW (keyboard_handle, &rec, 1, &n);
2298 else
2299 WriteConsoleInputA (keyboard_handle, &rec, 1, &n);
2300 }
2301 else
2302 PostMessage (focus, w, hs->vkCode, 1 | (1<<29));
2303 return 1;
2304 }
2305
2306 /* The normal case - pass the message through. */
2307 return CallNextHookEx (0, code, w, l);
2308}
2309
2310/* Set up the hook; can be called several times, with matching
2311 remove_w32_kbdhook calls. */
2312void
2313setup_w32_kbdhook (void)
2314{
2315 kbdhook.hook_count++;
2316
2317 /* Hooking is only available on NT architecture systems, as
2318 indicated by the w32_kbdhook_active variable. */
2319 if (kbdhook.hook_count == 1 && w32_kbdhook_active)
2320 {
2321 /* Get the handle of the Emacs console window. As the
2322 GetConsoleWindow function is only available on Win2000+, a
2323 hackish workaround described in Microsoft KB article 124103
2324 (https://support.microsoft.com/en-us/kb/124103) is used for
2325 NT 4 systems. */
2326 GetConsoleWindow_Proc get_console = (GetConsoleWindow_Proc)
2327 GetProcAddress (GetModuleHandle ("kernel32.dll"), "GetConsoleWindow");
2328
2329 if (get_console != NULL)
2330 kbdhook.console = get_console ();
2331 else
2332 {
2333 GUID guid;
2334 wchar_t *oldTitle = malloc (1024 * sizeof(wchar_t));
2335 wchar_t newTitle[64];
2336 int i;
2337
2338 CoCreateGuid (&guid);
2339 StringFromGUID2 (&guid, newTitle, 64);
2340 if (newTitle != NULL)
2341 {
2342 GetConsoleTitleW (oldTitle, 1024);
2343 SetConsoleTitleW (newTitle);
2344 for (i = 0; i < 25; i++)
2345 {
2346 Sleep (40);
2347 kbdhook.console = FindWindowW (NULL, newTitle);
2348 if (kbdhook.console != NULL)
2349 break;
2350 }
2351 SetConsoleTitleW (oldTitle);
2352 }
2353 free (oldTitle);
2354 }
2355
2356 /* Set the hook. */
2357 kbdhook.hook = SetWindowsHookEx (WH_KEYBOARD_LL, funhook,
2358 GetModuleHandle (NULL), 0);
2359 }
2360}
2361
2362/* Remove the hook. */
2363void
2364remove_w32_kbdhook (void)
2365{
2366 kbdhook.hook_count--;
2367 if (kbdhook.hook_count == 0 && w32_kbdhook_active)
2368 {
2369 UnhookWindowsHookEx (kbdhook.hook);
2370 kbdhook.hook = NULL;
2371 }
2372}
2373
2374/* Mark a specific key combination as hooked, preventing it to be
2375 handled by the system. */
2376void
2377hook_w32_key (int hook, int modifier, int vkey)
2378{
2379 char *tbl = NULL;
2380
2381 switch (modifier)
2382 {
2383 case VK_MENU:
2384 tbl = kbdhook.alt_hooked;
2385 break;
2386 case VK_LWIN:
2387 tbl = kbdhook.lwin_hooked;
2388 break;
2389 case VK_RWIN:
2390 tbl = kbdhook.rwin_hooked;
2391 break;
2392 }
2393
2394 if (tbl != NULL && vkey >= 0 && vkey <= 255)
2395 {
2396 /* VK_ANY hooks all keys for this modifier */
2397 if (vkey == VK_ANY)
2398 memset (tbl, (char)hook, 256);
2399 else
2400 tbl[vkey] = (char)hook;
2401 /* Alt-<modifier>s should go through */
2402 kbdhook.alt_hooked[VK_MENU] = 0;
2403 kbdhook.alt_hooked[VK_LMENU] = 0;
2404 kbdhook.alt_hooked[VK_RMENU] = 0;
2405 kbdhook.alt_hooked[VK_CONTROL] = 0;
2406 kbdhook.alt_hooked[VK_LCONTROL] = 0;
2407 kbdhook.alt_hooked[VK_RCONTROL] = 0;
2408 kbdhook.alt_hooked[VK_SHIFT] = 0;
2409 kbdhook.alt_hooked[VK_LSHIFT] = 0;
2410 kbdhook.alt_hooked[VK_RSHIFT] = 0;
2411 }
2412}
2413
2414/* Check the current Win key pressed state. */
2415int
2416check_w32_winkey_state (int vkey)
2417{
2418 /* The hook code handles grabbing of the Windows keys and Alt-* key
2419 combinations reserved by the system. Handling Alt is a bit
2420 easier, as Windows intends Alt-* shortcuts for application use in
2421 Windows; hotkeys such as Alt-tab and Alt-escape are special
2422 cases. Win-* hotkeys, on the other hand, are primarily meant for
2423 system use.
2424
2425 As a result, when we want Emacs to be able to grab the Win-*
2426 keys, we must swallow all Win key presses in a low-level keyboard
2427 hook. Unfortunately, this means that the Emacs window procedure
2428 (and console input handler) never see the keypresses either.
2429 Thus, to check the modifier states properly, Emacs code must use
2430 the check_w32_winkey_state function that uses the flags directly
2431 updated by the hook callback. */
2432 switch (vkey)
2433 {
2434 case VK_LWIN:
2435 return kbdhook.lwindown;
2436 case VK_RWIN:
2437 return kbdhook.rwindown;
2438 }
2439 return 0;
2440}
2441
2442/* Reset the keyboard hook state. Locking the workstation with Win-L
2443 leaves the Win key(s) "down" from the hook's point of view - the
2444 keyup event is never seen. Thus, this function must be called when
2445 the system is locked. */
2446void
2447reset_w32_kbdhook_state (void)
2448{
2449 kbdhook.lwindown = 0;
2450 kbdhook.rwindown = 0;
2451 kbdhook.winsdown = 0;
2452 kbdhook.send_win_up = 0;
2453 kbdhook.suppress_lone = 0;
2454 kbdhook.winseen = 0;
2455}
2456
2077/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish 2457/* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
2078 between left and right keys as advertised. We test for this 2458 between left and right keys as advertised. We test for this
2079 support dynamically, and set a flag when the support is absent. If 2459 support dynamically, and set a flag when the support is absent. If
@@ -2248,6 +2628,8 @@ modifier_set (int vkey)
2248 else 2628 else
2249 return (GetKeyState (vkey) & 0x1); 2629 return (GetKeyState (vkey) & 0x1);
2250 } 2630 }
2631 if (w32_kbdhook_active && (vkey == VK_LWIN || vkey == VK_RWIN))
2632 return check_w32_winkey_state (vkey);
2251 2633
2252 if (!modifiers_recorded) 2634 if (!modifiers_recorded)
2253 return (GetKeyState (vkey) & 0x8000); 2635 return (GetKeyState (vkey) & 0x8000);
@@ -2390,7 +2772,9 @@ map_keypad_keys (unsigned int virt_key, unsigned int extended)
2390/* List of special key combinations which w32 would normally capture, 2772/* List of special key combinations which w32 would normally capture,
2391 but Emacs should grab instead. Not directly visible to lisp, to 2773 but Emacs should grab instead. Not directly visible to lisp, to
2392 simplify synchronization. Each item is an integer encoding a virtual 2774 simplify synchronization. Each item is an integer encoding a virtual
2393 key code and modifier combination to capture. */ 2775 key code and modifier combination to capture.
2776 Note: This code is not used if keyboard hooks are active
2777 (Windows 2000 and later). */
2394static Lisp_Object w32_grabbed_keys; 2778static Lisp_Object w32_grabbed_keys;
2395 2779
2396#define HOTKEY(vk, mods) make_number (((vk) & 255) | ((mods) << 8)) 2780#define HOTKEY(vk, mods) make_number (((vk) & 255) | ((mods) << 8))
@@ -3440,7 +3824,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
3440 switch (wParam) 3824 switch (wParam)
3441 { 3825 {
3442 case VK_LWIN: 3826 case VK_LWIN:
3443 if (NILP (Vw32_pass_lwindow_to_system)) 3827 if (!w32_kbdhook_active && NILP (Vw32_pass_lwindow_to_system))
3444 { 3828 {
3445 /* Prevent system from acting on keyup (which opens the 3829 /* Prevent system from acting on keyup (which opens the
3446 Start menu if no other key was pressed) by simulating a 3830 Start menu if no other key was pressed) by simulating a
@@ -3459,7 +3843,7 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
3459 return 0; 3843 return 0;
3460 break; 3844 break;
3461 case VK_RWIN: 3845 case VK_RWIN:
3462 if (NILP (Vw32_pass_rwindow_to_system)) 3846 if (!w32_kbdhook_active && NILP (Vw32_pass_rwindow_to_system))
3463 { 3847 {
3464 if (GetAsyncKeyState (wParam) & 1) 3848 if (GetAsyncKeyState (wParam) & 1)
3465 { 3849 {
@@ -4316,10 +4700,12 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4316 case WM_SETFOCUS: 4700 case WM_SETFOCUS:
4317 dpyinfo->faked_key = 0; 4701 dpyinfo->faked_key = 0;
4318 reset_modifiers (); 4702 reset_modifiers ();
4319 register_hot_keys (hwnd); 4703 if (!w32_kbdhook_active)
4704 register_hot_keys (hwnd);
4320 goto command; 4705 goto command;
4321 case WM_KILLFOCUS: 4706 case WM_KILLFOCUS:
4322 unregister_hot_keys (hwnd); 4707 if (!w32_kbdhook_active)
4708 unregister_hot_keys (hwnd);
4323 button_state = 0; 4709 button_state = 0;
4324 ReleaseCapture (); 4710 ReleaseCapture ();
4325 /* Relinquish the system caret. */ 4711 /* Relinquish the system caret. */
@@ -4348,10 +4734,20 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4348 my_post_msg (&wmsg, hwnd, msg, wParam, lParam); 4734 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4349 goto dflt; 4735 goto dflt;
4350 4736
4737 case WM_CREATE:
4738 setup_w32_kbdhook ();
4739 goto dflt;
4740
4351 case WM_DESTROY: 4741 case WM_DESTROY:
4742 remove_w32_kbdhook ();
4352 CoUninitialize (); 4743 CoUninitialize ();
4353 return 0; 4744 return 0;
4354 4745
4746 case WM_WTSSESSION_CHANGE:
4747 if (wParam == WTS_SESSION_LOCK)
4748 reset_w32_kbdhook_state ();
4749 goto dflt;
4750
4355 case WM_CLOSE: 4751 case WM_CLOSE:
4356 wmsg.dwModifiers = w32_get_modifiers (); 4752 wmsg.dwModifiers = w32_get_modifiers ();
4357 my_post_msg (&wmsg, hwnd, msg, wParam, lParam); 4753 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
@@ -7617,19 +8013,34 @@ lookup_vk_code (char *key)
7617 && strcmp (lispy_function_keys[i], key) == 0) 8013 && strcmp (lispy_function_keys[i], key) == 0)
7618 return i; 8014 return i;
7619 8015
8016 if (w32_kbdhook_active)
8017 {
8018 /* Alphanumerics map to themselves. */
8019 if (key[1] == 0)
8020 {
8021 if (key[0] >= 'A' && key[0] <= 'Z' ||
8022 key[0] >= '0' && key[0] <= '9')
8023 return key[0];
8024 if (key[0] >= 'a' && key[0] <= 'z')
8025 return toupper(key[0]);
8026 }
8027 }
8028
7620 return -1; 8029 return -1;
7621} 8030}
7622 8031
7623/* Convert a one-element vector style key sequence to a hot key 8032/* Convert a one-element vector style key sequence to a hot key
7624 definition. */ 8033 definition. */
7625static Lisp_Object 8034static Lisp_Object
7626w32_parse_hot_key (Lisp_Object key) 8035w32_parse_and_hook_hot_key (Lisp_Object key, int hook)
7627{ 8036{
7628 /* Copied from Fdefine_key and store_in_keymap. */ 8037 /* Copied from Fdefine_key and store_in_keymap. */
7629 register Lisp_Object c; 8038 register Lisp_Object c;
7630 int vk_code; 8039 int vk_code;
7631 int lisp_modifiers; 8040 int lisp_modifiers;
7632 int w32_modifiers; 8041 int w32_modifiers;
8042 Lisp_Object res = Qnil;
8043 char* vkname;
7633 8044
7634 CHECK_VECTOR (key); 8045 CHECK_VECTOR (key);
7635 8046
@@ -7652,7 +8063,12 @@ w32_parse_hot_key (Lisp_Object key)
7652 c = Fcar (c); 8063 c = Fcar (c);
7653 if (!SYMBOLP (c)) 8064 if (!SYMBOLP (c))
7654 emacs_abort (); 8065 emacs_abort ();
7655 vk_code = lookup_vk_code (SSDATA (SYMBOL_NAME (c))); 8066 vkname = SSDATA (SYMBOL_NAME (c));
8067 /* [s-], [M-], [h-]: Register all keys for this modifier */
8068 if (w32_kbdhook_active && vkname[0] == 0)
8069 vk_code = VK_ANY;
8070 else
8071 vk_code = lookup_vk_code (vkname);
7656 } 8072 }
7657 else if (INTEGERP (c)) 8073 else if (INTEGERP (c))
7658 { 8074 {
@@ -7676,34 +8092,75 @@ w32_parse_hot_key (Lisp_Object key)
7676#define MOD_WIN 0x0008 8092#define MOD_WIN 0x0008
7677#endif 8093#endif
7678 8094
7679 /* Convert lisp modifiers to Windows hot-key form. */ 8095 if (w32_kbdhook_active)
7680 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0; 8096 {
7681 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0; 8097 /* Register Alt-x combinations. */
7682 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0; 8098 if (lisp_modifiers & alt_modifier)
7683 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0; 8099 {
8100 hook_w32_key (hook, VK_MENU, vk_code);
8101 res = Qt;
8102 }
8103 /* Register Win-x combinations based on modifier mappings. */
8104 if (((lisp_modifiers & hyper_modifier)
8105 && EQ (Vw32_lwindow_modifier, Qhyper))
8106 || ((lisp_modifiers & super_modifier)
8107 && EQ (Vw32_lwindow_modifier, Qsuper)))
8108 {
8109 hook_w32_key (hook, VK_LWIN, vk_code);
8110 res = Qt;
8111 }
8112 if (((lisp_modifiers & hyper_modifier)
8113 && EQ (Vw32_rwindow_modifier, Qhyper))
8114 || ((lisp_modifiers & super_modifier)
8115 && EQ (Vw32_rwindow_modifier, Qsuper)))
8116 {
8117 hook_w32_key (hook, VK_RWIN, vk_code);
8118 res = Qt;
8119 }
8120 return res;
8121 }
8122 else
8123 {
8124 /* Convert lisp modifiers to Windows hot-key form. */
8125 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
8126 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
8127 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
8128 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
7684 8129
7685 return HOTKEY (vk_code, w32_modifiers); 8130 return HOTKEY (vk_code, w32_modifiers);
8131 }
7686} 8132}
7687 8133
7688DEFUN ("w32-register-hot-key", Fw32_register_hot_key, 8134DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
7689 Sw32_register_hot_key, 1, 1, 0, 8135 Sw32_register_hot_key, 1, 1, 0,
7690 doc: /* Register KEY as a hot-key combination. 8136 doc: /* Register KEY as a hot-key combination.
7691Certain key combinations like Alt-Tab are reserved for system use on 8137Certain key combinations like Alt-Tab and Win-R are reserved for
7692Windows, and therefore are normally intercepted by the system. However, 8138system use on Windows, and therefore are normally intercepted by the
7693most of these key combinations can be received by registering them as 8139system. These key combinations can be received by registering them
7694hot-keys, overriding their special meaning. 8140as hot-keys, except for Win-L which always locks the computer.
7695 8141
7696KEY must be a one element key definition in vector form that would be 8142On Windows 98 and ME, KEY must be a one element key definition in
7697acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta 8143vector form that would be acceptable to `define-key' (e.g. [A-tab] for
7698modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper 8144Alt-Tab). The meta modifier is interpreted as Alt if
7699is always interpreted as the Windows modifier keys. 8145`w32-alt-is-meta' is t, and hyper is always interpreted as the Windows
7700 8146modifier keys. The return value is the hotkey-id if registered, otherwise nil.
7701The return value is the hotkey-id if registered, otherwise nil. */) 8147
8148On Windows versions since NT, KEY can also be specified as [M-], [s-] or
8149[h-] to indicate that all combinations of that key should be processed
8150by Emacs instead of the operating system. The super and hyper
8151modifiers are interpreted according to the current values of
8152`w32-lwindow-modifier' and `w32-rwindow-modifier'. For instance,
8153setting `w32-lwindow-modifier' to `super' and then calling
8154`(register-hot-key [s-])' grabs all combinations of the left Windows
8155key to Emacs, but leaves the right Windows key free for the operating
8156system keyboard shortcuts. The return value is t if the call affected
8157any key combinations, otherwise nil. */)
7702 (Lisp_Object key) 8158 (Lisp_Object key)
7703{ 8159{
7704 key = w32_parse_hot_key (key); 8160 key = w32_parse_and_hook_hot_key (key, 1);
7705 8161
7706 if (!NILP (key) && NILP (Fmemq (key, w32_grabbed_keys))) 8162 if (!w32_kbdhook_active
8163 && !NILP (key) && NILP (Fmemq (key, w32_grabbed_keys)))
7707 { 8164 {
7708 /* Reuse an empty slot if possible. */ 8165 /* Reuse an empty slot if possible. */
7709 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys); 8166 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
@@ -7731,7 +8188,10 @@ DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
7731 Lisp_Object item; 8188 Lisp_Object item;
7732 8189
7733 if (!INTEGERP (key)) 8190 if (!INTEGERP (key))
7734 key = w32_parse_hot_key (key); 8191 key = w32_parse_and_hook_hot_key (key, 0);
8192
8193 if (w32_kbdhook_active)
8194 return key;
7735 8195
7736 item = Fmemq (key, w32_grabbed_keys); 8196 item = Fmemq (key, w32_grabbed_keys);
7737 8197
@@ -9338,11 +9798,15 @@ When non-nil, the Start menu is opened by tapping the key.
9338If you set this to nil, the left \"Windows\" key is processed by Emacs 9798If you set this to nil, the left \"Windows\" key is processed by Emacs
9339according to the value of `w32-lwindow-modifier', which see. 9799according to the value of `w32-lwindow-modifier', which see.
9340 9800
9341Note that some combinations of the left \"Windows\" key with other keys are 9801Note that some combinations of the left \"Windows\" key with other
9342caught by Windows at low level, and so binding them in Emacs will have no 9802keys are caught by Windows at low level. For example, <lwindow>-r
9343effect. For example, <lwindow>-r always pops up the Windows Run dialog, 9803pops up the Windows Run dialog, <lwindow>-<Pause> pops up the "System
9344<lwindow>-<Pause> pops up the "System Properties" dialog, etc. However, see 9804Properties" dialog, etc. On Windows 10, no \"Windows\" key
9345the doc string of `w32-phantom-key-code'. */); 9805combinations are normally handed to applications. To enable Emacs to
9806process \"Windows\" key combinations, use the function
9807`w32-register-hot-key`.
9808
9809For Windows 98/ME, see the doc string of `w32-phantom-key-code'. */);
9346 Vw32_pass_lwindow_to_system = Qt; 9810 Vw32_pass_lwindow_to_system = Qt;
9347 9811
9348 DEFVAR_LISP ("w32-pass-rwindow-to-system", 9812 DEFVAR_LISP ("w32-pass-rwindow-to-system",
@@ -9353,11 +9817,15 @@ When non-nil, the Start menu is opened by tapping the key.
9353If you set this to nil, the right \"Windows\" key is processed by Emacs 9817If you set this to nil, the right \"Windows\" key is processed by Emacs
9354according to the value of `w32-rwindow-modifier', which see. 9818according to the value of `w32-rwindow-modifier', which see.
9355 9819
9356Note that some combinations of the right \"Windows\" key with other keys are 9820Note that some combinations of the right \"Windows\" key with other
9357caught by Windows at low level, and so binding them in Emacs will have no 9821keys are caught by Windows at low level. For example, <rwindow>-r
9358effect. For example, <rwindow>-r always pops up the Windows Run dialog, 9822pops up the Windows Run dialog, <rwindow>-<Pause> pops up the "System
9359<rwindow>-<Pause> pops up the "System Properties" dialog, etc. However, see 9823Properties" dialog, etc. On Windows 10, no \"Windows\" key
9360the doc string of `w32-phantom-key-code'. */); 9824combinations are normally handed to applications. To enable Emacs to
9825process \"Windows\" key combinations, use the function
9826`w32-register-hot-key`.
9827
9828For Windows 98/ME, see the doc string of `w32-phantom-key-code'. */);
9361 Vw32_pass_rwindow_to_system = Qt; 9829 Vw32_pass_rwindow_to_system = Qt;
9362 9830
9363 DEFVAR_LISP ("w32-phantom-key-code", 9831 DEFVAR_LISP ("w32-phantom-key-code",
@@ -9367,7 +9835,11 @@ Value is a number between 0 and 255.
9367 9835
9368Phantom key presses are generated in order to stop the system from 9836Phantom key presses are generated in order to stop the system from
9369acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or 9837acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
9370`w32-pass-rwindow-to-system' is nil. */); 9838`w32-pass-rwindow-to-system' is nil.
9839
9840This variable is only used on Windows 98 and ME. For other Windows
9841versions, see the documentation of the `w32-register-hot-key`
9842function. */);
9371 /* Although 255 is technically not a valid key code, it works and 9843 /* Although 255 is technically not a valid key code, it works and
9372 means that this hack won't interfere with any real key code. */ 9844 means that this hack won't interfere with any real key code. */
9373 XSETINT (Vw32_phantom_key_code, 255); 9845 XSETINT (Vw32_phantom_key_code, 255);
@@ -9397,7 +9869,9 @@ Any other value will cause the Scroll Lock key to be ignored. */);
9397 doc: /* Modifier to use for the left \"Windows\" key. 9869 doc: /* Modifier to use for the left \"Windows\" key.
9398The value can be hyper, super, meta, alt, control or shift for the 9870The value can be hyper, super, meta, alt, control or shift for the
9399respective modifier, or nil to appear as the `lwindow' key. 9871respective modifier, or nil to appear as the `lwindow' key.
9400Any other value will cause the key to be ignored. */); 9872Any other value will cause the key to be ignored.
9873
9874Also see the documentation of the `w32-register-hot-key` function. */);
9401 Vw32_lwindow_modifier = Qnil; 9875 Vw32_lwindow_modifier = Qnil;
9402 9876
9403 DEFVAR_LISP ("w32-rwindow-modifier", 9877 DEFVAR_LISP ("w32-rwindow-modifier",
@@ -9405,7 +9879,9 @@ Any other value will cause the key to be ignored. */);
9405 doc: /* Modifier to use for the right \"Windows\" key. 9879 doc: /* Modifier to use for the right \"Windows\" key.
9406The value can be hyper, super, meta, alt, control or shift for the 9880The value can be hyper, super, meta, alt, control or shift for the
9407respective modifier, or nil to appear as the `rwindow' key. 9881respective modifier, or nil to appear as the `rwindow' key.
9408Any other value will cause the key to be ignored. */); 9882Any other value will cause the key to be ignored.
9883
9884Also see the documentation of the `w32-register-hot-key` function. */);
9409 Vw32_rwindow_modifier = Qnil; 9885 Vw32_rwindow_modifier = Qnil;
9410 9886
9411 DEFVAR_LISP ("w32-apps-modifier", 9887 DEFVAR_LISP ("w32-apps-modifier",
diff --git a/src/w32inevt.c b/src/w32inevt.c
index e714e27f4bc..c7246c7a8e2 100644
--- a/src/w32inevt.c
+++ b/src/w32inevt.c
@@ -41,6 +41,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
41#include "termchar.h" /* for Mouse_HLInfo, tty_display_info */ 41#include "termchar.h" /* for Mouse_HLInfo, tty_display_info */
42#include "w32term.h" 42#include "w32term.h"
43#include "w32inevt.h" 43#include "w32inevt.h"
44#include "w32common.h"
44 45
45/* stdin, from w32console.c */ 46/* stdin, from w32console.c */
46extern HANDLE keyboard_handle; 47extern HANDLE keyboard_handle;
@@ -148,10 +149,12 @@ key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
148 switch (event->wVirtualKeyCode) 149 switch (event->wVirtualKeyCode)
149 { 150 {
150 case VK_LWIN: 151 case VK_LWIN:
151 mod_key_state &= ~LEFT_WIN_PRESSED; 152 if (!w32_kbdhook_active)
153 mod_key_state &= ~LEFT_WIN_PRESSED;
152 break; 154 break;
153 case VK_RWIN: 155 case VK_RWIN:
154 mod_key_state &= ~RIGHT_WIN_PRESSED; 156 if (!w32_kbdhook_active)
157 mod_key_state &= ~RIGHT_WIN_PRESSED;
155 break; 158 break;
156 case VK_APPS: 159 case VK_APPS:
157 mod_key_state &= ~APPS_PRESSED; 160 mod_key_state &= ~APPS_PRESSED;
@@ -185,7 +188,8 @@ key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
185 keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0); 188 keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0);
186 } 189 }
187 } 190 }
188 mod_key_state |= LEFT_WIN_PRESSED; 191 if (!w32_kbdhook_active)
192 mod_key_state |= LEFT_WIN_PRESSED;
189 if (!NILP (Vw32_lwindow_modifier)) 193 if (!NILP (Vw32_lwindow_modifier))
190 return 0; 194 return 0;
191 break; 195 break;
@@ -201,7 +205,8 @@ key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
201 keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0); 205 keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0);
202 } 206 }
203 } 207 }
204 mod_key_state |= RIGHT_WIN_PRESSED; 208 if (!w32_kbdhook_active)
209 mod_key_state |= RIGHT_WIN_PRESSED;
205 if (!NILP (Vw32_rwindow_modifier)) 210 if (!NILP (Vw32_rwindow_modifier))
206 return 0; 211 return 0;
207 break; 212 break;
@@ -267,6 +272,13 @@ key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
267 272
268 /* Recognize state of Windows and Apps keys. */ 273 /* Recognize state of Windows and Apps keys. */
269 event->dwControlKeyState |= mod_key_state; 274 event->dwControlKeyState |= mod_key_state;
275 if (w32_kbdhook_active)
276 {
277 if (check_w32_winkey_state (VK_LWIN))
278 event->dwControlKeyState |= LEFT_WIN_PRESSED;
279 if (check_w32_winkey_state (VK_RWIN))
280 event->dwControlKeyState |= RIGHT_WIN_PRESSED;
281 }
270 282
271 /* Distinguish numeric keypad keys from extended keys. */ 283 /* Distinguish numeric keypad keys from extended keys. */
272 event->wVirtualKeyCode = 284 event->wVirtualKeyCode =
diff --git a/src/w32term.h b/src/w32term.h
index 50906241f98..aed89d8c254 100644
--- a/src/w32term.h
+++ b/src/w32term.h
@@ -738,6 +738,12 @@ extern int handle_file_notifications (struct input_event *);
738extern void w32_initialize_display_info (Lisp_Object); 738extern void w32_initialize_display_info (Lisp_Object);
739extern void initialize_w32_display (struct terminal *, int *, int *); 739extern void initialize_w32_display (struct terminal *, int *, int *);
740 740
741/* Keyboard hooks. */
742extern void setup_w32_kbdhook (void);
743extern void remove_w32_kbdhook (void);
744extern int check_w32_winkey_state (int);
745#define w32_kbdhook_active (os_subtype != OS_9X)
746
741/* Keypad command key support. W32 doesn't have virtual keys defined 747/* Keypad command key support. W32 doesn't have virtual keys defined
742 for the function keys on the keypad (they are mapped to the standard 748 for the function keys on the keypad (they are mapped to the standard
743 function keys), so we define our own. */ 749 function keys), so we define our own. */