1 /* Input event support for Emacs on the Microsoft W32 API.
2 Copyright (C) 1992-1993, 1995, 2001-2011 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
21 Adapted from ntkbd.c by Tim Fleehart
37 #include "dispextern.h"
38 #include "blockinput.h"
39 #include "termhooks.h"
43 /* stdin, from w32console.c */
44 extern HANDLE keyboard_handle
;
46 /* Info for last mouse motion */
47 static COORD movement_pos
;
48 static DWORD movement_time
;
51 extern unsigned int map_keypad_keys (unsigned int, unsigned int);
52 extern unsigned int w32_key_to_modifier (int key
);
55 #define EVENT_QUEUE_SIZE 50
56 static INPUT_RECORD event_queue
[EVENT_QUEUE_SIZE
];
57 static INPUT_RECORD
*queue_ptr
= event_queue
, *queue_end
= event_queue
;
59 /* Temporarily store lead byte of DBCS input sequences. */
60 static char dbcs_lead
= 0;
63 fill_queue (BOOL block
)
68 if (queue_ptr
< queue_end
)
69 return queue_end
-queue_ptr
;
73 /* Check to see if there are some events to read before we try
74 because we can't block. */
75 if (!GetNumberOfConsoleInputEvents (keyboard_handle
, &events_waiting
))
77 if (events_waiting
== 0)
81 rc
= ReadConsoleInput (keyboard_handle
, event_queue
, EVENT_QUEUE_SIZE
,
85 queue_ptr
= event_queue
;
86 queue_end
= event_queue
+ events_waiting
;
87 return (int) events_waiting
;
90 /* In a generic, multi-frame world this should take a console handle
91 and return the frame for it
93 Right now, there's only one frame so return it. */
97 return SELECTED_FRAME ();
100 /* Translate console modifiers to emacs modifiers.
101 German keyboard support (Kai Morgan Zeise 2/18/95). */
103 w32_kbd_mods_to_emacs (DWORD mods
, WORD key
)
107 /* If we recognize right-alt and left-ctrl as AltGr, and it has been
108 pressed, first remove those modifiers. */
109 if (!NILP (Vw32_recognize_altgr
)
110 && (mods
& (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
))
111 == (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
))
112 mods
&= ~ (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
);
114 if (mods
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
))
115 retval
= ((NILP (Vw32_alt_is_meta
)) ? alt_modifier
: meta_modifier
);
117 if (mods
& (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
119 retval
|= ctrl_modifier
;
120 if ((mods
& (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
121 == (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
122 retval
|= meta_modifier
;
125 if (mods
& LEFT_WIN_PRESSED
)
126 retval
|= w32_key_to_modifier (VK_LWIN
);
127 if (mods
& RIGHT_WIN_PRESSED
)
128 retval
|= w32_key_to_modifier (VK_RWIN
);
129 if (mods
& APPS_PRESSED
)
130 retval
|= w32_key_to_modifier (VK_APPS
);
131 if (mods
& SCROLLLOCK_ON
)
132 retval
|= w32_key_to_modifier (VK_SCROLL
);
134 /* Just in case someone wanted the original behavior, make it
135 optional by setting w32-capslock-is-shiftlock to t. */
136 if (NILP (Vw32_capslock_is_shiftlock
)
137 /* Keys that should _not_ be affected by CapsLock. */
138 && ( (key
== VK_BACK
)
141 || (key
== VK_RETURN
)
142 || (key
== VK_ESCAPE
)
143 || ((key
>= VK_SPACE
) && (key
<= VK_HELP
))
144 || ((key
>= VK_NUMPAD0
) && (key
<= VK_F24
))
145 || ((key
>= VK_NUMPAD_CLEAR
) && (key
<= VK_NUMPAD_DELETE
))
148 /* Only consider shift state. */
149 if ((mods
& SHIFT_PRESSED
) != 0)
150 retval
|= shift_modifier
;
154 /* Ignore CapsLock state if not enabled. */
155 if (NILP (Vw32_enable_caps_lock
))
156 mods
&= ~CAPSLOCK_ON
;
157 if ((mods
& (SHIFT_PRESSED
| CAPSLOCK_ON
)) != 0)
158 retval
|= shift_modifier
;
165 /* Return nonzero if the virtual key is a dead key. */
167 is_dead_key (int wparam
)
169 unsigned int code
= MapVirtualKey (wparam
, 2);
171 /* Windows 95 returns 0x8000, NT returns 0x80000000. */
172 return (code
& 0x80008000) ? 1 : 0;
176 /* The return code indicates key code size. */
178 w32_kbd_patch_key (KEY_EVENT_RECORD
*event
)
180 unsigned int key_code
= event
->wVirtualKeyCode
;
181 unsigned int mods
= event
->dwControlKeyState
;
183 static BYTE ansi_code
[4];
184 static int isdead
= 0;
188 event
->uChar
.AsciiChar
= ansi_code
[2];
192 if (event
->uChar
.AsciiChar
!= 0)
195 memset (keystate
, 0, sizeof (keystate
));
196 keystate
[key_code
] = 0x80;
197 if (mods
& SHIFT_PRESSED
)
198 keystate
[VK_SHIFT
] = 0x80;
199 if (mods
& CAPSLOCK_ON
)
200 keystate
[VK_CAPITAL
] = 1;
201 /* If we recognize right-alt and left-ctrl as AltGr, set the key
202 states accordingly before invoking ToAscii. */
203 if (!NILP (Vw32_recognize_altgr
)
204 && (mods
& LEFT_CTRL_PRESSED
) && (mods
& RIGHT_ALT_PRESSED
))
206 keystate
[VK_CONTROL
] = 0x80;
207 keystate
[VK_LCONTROL
] = 0x80;
208 keystate
[VK_MENU
] = 0x80;
209 keystate
[VK_RMENU
] = 0x80;
213 /* Because of an OS bug, ToAscii corrupts the stack when called to
214 convert a dead key in console mode on NT4. Unfortunately, trying
215 to check for dead keys using MapVirtualKey doesn't work either -
216 these functions apparently use internal information about keyboard
217 layout which doesn't get properly updated in console programs when
218 changing layout (though apparently it gets partly updated,
219 otherwise ToAscii wouldn't crash). */
220 if (is_dead_key (event
->wVirtualKeyCode
))
224 /* On NT, call ToUnicode instead and then convert to the current
225 locale's default codepage. */
226 if (os_subtype
== OS_NT
)
230 isdead
= ToUnicode (event
->wVirtualKeyCode
, event
->wVirtualScanCode
,
231 keystate
, buf
, 128, 0);
237 event
->uChar
.UnicodeChar
= buf
[isdead
- 1];
239 GetLocaleInfo (GetThreadLocale (),
240 LOCALE_IDEFAULTANSICODEPAGE
, cp
, 20);
242 isdead
= WideCharToMultiByte (cpId
, 0, buf
, isdead
,
243 ansi_code
, 4, NULL
, NULL
);
250 isdead
= ToAscii (event
->wVirtualKeyCode
, event
->wVirtualScanCode
,
251 keystate
, (LPWORD
) ansi_code
, 0);
256 event
->uChar
.AsciiChar
= ansi_code
[0];
261 static int faked_key
= 0;
263 /* return code -1 means that event_queue_ptr won't be incremented.
264 In other word, this event makes two key codes. (by himi) */
266 key_event (KEY_EVENT_RECORD
*event
, struct input_event
*emacs_ev
, int *isdead
)
268 static int mod_key_state
= 0;
273 /* Skip key-up events. */
274 if (!event
->bKeyDown
)
276 switch (event
->wVirtualKeyCode
)
279 mod_key_state
&= ~LEFT_WIN_PRESSED
;
282 mod_key_state
&= ~RIGHT_WIN_PRESSED
;
285 mod_key_state
&= ~APPS_PRESSED
;
291 /* Ignore keystrokes we fake ourself; see below. */
292 if (faked_key
== event
->wVirtualKeyCode
)
298 /* To make it easier to debug this code, ignore modifier keys! */
299 switch (event
->wVirtualKeyCode
)
302 if (NILP (Vw32_pass_lwindow_to_system
))
304 /* Prevent system from acting on keyup (which opens the Start
305 menu if no other key was pressed) by simulating a press of
306 Space which we will ignore. */
307 if ((mod_key_state
& LEFT_WIN_PRESSED
) == 0)
309 if (NUMBERP (Vw32_phantom_key_code
))
310 faked_key
= XUINT (Vw32_phantom_key_code
) & 255;
312 faked_key
= VK_SPACE
;
313 keybd_event (faked_key
, (BYTE
) MapVirtualKey (faked_key
, 0), 0, 0);
316 mod_key_state
|= LEFT_WIN_PRESSED
;
317 if (!NILP (Vw32_lwindow_modifier
))
321 if (NILP (Vw32_pass_rwindow_to_system
))
323 if ((mod_key_state
& RIGHT_WIN_PRESSED
) == 0)
325 if (NUMBERP (Vw32_phantom_key_code
))
326 faked_key
= XUINT (Vw32_phantom_key_code
) & 255;
328 faked_key
= VK_SPACE
;
329 keybd_event (faked_key
, (BYTE
) MapVirtualKey (faked_key
, 0), 0, 0);
332 mod_key_state
|= RIGHT_WIN_PRESSED
;
333 if (!NILP (Vw32_rwindow_modifier
))
337 mod_key_state
|= APPS_PRESSED
;
338 if (!NILP (Vw32_apps_modifier
))
342 /* Decide whether to treat as modifier or function key. */
343 if (NILP (Vw32_enable_caps_lock
))
344 goto disable_lock_key
;
347 /* Decide whether to treat as modifier or function key. */
348 if (NILP (Vw32_enable_num_lock
))
349 goto disable_lock_key
;
352 /* Decide whether to treat as modifier or function key. */
353 if (NILP (Vw32_scroll_lock_modifier
))
354 goto disable_lock_key
;
357 /* Ensure the appropriate lock key state is off (and the
358 indicator light as well). */
359 wParam
= event
->wVirtualKeyCode
;
360 if (GetAsyncKeyState (wParam
) & 0x8000)
362 /* Fake another press of the relevant key. Apparently, this
363 really is the only way to turn off the indicator. */
365 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
366 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
367 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
368 KEYEVENTF_EXTENDEDKEY
| 0, 0);
369 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
370 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
378 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
379 which is confusing for purposes of key binding; convert
380 VK_CANCEL events into VK_PAUSE events. */
381 event
->wVirtualKeyCode
= VK_PAUSE
;
384 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
385 for purposes of key binding; convert these back into
386 VK_NUMLOCK events, at least when we want to see NumLock key
387 presses. (Note that there is never any possibility that
388 VK_PAUSE with Ctrl really is C-Pause as per above.) */
389 if (NILP (Vw32_enable_num_lock
)
390 && (event
->dwControlKeyState
391 & (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
)) != 0)
392 event
->wVirtualKeyCode
= VK_NUMLOCK
;
396 /* Recognize state of Windows and Apps keys. */
397 event
->dwControlKeyState
|= mod_key_state
;
399 /* Distinguish numeric keypad keys from extended keys. */
400 event
->wVirtualKeyCode
=
401 map_keypad_keys (event
->wVirtualKeyCode
,
402 (event
->dwControlKeyState
& ENHANCED_KEY
));
404 if (lispy_function_keys
[event
->wVirtualKeyCode
] == 0)
406 if (!NILP (Vw32_recognize_altgr
)
407 && (event
->dwControlKeyState
& LEFT_CTRL_PRESSED
)
408 && (event
->dwControlKeyState
& RIGHT_ALT_PRESSED
))
410 /* Don't try to interpret AltGr key chords; ToAscii seems not
411 to process them correctly. */
413 /* Handle key chords including any modifiers other than shift
414 directly, in order to preserve as much modifier information as
416 else if (event
->dwControlKeyState
417 & ( RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
418 | RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
419 | (!NILP (Vw32_lwindow_modifier
) ? LEFT_WIN_PRESSED
: 0)
420 | (!NILP (Vw32_rwindow_modifier
) ? RIGHT_WIN_PRESSED
: 0)
421 | (!NILP (Vw32_apps_modifier
) ? APPS_PRESSED
: 0)
422 | (!NILP (Vw32_scroll_lock_modifier
) ? SCROLLLOCK_ON
: 0)))
424 /* Don't translate modified alphabetic keystrokes, so the user
425 doesn't need to constantly switch layout to type control or
426 meta keystrokes when the normal layout translates
427 alphabetic characters to non-ascii characters. */
428 if ('A' <= event
->wVirtualKeyCode
&& event
->wVirtualKeyCode
<= 'Z')
430 event
->uChar
.AsciiChar
= event
->wVirtualKeyCode
;
431 if ((event
->dwControlKeyState
& SHIFT_PRESSED
) == 0)
432 event
->uChar
.AsciiChar
+= ('a' - 'A');
434 /* Try to handle unrecognized keystrokes by determining the
435 base character (ie. translating the base key plus shift
437 else if (event
->uChar
.AsciiChar
== 0)
438 w32_kbd_patch_key (event
);
441 if (event
->uChar
.AsciiChar
== 0)
443 emacs_ev
->kind
= NO_EVENT
;
446 else if (event
->uChar
.AsciiChar
> 0)
448 emacs_ev
->kind
= ASCII_KEYSTROKE_EVENT
;
449 emacs_ev
->code
= event
->uChar
.AsciiChar
;
451 else if (event
->uChar
.UnicodeChar
> 0)
453 emacs_ev
->kind
= MULTIBYTE_CHAR_KEYSTROKE_EVENT
;
454 emacs_ev
->code
= event
->uChar
.UnicodeChar
;
458 /* Fallback for non-Unicode versions of Windows. */
464 /* Get the codepage to interpret this key with. */
465 GetLocaleInfo (GetThreadLocale (),
466 LOCALE_IDEFAULTANSICODEPAGE
, cp
, 20);
470 dbcs
[1] = event
->uChar
.AsciiChar
;
474 if (!MultiByteToWideChar (cpId
, 0, dbcs
, 2, &code
, 1))
477 DebPrint (("Invalid DBCS sequence: %d %d\n",
479 emacs_ev
->kind
= NO_EVENT
;
482 else if (IsDBCSLeadByteEx (cpId
, dbcs
[1]))
485 emacs_ev
->kind
= NO_EVENT
;
489 if (!MultiByteToWideChar (cpId
, 0, &dbcs
[1], 1, &code
, 1))
492 DebPrint (("Invalid character: %d\n", dbcs
[1]));
493 emacs_ev
->kind
= NO_EVENT
;
496 emacs_ev
->kind
= MULTIBYTE_CHAR_KEYSTROKE_EVENT
;
497 emacs_ev
->code
= code
;
502 emacs_ev
->kind
= NON_ASCII_KEYSTROKE_EVENT
;
503 emacs_ev
->code
= event
->wVirtualKeyCode
;
506 XSETFRAME (emacs_ev
->frame_or_window
, get_frame ());
507 emacs_ev
->modifiers
= w32_kbd_mods_to_emacs (event
->dwControlKeyState
,
508 event
->wVirtualKeyCode
);
509 emacs_ev
->timestamp
= GetTickCount ();
514 w32_console_toggle_lock_key (int vk_code
, Lisp_Object new_state
)
516 int cur_state
= (GetKeyState (vk_code
) & 1);
519 || (NUMBERP (new_state
)
520 && ((XUINT (new_state
)) & 1) != cur_state
))
524 keybd_event ((BYTE
) vk_code
,
525 (BYTE
) MapVirtualKey (vk_code
, 0),
526 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
527 keybd_event ((BYTE
) vk_code
,
528 (BYTE
) MapVirtualKey (vk_code
, 0),
529 KEYEVENTF_EXTENDEDKEY
| 0, 0);
530 keybd_event ((BYTE
) vk_code
,
531 (BYTE
) MapVirtualKey (vk_code
, 0),
532 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
533 cur_state
= !cur_state
;
539 /* Mouse position hook. */
541 w32_console_mouse_position (FRAME_PTR
*f
,
543 Lisp_Object
*bar_window
,
544 enum scroll_bar_part
*part
,
556 SELECTED_FRAME ()->mouse_moved
= 0;
558 XSETINT (*x
, movement_pos
.X
);
559 XSETINT (*y
, movement_pos
.Y
);
560 *time
= movement_time
;
565 /* Remember mouse motion and notify emacs. */
567 mouse_moved_to (int x
, int y
)
569 /* If we're in the same place, ignore it */
570 if (x
!= movement_pos
.X
|| y
!= movement_pos
.Y
)
572 SELECTED_FRAME ()->mouse_moved
= 1;
575 movement_time
= GetTickCount ();
579 /* Consoles return button bits in a strange order:
580 least significant - Leftmost button
581 next - Rightmost button
585 Assume emacs likes three button mice, so
589 Others increase from there. */
591 #define NUM_TRANSLATED_MOUSE_BUTTONS 3
592 static int emacs_button_translation
[NUM_TRANSLATED_MOUSE_BUTTONS
] =
598 do_mouse_event (MOUSE_EVENT_RECORD
*event
,
599 struct input_event
*emacs_ev
)
601 static DWORD button_state
= 0;
602 DWORD but_change
, mask
;
605 if (event
->dwEventFlags
== MOUSE_MOVED
)
607 /* For movement events we just note that the mouse has moved
608 so that emacs will generate drag events. */
609 mouse_moved_to (event
->dwMousePosition
.X
, event
->dwMousePosition
.Y
);
613 /* It looks like the console code sends us a mouse event with
614 dwButtonState == 0 when a window is activated. Ignore this case. */
615 if (event
->dwButtonState
== button_state
)
618 emacs_ev
->kind
= MOUSE_CLICK_EVENT
;
620 /* Find out what button has changed state since the last button event. */
621 but_change
= button_state
^ event
->dwButtonState
;
623 for (i
= 0; mask
; i
++, mask
<<= 1)
624 if (but_change
& mask
)
626 if (i
< NUM_TRANSLATED_MOUSE_BUTTONS
)
627 emacs_ev
->code
= emacs_button_translation
[i
];
633 button_state
= event
->dwButtonState
;
634 emacs_ev
->timestamp
= GetTickCount ();
635 emacs_ev
->modifiers
= w32_kbd_mods_to_emacs (event
->dwControlKeyState
, 0) |
636 ((event
->dwButtonState
& mask
) ? down_modifier
: up_modifier
);
638 XSETFASTINT (emacs_ev
->x
, event
->dwMousePosition
.X
);
639 XSETFASTINT (emacs_ev
->y
, event
->dwMousePosition
.Y
);
640 /* for Mule 2.2 (Based on Emacs 19.28 */
642 XSET (emacs_ev
->frame_or_window
, Lisp_Frame
, get_frame ());
644 XSETFRAME (emacs_ev
->frame_or_window
, get_frame ());
651 resize_event (WINDOW_BUFFER_SIZE_RECORD
*event
)
653 FRAME_PTR f
= get_frame ();
655 change_frame_size (f
, event
->dwSize
.Y
, event
->dwSize
.X
, 0, 1, 0);
656 SET_FRAME_GARBAGED (f
);
660 maybe_generate_resize_event (void)
662 CONSOLE_SCREEN_BUFFER_INFO info
;
663 FRAME_PTR f
= get_frame ();
665 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE
), &info
);
667 /* It is okay to call this unconditionally, since it will do nothing
668 if the size hasn't actually changed. */
669 change_frame_size (f
,
670 1 + info
.srWindow
.Bottom
- info
.srWindow
.Top
,
671 1 + info
.srWindow
.Right
- info
.srWindow
.Left
,
676 w32_console_read_socket (struct terminal
*terminal
,
678 struct input_event
*hold_quit
)
680 int nev
, ret
= 0, add
;
683 if (interrupt_input_blocked
)
685 interrupt_input_pending
= 1;
689 interrupt_input_pending
= 0;
694 nev
= fill_queue (0);
697 /* If nev == -1, there was some kind of error
698 If nev == 0 then waitp must be zero and no events were available
706 struct input_event inev
;
709 inev
.kind
= NO_EVENT
;
712 switch (queue_ptr
->EventType
)
715 add
= key_event (&queue_ptr
->Event
.KeyEvent
, &inev
, &isdead
);
716 if (add
== -1) /* 95.7.25 by himi */
722 kbd_buffer_store_event_hold (&inev
, hold_quit
);
726 add
= do_mouse_event (&queue_ptr
->Event
.MouseEvent
, &inev
);
728 kbd_buffer_store_event_hold (&inev
, hold_quit
);
731 case WINDOW_BUFFER_SIZE_EVENT
:
732 if (w32_use_full_screen_buffer
)
733 resize_event (&queue_ptr
->Event
.WindowBufferSizeEvent
);
738 /* Internal event types, ignored. */
746 if (ret
> 0 || expected
== 0)
750 /* We don't get told about changes in the window size (only the buffer
751 size, which we no longer care about), so we have to check it
753 if (!w32_use_full_screen_buffer
)
754 maybe_generate_resize_event ();