Commit ccc2d29c authored by Geoff Voelker's avatar Geoff Voelker

(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.
parent f791da1d
......@@ -50,6 +50,8 @@ extern void free_frame_menubar ();
extern struct scroll_bar *x_window_to_scroll_bar ();
extern int quit_char;
extern char *lispy_function_keys[];
/* The colormap for converting color names to RGB values */
Lisp_Object Vw32_color_map;
......@@ -60,9 +62,34 @@ Lisp_Object Vw32_pass_alt_to_system;
to alt_modifier. */
Lisp_Object Vw32_alt_is_meta;
/* Non nil if left window, right window, and application key events
are passed on to Windows. */
Lisp_Object Vw32_pass_optional_keys_to_system;
/* Non nil if left window key events are passed on to Windows (this only
affects whether "tapping" the key opens the Start menu). */
Lisp_Object Vw32_pass_lwindow_to_system;
/* Non nil if right window key events are passed on to Windows (this
only affects whether "tapping" the key opens the Start menu). */
Lisp_Object Vw32_pass_rwindow_to_system;
/* Modifier associated with the left "Windows" key, or nil to act as a
normal key. */
Lisp_Object Vw32_lwindow_modifier;
/* Modifier associated with the right "Windows" key, or nil to act as a
normal key. */
Lisp_Object Vw32_rwindow_modifier;
/* Modifier associated with the "Apps" key, or nil to act as a normal
key. */
Lisp_Object Vw32_apps_modifier;
/* Value is nil if Num Lock acts as a function key. */
Lisp_Object Vw32_enable_num_lock;
/* Value is nil if Caps Lock acts as a function key. */
Lisp_Object Vw32_enable_caps_lock;
/* Modifier associated with Scroll Lock, or nil to act as a normal key. */
Lisp_Object Vw32_scroll_lock_modifier;
/* Switch to control whether we inhibit requests for italicised fonts (which
are synthesized, look ugly, and are trashed by cursor movement under NT). */
......@@ -205,6 +232,7 @@ extern int last_mouse_scroll_bar_pos;
/* From w32term.c. */
extern Lisp_Object Vw32_num_mouse_buttons;
extern Lisp_Object Vw32_recognize_altgr;
/* Error if we are not connected to MS-Windows. */
......@@ -2959,17 +2987,6 @@ w32_createwindow (f)
}
}
/* Convert between the modifier bits W32 uses and the modifier bits
Emacs uses. */
unsigned int
w32_get_modifiers ()
{
return (((GetKeyState (VK_SHIFT)&0x8000) ? shift_modifier : 0) |
((GetKeyState (VK_CONTROL)&0x8000) ? ctrl_modifier : 0) |
((GetKeyState (VK_MENU)&0x8000) ?
((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
}
void
my_post_msg (wmsg, hwnd, msg, wParam, lParam)
W32Msg * wmsg;
......@@ -3116,7 +3133,7 @@ sync_modifiers ()
static int
modifier_set (int vkey)
{
if (vkey == VK_CAPITAL)
if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
return (GetKeyState (vkey) & 0x1);
if (!modifiers_recorded)
return (GetKeyState (vkey) & 0x8000);
......@@ -3131,56 +3148,215 @@ modifier_set (int vkey)
return modifiers[EMACS_LMENU];
case VK_RMENU:
return modifiers[EMACS_RMENU];
default:
break;
}
return (GetKeyState (vkey) & 0x8000);
}
/* Convert between the modifier bits W32 uses and the modifier bits
Emacs uses. */
unsigned int
w32_key_to_modifier (int key)
{
Lisp_Object key_mapping;
switch (key)
{
case VK_LWIN:
key_mapping = Vw32_lwindow_modifier;
break;
case VK_RWIN:
key_mapping = Vw32_rwindow_modifier;
break;
case VK_APPS:
key_mapping = Vw32_apps_modifier;
break;
case VK_SCROLL:
key_mapping = Vw32_scroll_lock_modifier;
break;
default:
key_mapping = Qnil;
}
if (EQ (key_mapping, intern ("hyper")))
return hyper_modifier;
if (EQ (key_mapping, intern ("super")))
return super_modifier;
if (EQ (key_mapping, intern ("meta")))
return meta_modifier;
if (EQ (key_mapping, intern ("alt")))
return alt_modifier;
if (EQ (key_mapping, intern ("ctrl")))
return ctrl_modifier;
if (EQ (key_mapping, intern ("control"))) /* synonym for ctrl */
return ctrl_modifier;
if (EQ (key_mapping, intern ("shift")))
return shift_modifier;
/* Don't generate any modifier if not explicitly requested. */
return 0;
}
unsigned int
w32_get_modifiers ()
{
return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
(modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
(modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
(modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
(modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
(modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
(modifier_set (VK_MENU) ?
((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
}
/* We map the VK_* modifiers into console modifier constants
so that we can use the same routines to handle both console
and window input. */
static int
construct_modifiers (unsigned int wparam, unsigned int lparam)
construct_console_modifiers ()
{
int mods;
if (wparam != VK_CONTROL && wparam != VK_MENU)
mods = GetLastError ();
mods = 0;
mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
return mods;
}
static unsigned int
map_keypad_keys (unsigned int wparam, unsigned int lparam)
static int
w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
{
unsigned int extended = (lparam & 0x1000000L);
int mods;
/* Convert to emacs modifiers. */
mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
return mods;
}
if (wparam < VK_CLEAR || wparam > VK_DELETE)
return wparam;
unsigned int
map_keypad_keys (unsigned int virt_key, unsigned int extended)
{
if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
return virt_key;
if (wparam == VK_RETURN)
if (virt_key == VK_RETURN)
return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
if (wparam >= VK_PRIOR && wparam <= VK_DOWN)
return (!extended ? (VK_NUMPAD_PRIOR + (wparam - VK_PRIOR)) : wparam);
if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
if (virt_key == VK_INSERT || virt_key == VK_DELETE)
return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
if (virt_key == VK_CLEAR)
return (!extended ? VK_NUMPAD_CLEAR : virt_key);
return virt_key;
}
/* List of special key combinations which w32 would normally capture,
but emacs should grab instead. Not directly visible to lisp, to
simplify synchronization. Each item is an integer encoding a virtual
key code and modifier combination to capture. */
Lisp_Object w32_grabbed_keys;
#define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
#define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
#define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
#define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
/* Register hot-keys for reserved key combinations when Emacs has
keyboard focus, since this is the only way Emacs can receive key
combinations like Alt-Tab which are used by the system. */
static void
register_hot_keys (hwnd)
HWND hwnd;
{
Lisp_Object keylist;
/* Use GC_CONSP, since we are called asynchronously. */
for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
{
Lisp_Object key = XCAR (keylist);
/* Deleted entries get set to nil. */
if (!INTEGERP (key))
continue;
RegisterHotKey (hwnd, HOTKEY_ID (key),
HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
}
}
static void
unregister_hot_keys (hwnd)
HWND hwnd;
{
Lisp_Object keylist;
/* Use GC_CONSP, since we are called asynchronously. */
for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
{
Lisp_Object key = XCAR (keylist);
if (!INTEGERP (key))
continue;
UnregisterHotKey (hwnd, HOTKEY_ID (key));
}
}
static void
post_character_message (hwnd, msg, wParam, lParam, modifiers)
HWND hwnd;
UINT msg;
WPARAM wParam;
LPARAM lParam;
DWORD modifiers;
{
W32Msg wmsg;
if (wparam == VK_INSERT || wparam == VK_DELETE)
return (!extended ? (VK_NUMPAD_INSERT + (wparam - VK_INSERT)) : wparam);
wmsg.dwModifiers = modifiers;
if (wparam == VK_CLEAR)
return (!extended ? VK_NUMPAD_CLEAR : wparam);
/* Detect quit_char and set quit-flag directly. Note that we
still need to post a message to ensure the main thread will be
woken up if blocked in sys_select(), but we do NOT want to post
the quit_char message itself (because it will usually be as if
the user had typed quit_char twice). Instead, we post a dummy
message that has no particular effect. */
{
int c = wParam;
if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
c = make_ctrl_char (c) & 0377;
if (c == quit_char)
{
Vquit_flag = Qt;
/* The choice of message is somewhat arbitrary, as long as
the main thread handler just ignores it. */
msg = WM_NULL;
/* Interrupt any blocking system calls. */
signal_quit ();
}
}
return wparam;
my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
}
/* Main message dispatch loop. */
......@@ -3189,6 +3365,8 @@ static void
w32_msg_pump (deferred_msg * msg_buf)
{
MSG msg;
int result;
HWND focus_window;
msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
......@@ -3207,9 +3385,31 @@ w32_msg_pump (deferred_msg * msg_buf)
SetThreadLocale (msg.wParam);
/* Reply is not expected. */
break;
case WM_EMACS_SETKEYBOARDLAYOUT:
result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
result, 0))
abort ();
break;
case WM_EMACS_REGISTER_HOT_KEY:
focus_window = GetFocus ();
if (focus_window != NULL)
RegisterHotKey (focus_window,
HOTKEY_ID (msg.wParam),
HOTKEY_MODIFIERS (msg.wParam),
HOTKEY_VK_CODE (msg.wParam));
/* Reply is not expected. */
break;
case WM_EMACS_UNREGISTER_HOT_KEY:
focus_window = GetFocus ();
if (focus_window != NULL)
UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
/* Mark item as erased. */
XCAR ((Lisp_Object) msg.lParam) = Qnil;
if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
abort ();
break;
default:
/* No need to be so draconian! */
/* abort (); */
DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
}
}
......@@ -3326,8 +3526,6 @@ w32_msg_worker (dw)
/* Main window procedure */
extern char *lispy_function_keys[];
LRESULT CALLBACK
w32_wnd_proc (hwnd, msg, wParam, lParam)
HWND hwnd;
......@@ -3392,6 +3590,43 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
return (0);
}
case WM_INPUTLANGCHANGE:
/* Inform lisp thread of keyboard layout changes. */
my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
/* Clear dead keys in the keyboard state; for simplicity only
preserve modifier key states. */
{
int i;
BYTE keystate[256];
GetKeyboardState (keystate);
for (i = 0; i < 256; i++)
if (1
&& i != VK_SHIFT
&& i != VK_LSHIFT
&& i != VK_RSHIFT
&& i != VK_CAPITAL
&& i != VK_NUMLOCK
&& i != VK_SCROLL
&& i != VK_CONTROL
&& i != VK_LCONTROL
&& i != VK_RCONTROL
&& i != VK_MENU
&& i != VK_LMENU
&& i != VK_RMENU
&& i != VK_LWIN
&& i != VK_RWIN)
keystate[i] = 0;
SetKeyboardState (keystate);
}
goto dflt;
case WM_HOTKEY:
/* Synchronize hot keys with normal input. */
PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
return (0);
case WM_KEYUP:
case WM_SYSKEYUP:
record_keyup (wParam, lParam);
......@@ -3399,40 +3634,161 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
/* Ignore keystrokes we fake ourself; see below. */
if (dpyinfo->faked_key == wParam)
{
dpyinfo->faked_key = 0;
return 0;
}
/* Synchronize modifiers with current keystroke. */
sync_modifiers ();
record_keydown (wParam, lParam);
wParam = map_keypad_keys (wParam, lParam);
wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
windows_translate = 0;
switch (wParam) {
case VK_LWIN:
case VK_RWIN:
case VK_APPS:
/* More support for these keys will likely be necessary. */
if (!NILP (Vw32_pass_optional_keys_to_system))
switch (wParam)
{
case VK_LWIN:
if (NILP (Vw32_pass_lwindow_to_system))
{
/* Prevent system from acting on keyup (which opens the
Start menu if no other key was pressed) by simulating a
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 (!NILP (Vw32_lwindow_modifier))
return 0;
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 (!NILP (Vw32_rwindow_modifier))
return 0;
break;
case VK_APPS:
if (!NILP (Vw32_apps_modifier))
return 0;
break;
case VK_MENU:
if (NILP (Vw32_pass_alt_to_system))
return 0;
windows_translate = 1;
break;
case VK_MENU:
if (NILP (Vw32_pass_alt_to_system))
break;
case VK_CAPITAL:
/* 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_CONTROL:
case VK_CAPITAL:
case VK_SHIFT:
case VK_NUMLOCK:
case VK_SCROLL:
windows_translate = 1;
break;
default:
/* If not defined as a function key, change it to a WM_CHAR message. */
if (lispy_function_keys[wParam] == 0)
msg = WM_CHAR;
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;
case VK_SCROLL:
/* Decide whether to treat as modifier or function key. */
if (NILP (Vw32_scroll_lock_modifier))
goto disable_lock_key;
return 0;
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);
}
break;
case VK_CONTROL:
case VK_SHIFT:
case VK_PROCESSKEY: /* Generated by IME. */
windows_translate = 1;
break;
default:
/* If not defined as a function key, change it to a WM_CHAR message. */
if (lispy_function_keys[wParam] == 0)
{
if (!NILP (Vw32_recognize_altgr)
&& modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
{
/* Always let TranslateMessage handle AltGr key chords;
for some reason, ToAscii doesn't always process AltGr
chords correctly. */
windows_translate = 1;
}
else if (modifier_set (VK_CONTROL) || modifier_set (VK_MENU))
{
/* 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,
so the user doesn't need to constantly switch
layout to type control or meta keystrokes when
the normal layout translates alphabetic
characters to non-ascii characters. */
if (!modifier_set (VK_SHIFT))
wParam += ('a' - 'A');
msg = WM_CHAR;
}
else
{
/* Try to handle other keystrokes by determining the
base character (ie. translating the base key plus
shift modifier). */
int add;
int isdead = 0;
KEY_EVENT_RECORD key;
key.bKeyDown = TRUE;
key.wRepeatCount = 1;
key.wVirtualKeyCode = wParam;
key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
key.uChar.AsciiChar = 0;
key.dwControlKeyState = construct_console_modifiers ();
add = w32_kbd_patch_key (&key);
/* 0 means an unrecognised keycode, negative means
dead key. Ignore both. */
while (--add >= 0)
{
/* Forward asciified character sequence. */
post_character_message
(hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
w32_get_key_modifiers (wParam, lParam));
w32_kbd_patch_key (&key);
}
return 0;
}
}
else
{
/* Let TranslateMessage handle everything else. */
windows_translate = 1;
}
}
}
if (windows_translate)
{
......@@ -3447,36 +3803,8 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
case WM_SYSCHAR:
case WM_CHAR:
wmsg.dwModifiers = construct_modifiers (wParam, lParam);
#if 1
/* Detect quit_char and set quit-flag directly. Note that we
still need to post a message to ensure the main thread will be
woken up if blocked in sys_select(), but we do NOT want to post
the quit_char message itself (because it will usually be as if
the user had typed quit_char twice). Instead, we post a dummy
message that has no particular effect. */
{
int c = wParam;
if (isalpha (c) && (wmsg.dwModifiers == LEFT_CTRL_PRESSED
|| wmsg.dwModifiers == RIGHT_CTRL_PRESSED))
c = make_ctrl_char (c) & 0377;
if (c == quit_char)
{
Vquit_flag = Qt;
/* The choice of message is somewhat arbitrary, as long as
the main thread handler just ignores it. */
msg = WM_NULL;
/* Interrupt any blocking system calls. */
signal_quit ();
}
}
#endif
my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
post_character_message (hwnd, msg, wParam, lParam,
w32_get_key_modifiers (wParam, lParam));
break;
/* Simulate middle mouse button events when left and right buttons
......@@ -3817,8 +4145,10 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
goto dflt;
#endif
case WM_ACTIVATE:
case WM_ACTIVATEAPP:
dpyinfo->faked_key = 0;
reset_modifiers ();
case WM_ACTIVATE:
case WM_WINDOWPOSCHANGED:
case WM_SHOWWINDOW:
/* Inform lisp thread that a frame might have just been obscured
......@@ -3827,11 +4157,14 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
goto dflt;
case WM_SETFOCUS:
reset_modifiers ();
register_hot_keys (hwnd);
goto command;
case WM_KILLFOCUS:
unregister_hot_keys (hwnd);
case WM_MOVE:
case WM_SIZE:
case WM_COMMAND:
command:
wmsg.dwModifiers = w32_get_modifiers ();
my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
goto dflt;
......@@ -6086,6 +6419,187 @@ If optional parameter FRAME is not specified, use selected frame.")
return Qnil;
}
/* Lookup virtual keycode from string representing the name of a
non-ascii keystroke into the corresponding virtual key, using
lispy_function_keys. */
static int
lookup_vk_code (char *key)
{
int i;
for (i = 0; i < 256; i++)
if (lispy_function_keys[i] != 0
&& strcmp (lispy_function_keys[i], key) == 0)
return i;
return -1;
}
/* Convert a one-element vector style key sequence to a hot key
definition. */
static int
w32_parse_hot_key (key)
Lisp_Object key;
{
/* Copied from Fdefine_key and store_in_keymap. */
register Lisp_Object c;