aboutsummaryrefslogtreecommitdiffstats
path: root/src/w32fns.c
diff options
context:
space:
mode:
authorGeoff Voelker <[email protected]>1998-12-02 23:52:47 +0000
committerGeoff Voelker <[email protected]>1998-12-02 23:52:47 +0000
commitadcc38092facc5b5de19c467d71863106cae7b57 (patch)
tree8b8e4e6eccbb1cf7f4b3a002e088ce3d33249680 /src/w32fns.c
parent36f22224e1b22e6a45448ba634cd6ea57e44e152 (diff)
(Vw32_phantom_key_code): New variable.
(Qhyper, Qsuper, Qmeta, Qalt, Qctrl, Qcontrol, Qshift): New variables. (syms_of_w32fns): Init and register them. (reset_modifiers): Use a more precise test for whether Emacs has keyboard focus. Synchronize state of all keys that can be used as modifiers, to overcome problems arising from hot-keys. (w32_key_to_modifier): Be careful not to call intern() to avoid requiring thread synchronization. (w32_msg_pump): Handle new WM_EMACS_TOGGLE_LOCK_KEY message. (w32_wnd_proc): Ensure lock key indicator lights are updated promptly on Windows 9x, by passing key events on to the system. (w32_wnd_proc): Use Vw32_phantom_key_code to stop system responding to Windows key events when not wanted. (w32_wnd_proc): Undo the mapping of Ctrl-Pause into cancel and Ctrl-NumLock into pause by the system. (w32_wnd_proc): Don't translate key combinations containing any modifiers other than shift (and capslock). (w32_wnd_proc): Reset modifier key states when receiving focus (we can't determine the key states until we have keyboard focus). (Fw32_toggle_lock_key): New function. (syms_of_w32fns): Defsubr it.
Diffstat (limited to 'src/w32fns.c')
-rw-r--r--src/w32fns.c265
1 files changed, 217 insertions, 48 deletions
diff --git a/src/w32fns.c b/src/w32fns.c
index b501d19db2..47423f466f 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -48,6 +48,7 @@ Boston, MA 02111-1307, USA. */
extern void abort ();
extern void free_frame_menubar ();
extern struct scroll_bar *x_window_to_scroll_bar ();
+extern int w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state);
extern int quit_char;
extern char *lispy_function_keys[];
@@ -70,6 +71,10 @@ Lisp_Object Vw32_pass_lwindow_to_system;
only affects whether "tapping" the key opens the Start menu). */
Lisp_Object Vw32_pass_rwindow_to_system;
+/* Virtual key code used to generate "phantom" key presses in order
+ to stop system from acting on Windows key events. */
+Lisp_Object Vw32_phantom_key_code;
+
/* Modifier associated with the left "Windows" key, or nil to act as a
normal key. */
Lisp_Object Vw32_lwindow_modifier;
@@ -202,6 +207,14 @@ Lisp_Object Quser_position;
Lisp_Object Quser_size;
Lisp_Object Qdisplay;
+Lisp_Object Qhyper;
+Lisp_Object Qsuper;
+Lisp_Object Qmeta;
+Lisp_Object Qalt;
+Lisp_Object Qctrl;
+Lisp_Object Qcontrol;
+Lisp_Object Qshift;
+
/* State variables for emulating a three button mouse. */
#define LMOUSE 1
#define MMOUSE 2
@@ -3091,16 +3104,13 @@ reset_modifiers ()
{
SHORT ctrl, alt;
- if (!modifiers_recorded)
+ if (GetFocus () == NULL)
+ /* Emacs doesn't have keyboard focus. Do nothing. */
return;
ctrl = GetAsyncKeyState (VK_CONTROL);
alt = GetAsyncKeyState (VK_MENU);
- if (ctrl == 0 || alt == 0)
- /* Emacs doesn't have keyboard focus. Do nothing. */
- return;
-
if (!(ctrl & 0x08000))
/* Clear any recorded control modifier state. */
modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
@@ -3109,8 +3119,27 @@ reset_modifiers ()
/* Clear any recorded alt modifier state. */
modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
- /* Otherwise, leave the modifier state as it was when Emacs lost
- keyboard focus. */
+ /* Update the state of all modifier keys, because modifiers used in
+ hot-key combinations can get stuck on if Emacs loses focus as a
+ result of a hot-key being pressed. */
+ {
+ BYTE keystate[256];
+
+#define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
+
+ GetKeyboardState (keystate);
+ keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
+ keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
+ keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
+ keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
+ keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
+ keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
+ keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
+ keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
+ keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
+ keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
+ SetKeyboardState (keystate);
+ }
}
/* Synchronize modifier state with what is reported with the current
@@ -3178,19 +3207,25 @@ w32_key_to_modifier (int key)
key_mapping = Qnil;
}
- if (EQ (key_mapping, intern ("hyper")))
+ /* NB. This code runs in the input thread, asychronously to the lisp
+ thread, so we must be careful to ensure access to lisp data is
+ thread-safe. The following code is safe because the modifier
+ variable values are updated atomically from lisp and symbols are
+ not relocated by GC. Also, we don't have to worry about seeing GC
+ markbits here. */
+ if (EQ (key_mapping, Qhyper))
return hyper_modifier;
- if (EQ (key_mapping, intern ("super")))
+ if (EQ (key_mapping, Qsuper))
return super_modifier;
- if (EQ (key_mapping, intern ("meta")))
+ if (EQ (key_mapping, Qmeta))
return meta_modifier;
- if (EQ (key_mapping, intern ("alt")))
+ if (EQ (key_mapping, Qalt))
return alt_modifier;
- if (EQ (key_mapping, intern ("ctrl")))
+ if (EQ (key_mapping, Qctrl))
return ctrl_modifier;
- if (EQ (key_mapping, intern ("control"))) /* synonym for ctrl */
+ if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
return ctrl_modifier;
- if (EQ (key_mapping, intern ("shift")))
+ if (EQ (key_mapping, Qshift))
return shift_modifier;
/* Don't generate any modifier if not explicitly requested. */
@@ -3404,11 +3439,47 @@ w32_msg_pump (deferred_msg * msg_buf)
focus_window = GetFocus ();
if (focus_window != NULL)
UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
- /* Mark item as erased. */
+ /* Mark item as erased. NB: this code must be
+ thread-safe. The next line is okay because the cons
+ cell is never made into garbage and is not relocated by
+ GC. */
XCAR ((Lisp_Object) msg.lParam) = Qnil;
if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
abort ();
break;
+ case WM_EMACS_TOGGLE_LOCK_KEY:
+ {
+ int vk_code = (int) msg.wParam;
+ int cur_state = (GetKeyState (vk_code) & 1);
+ Lisp_Object new_state = (Lisp_Object) msg.lParam;
+
+ /* NB: This code must be thread-safe. It is safe to
+ call NILP because symbols are not relocated by GC,
+ and pointer here is not touched by GC (so the markbit
+ can't be set). Numbers are safe because they are
+ immediate values. */
+ if (NILP (new_state)
+ || (NUMBERP (new_state)
+ && (XUINT (new_state)) & 1 != cur_state))
+ {
+ one_w32_display_info.faked_key = vk_code;
+
+ keybd_event ((BYTE) vk_code,
+ (BYTE) MapVirtualKey (vk_code, 0),
+ KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
+ keybd_event ((BYTE) vk_code,
+ (BYTE) MapVirtualKey (vk_code, 0),
+ KEYEVENTF_EXTENDEDKEY | 0, 0);
+ keybd_event ((BYTE) vk_code,
+ (BYTE) MapVirtualKey (vk_code, 0),
+ KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
+ cur_state = !cur_state;
+ }
+ if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
+ cur_state, 0))
+ abort ();
+ }
+ break;
default:
DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
}
@@ -3638,7 +3709,9 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
if (dpyinfo->faked_key == wParam)
{
dpyinfo->faked_key = 0;
- return 0;
+ /* Make sure TranslateMessage sees them though. */
+ windows_translate = 1;
+ goto translate;
}
/* Synchronize modifiers with current keystroke. */
@@ -3658,33 +3731,44 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
press of Space which we will ignore. */
if (GetAsyncKeyState (wParam) & 1)
{
- dpyinfo->faked_key = VK_SPACE;
- keybd_event (VK_SPACE,
- (BYTE) MapVirtualKey (VK_SPACE, 0), 0, 0);
+ if (NUMBERP (Vw32_phantom_key_code))
+ wParam = XUINT (Vw32_phantom_key_code) & 255;
+ else
+ wParam = VK_SPACE;
+ dpyinfo->faked_key = wParam;
+ keybd_event (wParam, (BYTE) MapVirtualKey (wParam, 0), 0, 0);
}
}
if (!NILP (Vw32_lwindow_modifier))
return 0;
+ windows_translate = 1;
break;
case VK_RWIN:
if (NILP (Vw32_pass_rwindow_to_system))
{
if (GetAsyncKeyState (wParam) & 1)
{
- dpyinfo->faked_key = VK_SPACE;
- keybd_event (VK_SPACE,
- (BYTE) MapVirtualKey (VK_SPACE, 0), 0, 0);
+ if (NUMBERP (Vw32_phantom_key_code))
+ wParam = XUINT (Vw32_phantom_key_code) & 255;
+ else
+ wParam = VK_SPACE;
+ dpyinfo->faked_key = wParam;
+ keybd_event (wParam, (BYTE) MapVirtualKey (wParam, 0), 0, 0);
}
}
if (!NILP (Vw32_rwindow_modifier))
return 0;
+ windows_translate = 1;
break;
case VK_APPS:
if (!NILP (Vw32_apps_modifier))
return 0;
+ windows_translate = 1;
break;
case VK_MENU:
if (NILP (Vw32_pass_alt_to_system))
+ /* Prevent DefWindowProc from activating the menu bar if an
+ Alt key is pressed and released by itself. */
return 0;
windows_translate = 1;
break;
@@ -3692,42 +3776,65 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
/* Decide whether to treat as modifier or function key. */
if (NILP (Vw32_enable_caps_lock))
goto disable_lock_key;
- return 0;
+ windows_translate = 1;
+ break;
case VK_NUMLOCK:
/* Decide whether to treat as modifier or function key. */
if (NILP (Vw32_enable_num_lock))
goto disable_lock_key;
- return 0;
+ windows_translate = 1;
+ break;
case VK_SCROLL:
/* Decide whether to treat as modifier or function key. */
if (NILP (Vw32_scroll_lock_modifier))
goto disable_lock_key;
- return 0;
+ windows_translate = 1;
+ break;
disable_lock_key:
- /* Ensure the appropriate lock key state is off (and the
- indicator light as well). */
- if (GetAsyncKeyState (wParam) & 0x8000)
- {
- /* Fake another press of the relevant key. Apparently,
- this really is the only way to turn off the indicator. */
- dpyinfo->faked_key = wParam;
- keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
- KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
- keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
- KEYEVENTF_EXTENDEDKEY | 0, 0);
- keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
- KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
- }
+ /* Ensure the appropriate lock key state (and indicator light)
+ remains in the same state. We do this by faking another
+ press of the relevant key. Apparently, this really is the
+ only way to toggle the state of the indicator lights. */
+ dpyinfo->faked_key = wParam;
+ keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
+ KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
+ keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
+ KEYEVENTF_EXTENDEDKEY | 0, 0);
+ keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
+ KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
+ /* Ensure indicator lights are updated promptly on Windows 9x
+ (TranslateMessage apparently does this), after forwarding
+ input event. */
+ post_character_message (hwnd, msg, wParam, lParam,
+ w32_get_key_modifiers (wParam, lParam));
+ windows_translate = 1;
break;
case VK_CONTROL:
case VK_SHIFT:
case VK_PROCESSKEY: /* Generated by IME. */
windows_translate = 1;
break;
+ case VK_CANCEL:
+ /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
+ which is confusing for purposes of key binding; convert
+ VK_CANCEL events into VK_PAUSE events. */
+ wParam = VK_PAUSE;
+ break;
+ case VK_PAUSE:
+ /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
+ for purposes of key binding; convert these back into
+ VK_NUMLOCK events, at least when we want to see NumLock key
+ presses. (Note that there is never any possibility that
+ VK_PAUSE with Ctrl really is C-Pause as per above.) */
+ if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
+ wParam = VK_NUMLOCK;
+ break;
default:
/* If not defined as a function key, change it to a WM_CHAR message. */
if (lispy_function_keys[wParam] == 0)
{
+ DWORD modifiers = construct_console_modifiers ();
+
if (!NILP (Vw32_recognize_altgr)
&& modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
{
@@ -3736,11 +3843,11 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
chords correctly. */
windows_translate = 1;
}
- else if (modifier_set (VK_CONTROL) || modifier_set (VK_MENU))
+ else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
{
- /* Handle key chords including any modifiers other than shift
- directly, in order to preserve as much modifier information as
- possible. */
+ /* Handle key chords including any modifiers other
+ than shift directly, in order to preserve as much
+ modifier information as possible. */
if ('A' <= wParam && wParam <= 'Z')
{
/* Don't translate modified alphabetic keystrokes,
@@ -3766,7 +3873,7 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
key.wVirtualKeyCode = wParam;
key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
key.uChar.AsciiChar = 0;
- key.dwControlKeyState = construct_console_modifiers ();
+ key.dwControlKeyState = modifiers;
add = w32_kbd_patch_key (&key);
/* 0 means an unrecognised keycode, negative means
@@ -3790,6 +3897,7 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
}
}
+ translate:
if (windows_translate)
{
MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
@@ -3860,7 +3968,8 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
{
/* Hold onto message for now. */
mouse_button_timer =
- SetTimer (hwnd, MOUSE_BUTTON_ID, XINT (Vw32_mouse_button_tolerance), NULL);
+ SetTimer (hwnd, MOUSE_BUTTON_ID,
+ XINT (Vw32_mouse_button_tolerance), NULL);
saved_mouse_button_msg.msg.hwnd = hwnd;
saved_mouse_button_msg.msg.message = msg;
saved_mouse_button_msg.msg.wParam = wParam;
@@ -3960,7 +4069,8 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
if (saved_mouse_move_msg.msg.hwnd == 0)
mouse_move_timer =
- SetTimer (hwnd, MOUSE_MOVE_ID, XINT (Vw32_mouse_move_interval), NULL);
+ SetTimer (hwnd, MOUSE_MOVE_ID,
+ XINT (Vw32_mouse_move_interval), NULL);
/* Hold onto message for now. */
saved_mouse_move_msg.msg.hwnd = hwnd;
@@ -4146,8 +4256,6 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
#endif
case WM_ACTIVATEAPP:
- dpyinfo->faked_key = 0;
- reset_modifiers ();
case WM_ACTIVATE:
case WM_WINDOWPOSCHANGED:
case WM_SHOWWINDOW:
@@ -4157,6 +4265,8 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
goto dflt;
case WM_SETFOCUS:
+ dpyinfo->faked_key = 0;
+ reset_modifiers ();
register_hot_keys (hwnd);
goto command;
case WM_KILLFOCUS:
@@ -6600,6 +6710,39 @@ DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key, Sw32_reconstruct_hot
return key;
}
+
+DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key, Sw32_toggle_lock_key, 1, 2, 0,
+ "Toggle the state of the lock key KEY.\n\
+KEY can be `capslock', `kp-numlock', or `scroll'.\n\
+If the optional parameter NEW-STATE is a number, then the state of KEY\n\
+is set to off if the low bit of NEW-STATE is zero, otherwise on.")
+ (key, new_state)
+ Lisp_Object key, new_state;
+{
+ int vk_code;
+ int cur_state;
+
+ if (EQ (key, intern ("capslock")))
+ vk_code = VK_CAPITAL;
+ else if (EQ (key, intern ("kp-numlock")))
+ vk_code = VK_NUMLOCK;
+ else if (EQ (key, intern ("scroll")))
+ vk_code = VK_SCROLL;
+ else
+ return Qnil;
+
+ if (!dwWindowsThreadId)
+ return make_number (w32_console_toggle_lock_key (vk_code, new_state));
+
+ if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
+ (WPARAM) vk_code, (LPARAM) new_state))
+ {
+ MSG msg;
+ GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
+ return make_number (msg.wParam);
+ }
+ return Qnil;
+}
syms_of_w32fns ()
{
@@ -6677,6 +6820,21 @@ syms_of_w32fns ()
staticpro (&Qdisplay);
/* This is the end of symbol initialization. */
+ Qhyper = intern ("hyper");
+ staticpro (&Qhyper);
+ Qsuper = intern ("super");
+ staticpro (&Qsuper);
+ Qmeta = intern ("meta");
+ staticpro (&Qmeta);
+ Qalt = intern ("alt");
+ staticpro (&Qalt);
+ Qctrl = intern ("ctrl");
+ staticpro (&Qctrl);
+ Qcontrol = intern ("control");
+ staticpro (&Qcontrol);
+ Qshift = intern ("shift");
+ staticpro (&Qshift);
+
Qface_set_after_frame_default = intern ("face-set-after-frame-default");
staticpro (&Qface_set_after_frame_default);
@@ -6715,6 +6873,16 @@ When non-nil, the Start menu is opened by tapping the key.");
When non-nil, the Start menu is opened by tapping the key.");
Vw32_pass_rwindow_to_system = Qt;
+ DEFVAR_INT ("w32-phantom-key-code",
+ &Vw32_phantom_key_code,
+ "Virtual key code used to generate \"phantom\" key presses.\n\
+Value is a number between 0 and 255.\n\
+\n\
+Phantom key presses are generated in order to stop the system from\n\
+acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or\n\
+`w32-pass-rwindow-to-system' is nil.");
+ Vw32_phantom_key_code = VK_SPACE;
+
DEFVAR_LISP ("w32-enable-num-lock",
&Vw32_enable_num_lock,
"Non-nil if Num Lock should act normally.\n\
@@ -6885,6 +7053,7 @@ displayed according to the current fontset.");
defsubr (&Sw32_unregister_hot_key);
defsubr (&Sw32_registered_hot_keys);
defsubr (&Sw32_reconstruct_hot_key);
+ defsubr (&Sw32_toggle_lock_key);
/* Setting callback functions for fontset handler. */
get_font_info_func = w32_get_font_info;