1 /* Input event support for Emacs on the Microsoft W32 API.
2 Copyright (C) 1992, 1993, 1995, 2001, 2002, 2003, 2004, 2005, 2006,
3 2007, 2008 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
22 Adapted from ntkbd.c by Tim Fleehart
41 #include "blockinput.h"
42 #include "termhooks.h"
46 /* stdin, from ntterm */
47 extern HANDLE keyboard_handle
;
49 /* Info for last mouse motion */
50 static COORD movement_pos
;
51 static DWORD movement_time
;
54 extern void reinvoke_input_signal (void);
56 /* from w32console.c */
57 extern int w32_use_full_screen_buffer
;
60 extern Lisp_Object Vw32_alt_is_meta
;
61 extern unsigned int map_keypad_keys (unsigned int, unsigned int);
64 extern Lisp_Object Vw32_capslock_is_shiftlock
;
65 extern Lisp_Object Vw32_enable_caps_lock
;
66 extern Lisp_Object Vw32_enable_num_lock
;
67 extern Lisp_Object Vw32_recognize_altgr
;
68 extern Lisp_Object Vw32_pass_lwindow_to_system
;
69 extern Lisp_Object Vw32_pass_rwindow_to_system
;
70 extern Lisp_Object Vw32_phantom_key_code
;
71 extern Lisp_Object Vw32_lwindow_modifier
;
72 extern Lisp_Object Vw32_rwindow_modifier
;
73 extern Lisp_Object Vw32_apps_modifier
;
74 extern Lisp_Object Vw32_scroll_lock_modifier
;
75 extern unsigned int w32_key_to_modifier (int key
);
78 #define EVENT_QUEUE_SIZE 50
79 static INPUT_RECORD event_queue
[EVENT_QUEUE_SIZE
];
80 static INPUT_RECORD
*queue_ptr
= event_queue
, *queue_end
= event_queue
;
83 fill_queue (BOOL block
)
88 if (queue_ptr
< queue_end
)
89 return queue_end
-queue_ptr
;
93 /* Check to see if there are some events to read before we try
94 because we can't block. */
95 if (!GetNumberOfConsoleInputEvents (keyboard_handle
, &events_waiting
))
97 if (events_waiting
== 0)
101 rc
= ReadConsoleInput (keyboard_handle
, event_queue
, EVENT_QUEUE_SIZE
,
105 queue_ptr
= event_queue
;
106 queue_end
= event_queue
+ events_waiting
;
107 return (int) events_waiting
;
110 /* In a generic, multi-frame world this should take a console handle
111 and return the frame for it
113 Right now, there's only one frame so return it. */
117 return SELECTED_FRAME ();
120 /* Translate console modifiers to emacs modifiers.
121 German keyboard support (Kai Morgan Zeise 2/18/95). */
123 w32_kbd_mods_to_emacs (DWORD mods
, WORD key
)
127 /* If we recognize right-alt and left-ctrl as AltGr, and it has been
128 pressed, first remove those modifiers. */
129 if (!NILP (Vw32_recognize_altgr
)
130 && (mods
& (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
))
131 == (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
))
132 mods
&= ~ (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
);
134 if (mods
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
))
135 retval
= ((NILP (Vw32_alt_is_meta
)) ? alt_modifier
: meta_modifier
);
137 if (mods
& (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
139 retval
|= ctrl_modifier
;
140 if ((mods
& (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
141 == (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
142 retval
|= meta_modifier
;
145 if (mods
& LEFT_WIN_PRESSED
)
146 retval
|= w32_key_to_modifier (VK_LWIN
);
147 if (mods
& RIGHT_WIN_PRESSED
)
148 retval
|= w32_key_to_modifier (VK_RWIN
);
149 if (mods
& APPS_PRESSED
)
150 retval
|= w32_key_to_modifier (VK_APPS
);
151 if (mods
& SCROLLLOCK_ON
)
152 retval
|= w32_key_to_modifier (VK_SCROLL
);
154 /* Just in case someone wanted the original behavior, make it
155 optional by setting w32-capslock-is-shiftlock to t. */
156 if (NILP (Vw32_capslock_is_shiftlock
)
157 /* Keys that should _not_ be affected by CapsLock. */
158 && ( (key
== VK_BACK
)
161 || (key
== VK_RETURN
)
162 || (key
== VK_ESCAPE
)
163 || ((key
>= VK_SPACE
) && (key
<= VK_HELP
))
164 || ((key
>= VK_NUMPAD0
) && (key
<= VK_F24
))
165 || ((key
>= VK_NUMPAD_CLEAR
) && (key
<= VK_NUMPAD_DELETE
))
168 /* Only consider shift state. */
169 if ((mods
& SHIFT_PRESSED
) != 0)
170 retval
|= shift_modifier
;
174 /* Ignore CapsLock state if not enabled. */
175 if (NILP (Vw32_enable_caps_lock
))
176 mods
&= ~CAPSLOCK_ON
;
177 if ((mods
& (SHIFT_PRESSED
| CAPSLOCK_ON
)) != 0)
178 retval
|= shift_modifier
;
185 /* Return nonzero if the virtual key is a dead key. */
187 is_dead_key (int wparam
)
189 unsigned int code
= MapVirtualKey (wparam
, 2);
191 /* Windows 95 returns 0x8000, NT returns 0x80000000. */
192 return (code
& 0x80008000) ? 1 : 0;
196 /* The return code indicates key code size. */
198 w32_kbd_patch_key (KEY_EVENT_RECORD
*event
)
200 unsigned int key_code
= event
->wVirtualKeyCode
;
201 unsigned int mods
= event
->dwControlKeyState
;
203 static BYTE ansi_code
[4];
204 static int isdead
= 0;
208 event
->uChar
.AsciiChar
= ansi_code
[2];
212 if (event
->uChar
.AsciiChar
!= 0)
215 memset (keystate
, 0, sizeof (keystate
));
216 keystate
[key_code
] = 0x80;
217 if (mods
& SHIFT_PRESSED
)
218 keystate
[VK_SHIFT
] = 0x80;
219 if (mods
& CAPSLOCK_ON
)
220 keystate
[VK_CAPITAL
] = 1;
221 /* If we recognize right-alt and left-ctrl as AltGr, set the key
222 states accordingly before invoking ToAscii. */
223 if (!NILP (Vw32_recognize_altgr
)
224 && (mods
& LEFT_CTRL_PRESSED
) && (mods
& RIGHT_ALT_PRESSED
))
226 keystate
[VK_CONTROL
] = 0x80;
227 keystate
[VK_LCONTROL
] = 0x80;
228 keystate
[VK_MENU
] = 0x80;
229 keystate
[VK_RMENU
] = 0x80;
233 /* Because of an OS bug, ToAscii corrupts the stack when called to
234 convert a dead key in console mode on NT4. Unfortunately, trying
235 to check for dead keys using MapVirtualKey doesn't work either -
236 these functions apparently use internal information about keyboard
237 layout which doesn't get properly updated in console programs when
238 changing layout (though apparently it gets partly updated,
239 otherwise ToAscii wouldn't crash). */
240 if (is_dead_key (event
->wVirtualKeyCode
))
244 /* On NT, call ToUnicode instead and then convert to the current
245 locale's default codepage. */
246 if (os_subtype
== OS_NT
)
250 isdead
= ToUnicode (event
->wVirtualKeyCode
, event
->wVirtualScanCode
,
251 keystate
, buf
, 128, 0);
257 GetLocaleInfo (GetThreadLocale (),
258 LOCALE_IDEFAULTANSICODEPAGE
, cp
, 20);
260 isdead
= WideCharToMultiByte (cpId
, 0, buf
, isdead
,
261 ansi_code
, 4, NULL
, NULL
);
268 isdead
= ToAscii (event
->wVirtualKeyCode
, event
->wVirtualScanCode
,
269 keystate
, (LPWORD
) ansi_code
, 0);
274 event
->uChar
.AsciiChar
= ansi_code
[0];
279 extern char *lispy_function_keys
[];
281 static int faked_key
= 0;
283 /* return code -1 means that event_queue_ptr won't be incremented.
284 In other word, this event makes two key codes. (by himi) */
286 key_event (KEY_EVENT_RECORD
*event
, struct input_event
*emacs_ev
, int *isdead
)
288 static int mod_key_state
= 0;
293 /* Skip key-up events. */
294 if (!event
->bKeyDown
)
296 switch (event
->wVirtualKeyCode
)
299 mod_key_state
&= ~LEFT_WIN_PRESSED
;
302 mod_key_state
&= ~RIGHT_WIN_PRESSED
;
305 mod_key_state
&= ~APPS_PRESSED
;
311 /* Ignore keystrokes we fake ourself; see below. */
312 if (faked_key
== event
->wVirtualKeyCode
)
318 /* To make it easier to debug this code, ignore modifier keys! */
319 switch (event
->wVirtualKeyCode
)
322 if (NILP (Vw32_pass_lwindow_to_system
))
324 /* Prevent system from acting on keyup (which opens the Start
325 menu if no other key was pressed) by simulating a press of
326 Space which we will ignore. */
327 if ((mod_key_state
& LEFT_WIN_PRESSED
) == 0)
329 if (NUMBERP (Vw32_phantom_key_code
))
330 faked_key
= XUINT (Vw32_phantom_key_code
) & 255;
332 faked_key
= VK_SPACE
;
333 keybd_event (faked_key
, (BYTE
) MapVirtualKey (faked_key
, 0), 0, 0);
336 mod_key_state
|= LEFT_WIN_PRESSED
;
337 if (!NILP (Vw32_lwindow_modifier
))
341 if (NILP (Vw32_pass_rwindow_to_system
))
343 if ((mod_key_state
& RIGHT_WIN_PRESSED
) == 0)
345 if (NUMBERP (Vw32_phantom_key_code
))
346 faked_key
= XUINT (Vw32_phantom_key_code
) & 255;
348 faked_key
= VK_SPACE
;
349 keybd_event (faked_key
, (BYTE
) MapVirtualKey (faked_key
, 0), 0, 0);
352 mod_key_state
|= RIGHT_WIN_PRESSED
;
353 if (!NILP (Vw32_rwindow_modifier
))
357 mod_key_state
|= APPS_PRESSED
;
358 if (!NILP (Vw32_apps_modifier
))
362 /* Decide whether to treat as modifier or function key. */
363 if (NILP (Vw32_enable_caps_lock
))
364 goto disable_lock_key
;
367 /* Decide whether to treat as modifier or function key. */
368 if (NILP (Vw32_enable_num_lock
))
369 goto disable_lock_key
;
372 /* Decide whether to treat as modifier or function key. */
373 if (NILP (Vw32_scroll_lock_modifier
))
374 goto disable_lock_key
;
377 /* Ensure the appropriate lock key state is off (and the
378 indicator light as well). */
379 wParam
= event
->wVirtualKeyCode
;
380 if (GetAsyncKeyState (wParam
) & 0x8000)
382 /* Fake another press of the relevant key. Apparently, this
383 really is the only way to turn off the indicator. */
385 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
386 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
387 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
388 KEYEVENTF_EXTENDEDKEY
| 0, 0);
389 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
390 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
398 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
399 which is confusing for purposes of key binding; convert
400 VK_CANCEL events into VK_PAUSE events. */
401 event
->wVirtualKeyCode
= VK_PAUSE
;
404 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
405 for purposes of key binding; convert these back into
406 VK_NUMLOCK events, at least when we want to see NumLock key
407 presses. (Note that there is never any possibility that
408 VK_PAUSE with Ctrl really is C-Pause as per above.) */
409 if (NILP (Vw32_enable_num_lock
)
410 && (event
->dwControlKeyState
411 & (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
)) != 0)
412 event
->wVirtualKeyCode
= VK_NUMLOCK
;
416 /* Recognize state of Windows and Apps keys. */
417 event
->dwControlKeyState
|= mod_key_state
;
419 /* Distinguish numeric keypad keys from extended keys. */
420 event
->wVirtualKeyCode
=
421 map_keypad_keys (event
->wVirtualKeyCode
,
422 (event
->dwControlKeyState
& ENHANCED_KEY
));
424 if (lispy_function_keys
[event
->wVirtualKeyCode
] == 0)
426 emacs_ev
->kind
= ASCII_KEYSTROKE_EVENT
;
428 if (!NILP (Vw32_recognize_altgr
)
429 && (event
->dwControlKeyState
& LEFT_CTRL_PRESSED
)
430 && (event
->dwControlKeyState
& RIGHT_ALT_PRESSED
))
432 /* Don't try to interpret AltGr key chords; ToAscii seems not
433 to process them correctly. */
435 /* Handle key chords including any modifiers other than shift
436 directly, in order to preserve as much modifier information as
438 else if (event
->dwControlKeyState
439 & ( RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
440 | RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
441 | (!NILP (Vw32_lwindow_modifier
) ? LEFT_WIN_PRESSED
: 0)
442 | (!NILP (Vw32_rwindow_modifier
) ? RIGHT_WIN_PRESSED
: 0)
443 | (!NILP (Vw32_apps_modifier
) ? APPS_PRESSED
: 0)
444 | (!NILP (Vw32_scroll_lock_modifier
) ? SCROLLLOCK_ON
: 0)))
446 /* Don't translate modified alphabetic keystrokes, so the user
447 doesn't need to constantly switch layout to type control or
448 meta keystrokes when the normal layout translates
449 alphabetic characters to non-ascii characters. */
450 if ('A' <= event
->wVirtualKeyCode
&& event
->wVirtualKeyCode
<= 'Z')
452 event
->uChar
.AsciiChar
= event
->wVirtualKeyCode
;
453 if ((event
->dwControlKeyState
& SHIFT_PRESSED
) == 0)
454 event
->uChar
.AsciiChar
+= ('a' - 'A');
456 /* Try to handle unrecognized keystrokes by determining the
457 base character (ie. translating the base key plus shift
459 else if (event
->uChar
.AsciiChar
== 0)
460 w32_kbd_patch_key (event
);
462 if (event
->uChar
.AsciiChar
== 0)
464 emacs_ev
->code
= event
->uChar
.AsciiChar
;
468 emacs_ev
->kind
= NON_ASCII_KEYSTROKE_EVENT
;
469 emacs_ev
->code
= event
->wVirtualKeyCode
;
472 XSETFRAME (emacs_ev
->frame_or_window
, get_frame ());
473 emacs_ev
->modifiers
= w32_kbd_mods_to_emacs (event
->dwControlKeyState
,
474 event
->wVirtualKeyCode
);
475 emacs_ev
->timestamp
= GetTickCount ();
480 w32_console_toggle_lock_key (int vk_code
, Lisp_Object new_state
)
482 int cur_state
= (GetKeyState (vk_code
) & 1);
485 || (NUMBERP (new_state
)
486 && ((XUINT (new_state
)) & 1) != cur_state
))
490 keybd_event ((BYTE
) vk_code
,
491 (BYTE
) MapVirtualKey (vk_code
, 0),
492 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
493 keybd_event ((BYTE
) vk_code
,
494 (BYTE
) MapVirtualKey (vk_code
, 0),
495 KEYEVENTF_EXTENDEDKEY
| 0, 0);
496 keybd_event ((BYTE
) vk_code
,
497 (BYTE
) MapVirtualKey (vk_code
, 0),
498 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
499 cur_state
= !cur_state
;
505 /* Mouse position hook. */
507 w32_console_mouse_position (FRAME_PTR
*f
,
509 Lisp_Object
*bar_window
,
510 enum scroll_bar_part
*part
,
522 SELECTED_FRAME ()->mouse_moved
= 0;
524 XSETINT(*x
, movement_pos
.X
);
525 XSETINT(*y
, movement_pos
.Y
);
526 *time
= movement_time
;
531 /* Remember mouse motion and notify emacs. */
533 mouse_moved_to (int x
, int y
)
535 /* If we're in the same place, ignore it */
536 if (x
!= movement_pos
.X
|| y
!= movement_pos
.Y
)
538 SELECTED_FRAME ()->mouse_moved
= 1;
541 movement_time
= GetTickCount ();
545 /* Consoles return button bits in a strange order:
546 least significant - Leftmost button
547 next - Rightmost button
551 Assume emacs likes three button mice, so
555 Others increase from there. */
557 #define NUM_TRANSLATED_MOUSE_BUTTONS 3
558 static int emacs_button_translation
[NUM_TRANSLATED_MOUSE_BUTTONS
] =
564 do_mouse_event (MOUSE_EVENT_RECORD
*event
,
565 struct input_event
*emacs_ev
)
567 static DWORD button_state
= 0;
568 DWORD but_change
, mask
;
571 if (event
->dwEventFlags
== MOUSE_MOVED
)
573 /* For movement events we just note that the mouse has moved
574 so that emacs will generate drag events. */
575 mouse_moved_to (event
->dwMousePosition
.X
, event
->dwMousePosition
.Y
);
579 /* It looks like the console code sends us a mouse event with
580 dwButtonState == 0 when a window is activated. Ignore this case. */
581 if (event
->dwButtonState
== button_state
)
584 emacs_ev
->kind
= MOUSE_CLICK_EVENT
;
586 /* Find out what button has changed state since the last button event. */
587 but_change
= button_state
^ event
->dwButtonState
;
589 for (i
= 0; mask
; i
++, mask
<<= 1)
590 if (but_change
& mask
)
592 if (i
< NUM_TRANSLATED_MOUSE_BUTTONS
)
593 emacs_ev
->code
= emacs_button_translation
[i
];
599 button_state
= event
->dwButtonState
;
600 emacs_ev
->timestamp
= GetTickCount ();
601 emacs_ev
->modifiers
= w32_kbd_mods_to_emacs (event
->dwControlKeyState
, 0) |
602 ((event
->dwButtonState
& mask
) ? down_modifier
: up_modifier
);
604 XSETFASTINT (emacs_ev
->x
, event
->dwMousePosition
.X
);
605 XSETFASTINT (emacs_ev
->y
, event
->dwMousePosition
.Y
);
606 /* for Mule 2.2 (Based on Emacs 19.28 */
608 XSET (emacs_ev
->frame_or_window
, Lisp_Frame
, get_frame ());
610 XSETFRAME (emacs_ev
->frame_or_window
, get_frame ());
617 resize_event (WINDOW_BUFFER_SIZE_RECORD
*event
)
619 FRAME_PTR f
= get_frame ();
621 change_frame_size (f
, event
->dwSize
.Y
, event
->dwSize
.X
, 0, 1, 0);
622 SET_FRAME_GARBAGED (f
);
626 maybe_generate_resize_event ()
628 CONSOLE_SCREEN_BUFFER_INFO info
;
629 FRAME_PTR f
= get_frame ();
631 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE
), &info
);
633 /* It is okay to call this unconditionally, since it will do nothing
634 if the size hasn't actually changed. */
635 change_frame_size (f
,
636 1 + info
.srWindow
.Bottom
- info
.srWindow
.Top
,
637 1 + info
.srWindow
.Right
- info
.srWindow
.Left
,
642 w32_console_read_socket (struct terminal
*terminal
,
644 struct input_event
*hold_quit
)
646 BOOL no_events
= TRUE
;
647 int nev
, ret
= 0, add
;
650 if (interrupt_input_blocked
)
652 interrupt_input_pending
= 1;
656 interrupt_input_pending
= 0;
661 nev
= fill_queue (0);
664 /* If nev == -1, there was some kind of error
665 If nev == 0 then waitp must be zero and no events were available
673 struct input_event inev
;
676 inev
.kind
= NO_EVENT
;
679 switch (queue_ptr
->EventType
)
682 add
= key_event (&queue_ptr
->Event
.KeyEvent
, &inev
, &isdead
);
683 if (add
== -1) /* 95.7.25 by himi */
689 kbd_buffer_store_event_hold (&inev
, hold_quit
);
693 add
= do_mouse_event (&queue_ptr
->Event
.MouseEvent
, &inev
);
695 kbd_buffer_store_event_hold (&inev
, hold_quit
);
698 case WINDOW_BUFFER_SIZE_EVENT
:
699 if (w32_use_full_screen_buffer
)
700 resize_event (&queue_ptr
->Event
.WindowBufferSizeEvent
);
705 /* Internal event types, ignored. */
713 if (ret
> 0 || expected
== 0)
717 /* We don't get told about changes in the window size (only the buffer
718 size, which we no longer care about), so we have to check it
720 if (!w32_use_full_screen_buffer
)
721 maybe_generate_resize_event ();
727 /* arch-tag: 0bcb39b7-d085-4b85-9070-6750e8c03047
728 (do not change this comment) */