aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGeoff Voelker1998-11-10 20:54:46 +0000
committerGeoff Voelker1998-11-10 20:54:46 +0000
commitccc2d29c56505a9a7fd38f7e582c16ee38f31b26 (patch)
tree77fa1adaf66dbe4a5187d0ad887a3abc88709673 /src
parentf791da1d45c76c873b09b20e7fe2b70e3d0bfd39 (diff)
downloademacs-ccc2d29c56505a9a7fd38f7e582c16ee38f31b26.tar.gz
emacs-ccc2d29c56505a9a7fd38f7e582c16ee38f31b26.zip
(Vw32_pass_optional_keys_to_system): Variable removed.
(Vw32_pass_lwindow_to_system): (Vw32_pass_rwindow_to_system): (Vw32_lwindow_modifier): (Vw32_rwindow_modifier): (Vw32_apps_modifier): (Vw32_enable_num_lock): (Vw32_enable_caps_lock): (Vw32_scroll_lock_modifier): New variables. (modifier_set): Return toggle state for Scroll Lock. (w32_key_to_modifier): New function. Returns chosen modifier bit for given key. (w32_get_modifiers): Returns modifier flags for non-keyboard input events. (construct_console_modifiers): Renamed from construct_modifiers; recognize Windows and Apps keys as modifiers. (w32_get_key_modifiers): New function. Returns modifier flags for keyboard input events. (map_keypad_keys): Make non-static. Use second arg as extended flag. (w32_grabbed_keys): New variable. (HOTKEY, HOTKEY_ID, HOTKEY_VK_CODE, HOTKEY_MODIFIERS): New macros. (register_hot_keys): (unregister_hot_keys): (lookup_vk_code): (w32_parse_hot_key): (Fw32_register_hot_key): (Fw32_unregister_hot_key): (Fw32_registered_hot_keys): (Fw32_reconstruct_hot_key): New functions to support hotkeys. (post_character_message): New function. (w32_msg_pump): Handle new messages for using hotkeys and changing keyboard layout/language. (w32_wnd_proc): Major rework of keyboard input handling: optionally recognize Windows keys and Apps key as modifiers; optionally treat NumLock, CapsLock and ScrollLock as function keys; let system translate keystrokes to characters to avoid system bugs relating to dead-key handling; preserve shift distinction for control characters; forward keyboard layout/language changes to lisp; detect and convert hot-key events to normal keystrokes. (syms_of_w32fns): Register new functions and variables. (w32_last_error): New function for use in debugging.
Diffstat (limited to 'src')
-rw-r--r--src/w32fns.c783
1 files changed, 680 insertions, 103 deletions
diff --git a/src/w32fns.c b/src/w32fns.c
index 2765c7bbb03..c11c3d5c841 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -50,6 +50,8 @@ extern void free_frame_menubar ();
50extern struct scroll_bar *x_window_to_scroll_bar (); 50extern struct scroll_bar *x_window_to_scroll_bar ();
51extern int quit_char; 51extern int quit_char;
52 52
53extern char *lispy_function_keys[];
54
53/* The colormap for converting color names to RGB values */ 55/* The colormap for converting color names to RGB values */
54Lisp_Object Vw32_color_map; 56Lisp_Object Vw32_color_map;
55 57
@@ -60,9 +62,34 @@ Lisp_Object Vw32_pass_alt_to_system;
60 to alt_modifier. */ 62 to alt_modifier. */
61Lisp_Object Vw32_alt_is_meta; 63Lisp_Object Vw32_alt_is_meta;
62 64
63/* Non nil if left window, right window, and application key events 65/* Non nil if left window key events are passed on to Windows (this only
64 are passed on to Windows. */ 66 affects whether "tapping" the key opens the Start menu). */
65Lisp_Object Vw32_pass_optional_keys_to_system; 67Lisp_Object Vw32_pass_lwindow_to_system;
68
69/* Non nil if right window key events are passed on to Windows (this
70 only affects whether "tapping" the key opens the Start menu). */
71Lisp_Object Vw32_pass_rwindow_to_system;
72
73/* Modifier associated with the left "Windows" key, or nil to act as a
74 normal key. */
75Lisp_Object Vw32_lwindow_modifier;
76
77/* Modifier associated with the right "Windows" key, or nil to act as a
78 normal key. */
79Lisp_Object Vw32_rwindow_modifier;
80
81/* Modifier associated with the "Apps" key, or nil to act as a normal
82 key. */
83Lisp_Object Vw32_apps_modifier;
84
85/* Value is nil if Num Lock acts as a function key. */
86Lisp_Object Vw32_enable_num_lock;
87
88/* Value is nil if Caps Lock acts as a function key. */
89Lisp_Object Vw32_enable_caps_lock;
90
91/* Modifier associated with Scroll Lock, or nil to act as a normal key. */
92Lisp_Object Vw32_scroll_lock_modifier;
66 93
67/* Switch to control whether we inhibit requests for italicised fonts (which 94/* Switch to control whether we inhibit requests for italicised fonts (which
68 are synthesized, look ugly, and are trashed by cursor movement under NT). */ 95 are synthesized, look ugly, and are trashed by cursor movement under NT). */
@@ -205,6 +232,7 @@ extern int last_mouse_scroll_bar_pos;
205 232
206/* From w32term.c. */ 233/* From w32term.c. */
207extern Lisp_Object Vw32_num_mouse_buttons; 234extern Lisp_Object Vw32_num_mouse_buttons;
235extern Lisp_Object Vw32_recognize_altgr;
208 236
209 237
210/* Error if we are not connected to MS-Windows. */ 238/* Error if we are not connected to MS-Windows. */
@@ -2959,17 +2987,6 @@ w32_createwindow (f)
2959 } 2987 }
2960} 2988}
2961 2989
2962/* Convert between the modifier bits W32 uses and the modifier bits
2963 Emacs uses. */
2964unsigned int
2965w32_get_modifiers ()
2966{
2967 return (((GetKeyState (VK_SHIFT)&0x8000) ? shift_modifier : 0) |
2968 ((GetKeyState (VK_CONTROL)&0x8000) ? ctrl_modifier : 0) |
2969 ((GetKeyState (VK_MENU)&0x8000) ?
2970 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
2971}
2972
2973void 2990void
2974my_post_msg (wmsg, hwnd, msg, wParam, lParam) 2991my_post_msg (wmsg, hwnd, msg, wParam, lParam)
2975 W32Msg * wmsg; 2992 W32Msg * wmsg;
@@ -3116,7 +3133,7 @@ sync_modifiers ()
3116static int 3133static int
3117modifier_set (int vkey) 3134modifier_set (int vkey)
3118{ 3135{
3119 if (vkey == VK_CAPITAL) 3136 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
3120 return (GetKeyState (vkey) & 0x1); 3137 return (GetKeyState (vkey) & 0x1);
3121 if (!modifiers_recorded) 3138 if (!modifiers_recorded)
3122 return (GetKeyState (vkey) & 0x8000); 3139 return (GetKeyState (vkey) & 0x8000);
@@ -3131,56 +3148,215 @@ modifier_set (int vkey)
3131 return modifiers[EMACS_LMENU]; 3148 return modifiers[EMACS_LMENU];
3132 case VK_RMENU: 3149 case VK_RMENU:
3133 return modifiers[EMACS_RMENU]; 3150 return modifiers[EMACS_RMENU];
3134 default:
3135 break;
3136 } 3151 }
3137 return (GetKeyState (vkey) & 0x8000); 3152 return (GetKeyState (vkey) & 0x8000);
3138} 3153}
3139 3154
3155/* Convert between the modifier bits W32 uses and the modifier bits
3156 Emacs uses. */
3157
3158unsigned int
3159w32_key_to_modifier (int key)
3160{
3161 Lisp_Object key_mapping;
3162
3163 switch (key)
3164 {
3165 case VK_LWIN:
3166 key_mapping = Vw32_lwindow_modifier;
3167 break;
3168 case VK_RWIN:
3169 key_mapping = Vw32_rwindow_modifier;
3170 break;
3171 case VK_APPS:
3172 key_mapping = Vw32_apps_modifier;
3173 break;
3174 case VK_SCROLL:
3175 key_mapping = Vw32_scroll_lock_modifier;
3176 break;
3177 default:
3178 key_mapping = Qnil;
3179 }
3180
3181 if (EQ (key_mapping, intern ("hyper")))
3182 return hyper_modifier;
3183 if (EQ (key_mapping, intern ("super")))
3184 return super_modifier;
3185 if (EQ (key_mapping, intern ("meta")))
3186 return meta_modifier;
3187 if (EQ (key_mapping, intern ("alt")))
3188 return alt_modifier;
3189 if (EQ (key_mapping, intern ("ctrl")))
3190 return ctrl_modifier;
3191 if (EQ (key_mapping, intern ("control"))) /* synonym for ctrl */
3192 return ctrl_modifier;
3193 if (EQ (key_mapping, intern ("shift")))
3194 return shift_modifier;
3195
3196 /* Don't generate any modifier if not explicitly requested. */
3197 return 0;
3198}
3199
3200unsigned int
3201w32_get_modifiers ()
3202{
3203 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3204 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3205 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3206 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3207 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3208 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3209 (modifier_set (VK_MENU) ?
3210 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3211}
3212
3140/* We map the VK_* modifiers into console modifier constants 3213/* We map the VK_* modifiers into console modifier constants
3141 so that we can use the same routines to handle both console 3214 so that we can use the same routines to handle both console
3142 and window input. */ 3215 and window input. */
3143 3216
3144static int 3217static int
3145construct_modifiers (unsigned int wparam, unsigned int lparam) 3218construct_console_modifiers ()
3146{ 3219{
3147 int mods; 3220 int mods;
3148 3221
3149 if (wparam != VK_CONTROL && wparam != VK_MENU)
3150 mods = GetLastError ();
3151
3152 mods = 0; 3222 mods = 0;
3153 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0; 3223 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3154 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0; 3224 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
3225 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3226 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
3155 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0; 3227 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3156 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0; 3228 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3157 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0; 3229 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3158 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0; 3230 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
3231 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3232 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3233 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
3159 3234
3160 return mods; 3235 return mods;
3161} 3236}
3162 3237
3163static unsigned int 3238static int
3164map_keypad_keys (unsigned int wparam, unsigned int lparam) 3239w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
3165{ 3240{
3166 unsigned int extended = (lparam & 0x1000000L); 3241 int mods;
3242
3243 /* Convert to emacs modifiers. */
3244 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3245
3246 return mods;
3247}
3167 3248
3168 if (wparam < VK_CLEAR || wparam > VK_DELETE) 3249unsigned int
3169 return wparam; 3250map_keypad_keys (unsigned int virt_key, unsigned int extended)
3251{
3252 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3253 return virt_key;
3170 3254
3171 if (wparam == VK_RETURN) 3255 if (virt_key == VK_RETURN)
3172 return (extended ? VK_NUMPAD_ENTER : VK_RETURN); 3256 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3173 3257
3174 if (wparam >= VK_PRIOR && wparam <= VK_DOWN) 3258 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3175 return (!extended ? (VK_NUMPAD_PRIOR + (wparam - VK_PRIOR)) : wparam); 3259 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3260
3261 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3262 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3263
3264 if (virt_key == VK_CLEAR)
3265 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3266
3267 return virt_key;
3268}
3269
3270/* List of special key combinations which w32 would normally capture,
3271 but emacs should grab instead. Not directly visible to lisp, to
3272 simplify synchronization. Each item is an integer encoding a virtual
3273 key code and modifier combination to capture. */
3274Lisp_Object w32_grabbed_keys;
3275
3276#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3277#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3278#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3279#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3280
3281/* Register hot-keys for reserved key combinations when Emacs has
3282 keyboard focus, since this is the only way Emacs can receive key
3283 combinations like Alt-Tab which are used by the system. */
3284
3285static void
3286register_hot_keys (hwnd)
3287 HWND hwnd;
3288{
3289 Lisp_Object keylist;
3290
3291 /* Use GC_CONSP, since we are called asynchronously. */
3292 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3293 {
3294 Lisp_Object key = XCAR (keylist);
3295
3296 /* Deleted entries get set to nil. */
3297 if (!INTEGERP (key))
3298 continue;
3299
3300 RegisterHotKey (hwnd, HOTKEY_ID (key),
3301 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3302 }
3303}
3304
3305static void
3306unregister_hot_keys (hwnd)
3307 HWND hwnd;
3308{
3309 Lisp_Object keylist;
3310
3311 /* Use GC_CONSP, since we are called asynchronously. */
3312 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3313 {
3314 Lisp_Object key = XCAR (keylist);
3315
3316 if (!INTEGERP (key))
3317 continue;
3318
3319 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3320 }
3321}
3322
3323static void
3324post_character_message (hwnd, msg, wParam, lParam, modifiers)
3325 HWND hwnd;
3326 UINT msg;
3327 WPARAM wParam;
3328 LPARAM lParam;
3329 DWORD modifiers;
3330
3331{
3332 W32Msg wmsg;
3176 3333
3177 if (wparam == VK_INSERT || wparam == VK_DELETE) 3334 wmsg.dwModifiers = modifiers;
3178 return (!extended ? (VK_NUMPAD_INSERT + (wparam - VK_INSERT)) : wparam);
3179 3335
3180 if (wparam == VK_CLEAR) 3336 /* Detect quit_char and set quit-flag directly. Note that we
3181 return (!extended ? VK_NUMPAD_CLEAR : wparam); 3337 still need to post a message to ensure the main thread will be
3338 woken up if blocked in sys_select(), but we do NOT want to post
3339 the quit_char message itself (because it will usually be as if
3340 the user had typed quit_char twice). Instead, we post a dummy
3341 message that has no particular effect. */
3342 {
3343 int c = wParam;
3344 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
3345 c = make_ctrl_char (c) & 0377;
3346 if (c == quit_char)
3347 {
3348 Vquit_flag = Qt;
3349
3350 /* The choice of message is somewhat arbitrary, as long as
3351 the main thread handler just ignores it. */
3352 msg = WM_NULL;
3353
3354 /* Interrupt any blocking system calls. */
3355 signal_quit ();
3356 }
3357 }
3182 3358
3183 return wparam; 3359 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3184} 3360}
3185 3361
3186/* Main message dispatch loop. */ 3362/* Main message dispatch loop. */
@@ -3189,6 +3365,8 @@ static void
3189w32_msg_pump (deferred_msg * msg_buf) 3365w32_msg_pump (deferred_msg * msg_buf)
3190{ 3366{
3191 MSG msg; 3367 MSG msg;
3368 int result;
3369 HWND focus_window;
3192 3370
3193 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL); 3371 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
3194 3372
@@ -3207,9 +3385,31 @@ w32_msg_pump (deferred_msg * msg_buf)
3207 SetThreadLocale (msg.wParam); 3385 SetThreadLocale (msg.wParam);
3208 /* Reply is not expected. */ 3386 /* Reply is not expected. */
3209 break; 3387 break;
3388 case WM_EMACS_SETKEYBOARDLAYOUT:
3389 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3390 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3391 result, 0))
3392 abort ();
3393 break;
3394 case WM_EMACS_REGISTER_HOT_KEY:
3395 focus_window = GetFocus ();
3396 if (focus_window != NULL)
3397 RegisterHotKey (focus_window,
3398 HOTKEY_ID (msg.wParam),
3399 HOTKEY_MODIFIERS (msg.wParam),
3400 HOTKEY_VK_CODE (msg.wParam));
3401 /* Reply is not expected. */
3402 break;
3403 case WM_EMACS_UNREGISTER_HOT_KEY:
3404 focus_window = GetFocus ();
3405 if (focus_window != NULL)
3406 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
3407 /* Mark item as erased. */
3408 XCAR ((Lisp_Object) msg.lParam) = Qnil;
3409 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3410 abort ();
3411 break;
3210 default: 3412 default:
3211 /* No need to be so draconian! */
3212 /* abort (); */
3213 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message)); 3413 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
3214 } 3414 }
3215 } 3415 }
@@ -3326,8 +3526,6 @@ w32_msg_worker (dw)
3326 3526
3327/* Main window procedure */ 3527/* Main window procedure */
3328 3528
3329extern char *lispy_function_keys[];
3330
3331LRESULT CALLBACK 3529LRESULT CALLBACK
3332w32_wnd_proc (hwnd, msg, wParam, lParam) 3530w32_wnd_proc (hwnd, msg, wParam, lParam)
3333 HWND hwnd; 3531 HWND hwnd;
@@ -3392,6 +3590,43 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
3392 return (0); 3590 return (0);
3393 } 3591 }
3394 3592
3593 case WM_INPUTLANGCHANGE:
3594 /* Inform lisp thread of keyboard layout changes. */
3595 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3596
3597 /* Clear dead keys in the keyboard state; for simplicity only
3598 preserve modifier key states. */
3599 {
3600 int i;
3601 BYTE keystate[256];
3602
3603 GetKeyboardState (keystate);
3604 for (i = 0; i < 256; i++)
3605 if (1
3606 && i != VK_SHIFT
3607 && i != VK_LSHIFT
3608 && i != VK_RSHIFT
3609 && i != VK_CAPITAL
3610 && i != VK_NUMLOCK
3611 && i != VK_SCROLL
3612 && i != VK_CONTROL
3613 && i != VK_LCONTROL
3614 && i != VK_RCONTROL
3615 && i != VK_MENU
3616 && i != VK_LMENU
3617 && i != VK_RMENU
3618 && i != VK_LWIN
3619 && i != VK_RWIN)
3620 keystate[i] = 0;
3621 SetKeyboardState (keystate);
3622 }
3623 goto dflt;
3624
3625 case WM_HOTKEY:
3626 /* Synchronize hot keys with normal input. */
3627 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
3628 return (0);
3629
3395 case WM_KEYUP: 3630 case WM_KEYUP:
3396 case WM_SYSKEYUP: 3631 case WM_SYSKEYUP:
3397 record_keyup (wParam, lParam); 3632 record_keyup (wParam, lParam);
@@ -3399,40 +3634,161 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
3399 3634
3400 case WM_KEYDOWN: 3635 case WM_KEYDOWN:
3401 case WM_SYSKEYDOWN: 3636 case WM_SYSKEYDOWN:
3637 /* Ignore keystrokes we fake ourself; see below. */
3638 if (dpyinfo->faked_key == wParam)
3639 {
3640 dpyinfo->faked_key = 0;
3641 return 0;
3642 }
3643
3402 /* Synchronize modifiers with current keystroke. */ 3644 /* Synchronize modifiers with current keystroke. */
3403 sync_modifiers (); 3645 sync_modifiers ();
3404
3405 record_keydown (wParam, lParam); 3646 record_keydown (wParam, lParam);
3406 3647 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
3407 wParam = map_keypad_keys (wParam, lParam);
3408 3648
3409 windows_translate = 0; 3649 windows_translate = 0;
3410 switch (wParam) { 3650
3411 case VK_LWIN: 3651 switch (wParam)
3412 case VK_RWIN: 3652 {
3413 case VK_APPS: 3653 case VK_LWIN:
3414 /* More support for these keys will likely be necessary. */ 3654 if (NILP (Vw32_pass_lwindow_to_system))
3415 if (!NILP (Vw32_pass_optional_keys_to_system)) 3655 {
3656 /* Prevent system from acting on keyup (which opens the
3657 Start menu if no other key was pressed) by simulating a
3658 press of Space which we will ignore. */
3659 if (GetAsyncKeyState (wParam) & 1)
3660 {
3661 dpyinfo->faked_key = VK_SPACE;
3662 keybd_event (VK_SPACE,
3663 (BYTE) MapVirtualKey (VK_SPACE, 0), 0, 0);
3664 }
3665 }
3666 if (!NILP (Vw32_lwindow_modifier))
3667 return 0;
3668 break;
3669 case VK_RWIN:
3670 if (NILP (Vw32_pass_rwindow_to_system))
3671 {
3672 if (GetAsyncKeyState (wParam) & 1)
3673 {
3674 dpyinfo->faked_key = VK_SPACE;
3675 keybd_event (VK_SPACE,
3676 (BYTE) MapVirtualKey (VK_SPACE, 0), 0, 0);
3677 }
3678 }
3679 if (!NILP (Vw32_rwindow_modifier))
3680 return 0;
3681 break;
3682 case VK_APPS:
3683 if (!NILP (Vw32_apps_modifier))
3684 return 0;
3685 break;
3686 case VK_MENU:
3687 if (NILP (Vw32_pass_alt_to_system))
3688 return 0;
3416 windows_translate = 1; 3689 windows_translate = 1;
3417 break; 3690 break;
3418 case VK_MENU: 3691 case VK_CAPITAL:
3419 if (NILP (Vw32_pass_alt_to_system)) 3692 /* Decide whether to treat as modifier or function key. */
3693 if (NILP (Vw32_enable_caps_lock))
3694 goto disable_lock_key;
3420 return 0; 3695 return 0;
3421 windows_translate = 1; 3696 case VK_NUMLOCK:
3422 break; 3697 /* Decide whether to treat as modifier or function key. */
3423 case VK_CONTROL: 3698 if (NILP (Vw32_enable_num_lock))
3424 case VK_CAPITAL: 3699 goto disable_lock_key;
3425 case VK_SHIFT: 3700 return 0;
3426 case VK_NUMLOCK: 3701 case VK_SCROLL:
3427 case VK_SCROLL: 3702 /* Decide whether to treat as modifier or function key. */
3428 windows_translate = 1; 3703 if (NILP (Vw32_scroll_lock_modifier))
3429 break; 3704 goto disable_lock_key;
3430 default: 3705 return 0;
3431 /* If not defined as a function key, change it to a WM_CHAR message. */ 3706 disable_lock_key:
3432 if (lispy_function_keys[wParam] == 0) 3707 /* Ensure the appropriate lock key state is off (and the
3433 msg = WM_CHAR; 3708 indicator light as well). */
3434 break; 3709 if (GetAsyncKeyState (wParam) & 0x8000)
3435 } 3710 {
3711 /* Fake another press of the relevant key. Apparently,
3712 this really is the only way to turn off the indicator. */
3713 dpyinfo->faked_key = wParam;
3714 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
3715 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3716 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
3717 KEYEVENTF_EXTENDEDKEY | 0, 0);
3718 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
3719 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3720 }
3721 break;
3722 case VK_CONTROL:
3723 case VK_SHIFT:
3724 case VK_PROCESSKEY: /* Generated by IME. */
3725 windows_translate = 1;
3726 break;
3727 default:
3728 /* If not defined as a function key, change it to a WM_CHAR message. */
3729 if (lispy_function_keys[wParam] == 0)
3730 {
3731 if (!NILP (Vw32_recognize_altgr)
3732 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
3733 {
3734 /* Always let TranslateMessage handle AltGr key chords;
3735 for some reason, ToAscii doesn't always process AltGr
3736 chords correctly. */
3737 windows_translate = 1;
3738 }
3739 else if (modifier_set (VK_CONTROL) || modifier_set (VK_MENU))
3740 {
3741 /* Handle key chords including any modifiers other than shift
3742 directly, in order to preserve as much modifier information as
3743 possible. */
3744 if ('A' <= wParam && wParam <= 'Z')
3745 {
3746 /* Don't translate modified alphabetic keystrokes,
3747 so the user doesn't need to constantly switch
3748 layout to type control or meta keystrokes when
3749 the normal layout translates alphabetic
3750 characters to non-ascii characters. */
3751 if (!modifier_set (VK_SHIFT))
3752 wParam += ('a' - 'A');
3753 msg = WM_CHAR;
3754 }
3755 else
3756 {
3757 /* Try to handle other keystrokes by determining the
3758 base character (ie. translating the base key plus
3759 shift modifier). */
3760 int add;
3761 int isdead = 0;
3762 KEY_EVENT_RECORD key;
3763
3764 key.bKeyDown = TRUE;
3765 key.wRepeatCount = 1;
3766 key.wVirtualKeyCode = wParam;
3767 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
3768 key.uChar.AsciiChar = 0;
3769 key.dwControlKeyState = construct_console_modifiers ();
3770
3771 add = w32_kbd_patch_key (&key);
3772 /* 0 means an unrecognised keycode, negative means
3773 dead key. Ignore both. */
3774 while (--add >= 0)
3775 {
3776 /* Forward asciified character sequence. */
3777 post_character_message
3778 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
3779 w32_get_key_modifiers (wParam, lParam));
3780 w32_kbd_patch_key (&key);
3781 }
3782 return 0;
3783 }
3784 }
3785 else
3786 {
3787 /* Let TranslateMessage handle everything else. */
3788 windows_translate = 1;
3789 }
3790 }
3791 }
3436 3792
3437 if (windows_translate) 3793 if (windows_translate)
3438 { 3794 {
@@ -3447,36 +3803,8 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
3447 3803
3448 case WM_SYSCHAR: 3804 case WM_SYSCHAR:
3449 case WM_CHAR: 3805 case WM_CHAR:
3450 wmsg.dwModifiers = construct_modifiers (wParam, lParam); 3806 post_character_message (hwnd, msg, wParam, lParam,
3451 3807 w32_get_key_modifiers (wParam, lParam));
3452#if 1
3453 /* Detect quit_char and set quit-flag directly. Note that we
3454 still need to post a message to ensure the main thread will be
3455 woken up if blocked in sys_select(), but we do NOT want to post
3456 the quit_char message itself (because it will usually be as if
3457 the user had typed quit_char twice). Instead, we post a dummy
3458 message that has no particular effect. */
3459 {
3460 int c = wParam;
3461 if (isalpha (c) && (wmsg.dwModifiers == LEFT_CTRL_PRESSED
3462 || wmsg.dwModifiers == RIGHT_CTRL_PRESSED))
3463 c = make_ctrl_char (c) & 0377;
3464 if (c == quit_char)
3465 {
3466 Vquit_flag = Qt;
3467
3468 /* The choice of message is somewhat arbitrary, as long as
3469 the main thread handler just ignores it. */
3470 msg = WM_NULL;
3471
3472 /* Interrupt any blocking system calls. */
3473 signal_quit ();
3474 }
3475 }
3476#endif
3477
3478 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3479
3480 break; 3808 break;
3481 3809
3482 /* Simulate middle mouse button events when left and right buttons 3810 /* Simulate middle mouse button events when left and right buttons
@@ -3817,8 +4145,10 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
3817 goto dflt; 4145 goto dflt;
3818#endif 4146#endif
3819 4147
3820 case WM_ACTIVATE:
3821 case WM_ACTIVATEAPP: 4148 case WM_ACTIVATEAPP:
4149 dpyinfo->faked_key = 0;
4150 reset_modifiers ();
4151 case WM_ACTIVATE:
3822 case WM_WINDOWPOSCHANGED: 4152 case WM_WINDOWPOSCHANGED:
3823 case WM_SHOWWINDOW: 4153 case WM_SHOWWINDOW:
3824 /* Inform lisp thread that a frame might have just been obscured 4154 /* Inform lisp thread that a frame might have just been obscured
@@ -3827,11 +4157,14 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
3827 goto dflt; 4157 goto dflt;
3828 4158
3829 case WM_SETFOCUS: 4159 case WM_SETFOCUS:
3830 reset_modifiers (); 4160 register_hot_keys (hwnd);
4161 goto command;
3831 case WM_KILLFOCUS: 4162 case WM_KILLFOCUS:
4163 unregister_hot_keys (hwnd);
3832 case WM_MOVE: 4164 case WM_MOVE:
3833 case WM_SIZE: 4165 case WM_SIZE:
3834 case WM_COMMAND: 4166 case WM_COMMAND:
4167 command:
3835 wmsg.dwModifiers = w32_get_modifiers (); 4168 wmsg.dwModifiers = w32_get_modifiers ();
3836 my_post_msg (&wmsg, hwnd, msg, wParam, lParam); 4169 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3837 goto dflt; 4170 goto dflt;
@@ -6086,6 +6419,187 @@ If optional parameter FRAME is not specified, use selected frame.")
6086 return Qnil; 6419 return Qnil;
6087} 6420}
6088 6421
6422/* Lookup virtual keycode from string representing the name of a
6423 non-ascii keystroke into the corresponding virtual key, using
6424 lispy_function_keys. */
6425static int
6426lookup_vk_code (char *key)
6427{
6428 int i;
6429
6430 for (i = 0; i < 256; i++)
6431 if (lispy_function_keys[i] != 0
6432 && strcmp (lispy_function_keys[i], key) == 0)
6433 return i;
6434
6435 return -1;
6436}
6437
6438/* Convert a one-element vector style key sequence to a hot key
6439 definition. */
6440static int
6441w32_parse_hot_key (key)
6442 Lisp_Object key;
6443{
6444 /* Copied from Fdefine_key and store_in_keymap. */
6445 register Lisp_Object c;
6446 int vk_code;
6447 int lisp_modifiers;
6448 int w32_modifiers;
6449 struct gcpro gcpro1;
6450
6451 CHECK_VECTOR (key, 0);
6452
6453 if (XFASTINT (Flength (key)) != 1)
6454 return Qnil;
6455
6456 GCPRO1 (key);
6457
6458 c = Faref (key, make_number (0));
6459
6460 if (CONSP (c) && lucid_event_type_list_p (c))
6461 c = Fevent_convert_list (c);
6462
6463 UNGCPRO;
6464
6465 if (! INTEGERP (c) && ! SYMBOLP (c))
6466 error ("Key definition is invalid");
6467
6468 /* Work out the base key and the modifiers. */
6469 if (SYMBOLP (c))
6470 {
6471 c = parse_modifiers (c);
6472 lisp_modifiers = Fcar (Fcdr (c));
6473 c = Fcar (c);
6474 if (!SYMBOLP (c))
6475 abort ();
6476 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
6477 }
6478 else if (INTEGERP (c))
6479 {
6480 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
6481 /* Many ascii characters are their own virtual key code. */
6482 vk_code = XINT (c) & CHARACTERBITS;
6483 }
6484
6485 if (vk_code < 0 || vk_code > 255)
6486 return Qnil;
6487
6488 if ((lisp_modifiers & meta_modifier) != 0
6489 && !NILP (Vw32_alt_is_meta))
6490 lisp_modifiers |= alt_modifier;
6491
6492 /* Convert lisp modifiers to Windows hot-key form. */
6493 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
6494 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
6495 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
6496 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
6497
6498 return HOTKEY (vk_code, w32_modifiers);
6499}
6500
6501DEFUN ("w32-register-hot-key", Fw32_register_hot_key, Sw32_register_hot_key, 1, 1, 0,
6502 "Register KEY as a hot-key combination.\n\
6503Certain key combinations like Alt-Tab are reserved for system use on\n\
6504Windows, and therefore are normally intercepted by the system. However,\n\
6505most of these key combinations can be received by registering them as\n\
6506hot-keys, overriding their special meaning.\n\
6507\n\
6508KEY must be a one element key definition in vector form that would be\n\
6509acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta\n\
6510modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper\n\
6511is always interpreted as the Windows modifier keys.\n\
6512\n\
6513The return value is the hotkey-id if registered, otherwise nil.")
6514 (key)
6515 Lisp_Object key;
6516{
6517 key = w32_parse_hot_key (key);
6518
6519 if (NILP (Fmemq (key, w32_grabbed_keys)))
6520 {
6521 /* Reuse an empty slot if possible. */
6522 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
6523
6524 /* Safe to add new key to list, even if we have focus. */
6525 if (NILP (item))
6526 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
6527 else
6528 XCAR (item) = key;
6529
6530 /* Notify input thread about new hot-key definition, so that it
6531 takes effect without needing to switch focus. */
6532 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
6533 (WPARAM) key, 0);
6534 }
6535
6536 return key;
6537}
6538
6539DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key, Sw32_unregister_hot_key, 1, 1, 0,
6540 "Unregister HOTKEY as a hot-key combination.")
6541 (key)
6542 Lisp_Object key;
6543{
6544 Lisp_Object item;
6545
6546 if (!INTEGERP (key))
6547 key = w32_parse_hot_key (key);
6548
6549 item = Fmemq (key, w32_grabbed_keys);
6550
6551 if (!NILP (item))
6552 {
6553 /* Notify input thread about hot-key definition being removed, so
6554 that it takes effect without needing focus switch. */
6555 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
6556 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
6557 {
6558 MSG msg;
6559 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
6560 }
6561 return Qt;
6562 }
6563 return Qnil;
6564}
6565
6566DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys, Sw32_registered_hot_keys, 0, 0, 0,
6567 "Return list of registered hot-key IDs.")
6568 ()
6569{
6570 return Fcopy_sequence (w32_grabbed_keys);
6571}
6572
6573DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key, Sw32_reconstruct_hot_key, 1, 1, 0,
6574 "Convert hot-key ID to a lisp key combination.")
6575 (hotkeyid)
6576 Lisp_Object hotkeyid;
6577{
6578 int vk_code, w32_modifiers;
6579 Lisp_Object key;
6580
6581 CHECK_NUMBER (hotkeyid, 0);
6582
6583 vk_code = HOTKEY_VK_CODE (hotkeyid);
6584 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
6585
6586 if (lispy_function_keys[vk_code])
6587 key = intern (lispy_function_keys[vk_code]);
6588 else
6589 key = make_number (vk_code);
6590
6591 key = Fcons (key, Qnil);
6592 if (w32_modifiers & MOD_SHIFT)
6593 key = Fcons (intern ("shift"), key);
6594 if (w32_modifiers & MOD_CONTROL)
6595 key = Fcons (intern ("control"), key);
6596 if (w32_modifiers & MOD_ALT)
6597 key = Fcons (intern (NILP (Vw32_alt_is_meta) ? "alt" : "meta"), key);
6598 if (w32_modifiers & MOD_WIN)
6599 key = Fcons (intern ("hyper"), key);
6600
6601 return key;
6602}
6089 6603
6090syms_of_w32fns () 6604syms_of_w32fns ()
6091{ 6605{
@@ -6171,8 +6685,11 @@ syms_of_w32fns ()
6171 Fput (Qundefined_color, Qerror_message, 6685 Fput (Qundefined_color, Qerror_message,
6172 build_string ("Undefined color")); 6686 build_string ("Undefined color"));
6173 6687
6688 staticpro (&w32_grabbed_keys);
6689 w32_grabbed_keys = Qnil;
6690
6174 DEFVAR_LISP ("w32-color-map", &Vw32_color_map, 6691 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
6175 "A array of color name mappings for windows."); 6692 "An array of color name mappings for windows.");
6176 Vw32_color_map = Qnil; 6693 Vw32_color_map = Qnil;
6177 6694
6178 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system, 6695 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
@@ -6186,11 +6703,61 @@ open the System menu. When nil, Emacs silently swallows alt key events.");
6186When nil, Emacs will translate the alt key to the Alt modifier, and not Meta."); 6703When nil, Emacs will translate the alt key to the Alt modifier, and not Meta.");
6187 Vw32_alt_is_meta = Qt; 6704 Vw32_alt_is_meta = Qt;
6188 6705
6189 DEFVAR_LISP ("w32-pass-optional-keys-to-system", 6706 DEFVAR_LISP ("w32-pass-lwindow-to-system",
6190 &Vw32_pass_optional_keys_to_system, 6707 &Vw32_pass_lwindow_to_system,
6191 "Non-nil if the 'optional' keys (left window, right window,\n\ 6708 "Non-nil if the left \"Windows\" key is passed on to Windows.\n\
6192and application keys) are passed on to Windows."); 6709When non-nil, the Start menu is opened by tapping the key.");
6193 Vw32_pass_optional_keys_to_system = Qnil; 6710 Vw32_pass_lwindow_to_system = Qt;
6711
6712 DEFVAR_LISP ("w32-pass-rwindow-to-system",
6713 &Vw32_pass_rwindow_to_system,
6714 "Non-nil if the right \"Windows\" key is passed on to Windows.\n\
6715When non-nil, the Start menu is opened by tapping the key.");
6716 Vw32_pass_rwindow_to_system = Qt;
6717
6718 DEFVAR_LISP ("w32-enable-num-lock",
6719 &Vw32_enable_num_lock,
6720 "Non-nil if Num Lock should act normally.\n\
6721Set to nil to see Num Lock as the key `kp-numlock'.");
6722 Vw32_enable_num_lock = Qt;
6723
6724 DEFVAR_LISP ("w32-enable-caps-lock",
6725 &Vw32_enable_caps_lock,
6726 "Non-nil if Caps Lock should act normally.\n\
6727Set to nil to see Caps Lock as the key `capslock'.");
6728 Vw32_enable_caps_lock = Qt;
6729
6730 DEFVAR_LISP ("w32-scroll-lock-modifier",
6731 &Vw32_scroll_lock_modifier,
6732 "Modifier to use for the Scroll Lock on state.\n\
6733The value can be hyper, super, meta, alt, control or shift for the\n\
6734respective modifier, or nil to see Scroll Lock as the key `scroll'.\n\
6735Any other value will cause the key to be ignored.");
6736 Vw32_scroll_lock_modifier = Qt;
6737
6738 DEFVAR_LISP ("w32-lwindow-modifier",
6739 &Vw32_lwindow_modifier,
6740 "Modifier to use for the left \"Windows\" key.\n\
6741The value can be hyper, super, meta, alt, control or shift for the\n\
6742respective modifier, or nil to appear as the key `lwindow'.\n\
6743Any other value will cause the key to be ignored.");
6744 Vw32_lwindow_modifier = Qnil;
6745
6746 DEFVAR_LISP ("w32-rwindow-modifier",
6747 &Vw32_rwindow_modifier,
6748 "Modifier to use for the right \"Windows\" key.\n\
6749The value can be hyper, super, meta, alt, control or shift for the\n\
6750respective modifier, or nil to appear as the key `rwindow'.\n\
6751Any other value will cause the key to be ignored.");
6752 Vw32_rwindow_modifier = Qnil;
6753
6754 DEFVAR_LISP ("w32-apps-modifier",
6755 &Vw32_apps_modifier,
6756 "Modifier to use for the \"Apps\" key.\n\
6757The value can be hyper, super, meta, alt, control or shift for the\n\
6758respective modifier, or nil to appear as the key `apps'.\n\
6759Any other value will cause the key to be ignored.");
6760 Vw32_apps_modifier = Qnil;
6194 6761
6195 DEFVAR_LISP ("w32-enable-italics", &Vw32_enable_italics, 6762 DEFVAR_LISP ("w32-enable-italics", &Vw32_enable_italics,
6196 "Non-nil enables selection of artificially italicized fonts."); 6763 "Non-nil enables selection of artificially italicized fonts.");
@@ -6314,6 +6881,10 @@ displayed according to the current fontset.");
6314 defsubr (&Sw32_default_color_map); 6881 defsubr (&Sw32_default_color_map);
6315 defsubr (&Sw32_load_color_file); 6882 defsubr (&Sw32_load_color_file);
6316 defsubr (&Sw32_send_sys_command); 6883 defsubr (&Sw32_send_sys_command);
6884 defsubr (&Sw32_register_hot_key);
6885 defsubr (&Sw32_unregister_hot_key);
6886 defsubr (&Sw32_registered_hot_keys);
6887 defsubr (&Sw32_reconstruct_hot_key);
6317 6888
6318 /* Setting callback functions for fontset handler. */ 6889 /* Setting callback functions for fontset handler. */
6319 get_font_info_func = w32_get_font_info; 6890 get_font_info_func = w32_get_font_info;
@@ -6328,6 +6899,12 @@ displayed according to the current fontset.");
6328#undef abort 6899#undef abort
6329 6900
6330void 6901void
6902/* For convenience when debugging. */
6903int
6904w32_last_error()
6905{
6906 return GetLastError ();
6907}
6331w32_abort() 6908w32_abort()
6332{ 6909{
6333 int button; 6910 int button;