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, 2009, 2010 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
42 #include "dispextern.h"
43 #include "blockinput.h"
44 #include "termhooks.h"
48 /* stdin, from ntterm */
49 extern HANDLE keyboard_handle
;
51 /* Info for last mouse motion */
52 static COORD movement_pos
;
53 static DWORD movement_time
;
56 extern void reinvoke_input_signal (void);
58 /* from w32console.c */
59 extern int w32_use_full_screen_buffer
;
62 extern Lisp_Object Vw32_alt_is_meta
;
63 extern unsigned int map_keypad_keys (unsigned int, unsigned int);
66 extern Lisp_Object Vw32_capslock_is_shiftlock
;
67 extern Lisp_Object Vw32_enable_caps_lock
;
68 extern Lisp_Object Vw32_enable_num_lock
;
69 extern Lisp_Object Vw32_recognize_altgr
;
70 extern Lisp_Object Vw32_pass_lwindow_to_system
;
71 extern Lisp_Object Vw32_pass_rwindow_to_system
;
72 extern Lisp_Object Vw32_phantom_key_code
;
73 extern Lisp_Object Vw32_lwindow_modifier
;
74 extern Lisp_Object Vw32_rwindow_modifier
;
75 extern Lisp_Object Vw32_apps_modifier
;
76 extern Lisp_Object Vw32_scroll_lock_modifier
;
77 extern unsigned int w32_key_to_modifier (int key
);
80 #define EVENT_QUEUE_SIZE 50
81 static INPUT_RECORD event_queue
[EVENT_QUEUE_SIZE
];
82 static INPUT_RECORD
*queue_ptr
= event_queue
, *queue_end
= event_queue
;
84 /* Temporarily store lead byte of DBCS input sequences. */
85 static char dbcs_lead
= 0;
88 fill_queue (BOOL block
)
93 if (queue_ptr
< queue_end
)
94 return queue_end
-queue_ptr
;
98 /* Check to see if there are some events to read before we try
99 because we can't block. */
100 if (!GetNumberOfConsoleInputEvents (keyboard_handle
, &events_waiting
))
102 if (events_waiting
== 0)
106 rc
= ReadConsoleInput (keyboard_handle
, event_queue
, EVENT_QUEUE_SIZE
,
110 queue_ptr
= event_queue
;
111 queue_end
= event_queue
+ events_waiting
;
112 return (int) events_waiting
;
115 /* In a generic, multi-frame world this should take a console handle
116 and return the frame for it
118 Right now, there's only one frame so return it. */
122 return SELECTED_FRAME ();
125 /* Translate console modifiers to emacs modifiers.
126 German keyboard support (Kai Morgan Zeise 2/18/95). */
128 w32_kbd_mods_to_emacs (DWORD mods
, WORD key
)
132 /* If we recognize right-alt and left-ctrl as AltGr, and it has been
133 pressed, first remove those modifiers. */
134 if (!NILP (Vw32_recognize_altgr
)
135 && (mods
& (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
))
136 == (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
))
137 mods
&= ~ (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
);
139 if (mods
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
))
140 retval
= ((NILP (Vw32_alt_is_meta
)) ? alt_modifier
: meta_modifier
);
142 if (mods
& (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
144 retval
|= ctrl_modifier
;
145 if ((mods
& (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
146 == (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
147 retval
|= meta_modifier
;
150 if (mods
& LEFT_WIN_PRESSED
)
151 retval
|= w32_key_to_modifier (VK_LWIN
);
152 if (mods
& RIGHT_WIN_PRESSED
)
153 retval
|= w32_key_to_modifier (VK_RWIN
);
154 if (mods
& APPS_PRESSED
)
155 retval
|= w32_key_to_modifier (VK_APPS
);
156 if (mods
& SCROLLLOCK_ON
)
157 retval
|= w32_key_to_modifier (VK_SCROLL
);
159 /* Just in case someone wanted the original behavior, make it
160 optional by setting w32-capslock-is-shiftlock to t. */
161 if (NILP (Vw32_capslock_is_shiftlock
)
162 /* Keys that should _not_ be affected by CapsLock. */
163 && ( (key
== VK_BACK
)
166 || (key
== VK_RETURN
)
167 || (key
== VK_ESCAPE
)
168 || ((key
>= VK_SPACE
) && (key
<= VK_HELP
))
169 || ((key
>= VK_NUMPAD0
) && (key
<= VK_F24
))
170 || ((key
>= VK_NUMPAD_CLEAR
) && (key
<= VK_NUMPAD_DELETE
))
173 /* Only consider shift state. */
174 if ((mods
& SHIFT_PRESSED
) != 0)
175 retval
|= shift_modifier
;
179 /* Ignore CapsLock state if not enabled. */
180 if (NILP (Vw32_enable_caps_lock
))
181 mods
&= ~CAPSLOCK_ON
;
182 if ((mods
& (SHIFT_PRESSED
| CAPSLOCK_ON
)) != 0)
183 retval
|= shift_modifier
;
190 /* Return nonzero if the virtual key is a dead key. */
192 is_dead_key (int wparam
)
194 unsigned int code
= MapVirtualKey (wparam
, 2);
196 /* Windows 95 returns 0x8000, NT returns 0x80000000. */
197 return (code
& 0x80008000) ? 1 : 0;
201 /* The return code indicates key code size. */
203 w32_kbd_patch_key (KEY_EVENT_RECORD
*event
)
205 unsigned int key_code
= event
->wVirtualKeyCode
;
206 unsigned int mods
= event
->dwControlKeyState
;
208 static BYTE ansi_code
[4];
209 static int isdead
= 0;
213 event
->uChar
.AsciiChar
= ansi_code
[2];
217 if (event
->uChar
.AsciiChar
!= 0)
220 memset (keystate
, 0, sizeof (keystate
));
221 keystate
[key_code
] = 0x80;
222 if (mods
& SHIFT_PRESSED
)
223 keystate
[VK_SHIFT
] = 0x80;
224 if (mods
& CAPSLOCK_ON
)
225 keystate
[VK_CAPITAL
] = 1;
226 /* If we recognize right-alt and left-ctrl as AltGr, set the key
227 states accordingly before invoking ToAscii. */
228 if (!NILP (Vw32_recognize_altgr
)
229 && (mods
& LEFT_CTRL_PRESSED
) && (mods
& RIGHT_ALT_PRESSED
))
231 keystate
[VK_CONTROL
] = 0x80;
232 keystate
[VK_LCONTROL
] = 0x80;
233 keystate
[VK_MENU
] = 0x80;
234 keystate
[VK_RMENU
] = 0x80;
238 /* Because of an OS bug, ToAscii corrupts the stack when called to
239 convert a dead key in console mode on NT4. Unfortunately, trying
240 to check for dead keys using MapVirtualKey doesn't work either -
241 these functions apparently use internal information about keyboard
242 layout which doesn't get properly updated in console programs when
243 changing layout (though apparently it gets partly updated,
244 otherwise ToAscii wouldn't crash). */
245 if (is_dead_key (event
->wVirtualKeyCode
))
249 /* On NT, call ToUnicode instead and then convert to the current
250 locale's default codepage. */
251 if (os_subtype
== OS_NT
)
255 isdead
= ToUnicode (event
->wVirtualKeyCode
, event
->wVirtualScanCode
,
256 keystate
, buf
, 128, 0);
262 event
->uChar
.UnicodeChar
= buf
[isdead
- 1];
264 GetLocaleInfo (GetThreadLocale (),
265 LOCALE_IDEFAULTANSICODEPAGE
, cp
, 20);
267 isdead
= WideCharToMultiByte (cpId
, 0, buf
, isdead
,
268 ansi_code
, 4, NULL
, NULL
);
275 isdead
= ToAscii (event
->wVirtualKeyCode
, event
->wVirtualScanCode
,
276 keystate
, (LPWORD
) ansi_code
, 0);
281 event
->uChar
.AsciiChar
= ansi_code
[0];
286 extern char *lispy_function_keys
[];
288 static int faked_key
= 0;
290 /* return code -1 means that event_queue_ptr won't be incremented.
291 In other word, this event makes two key codes. (by himi) */
293 key_event (KEY_EVENT_RECORD
*event
, struct input_event
*emacs_ev
, int *isdead
)
295 static int mod_key_state
= 0;
300 /* Skip key-up events. */
301 if (!event
->bKeyDown
)
303 switch (event
->wVirtualKeyCode
)
306 mod_key_state
&= ~LEFT_WIN_PRESSED
;
309 mod_key_state
&= ~RIGHT_WIN_PRESSED
;
312 mod_key_state
&= ~APPS_PRESSED
;
318 /* Ignore keystrokes we fake ourself; see below. */
319 if (faked_key
== event
->wVirtualKeyCode
)
325 /* To make it easier to debug this code, ignore modifier keys! */
326 switch (event
->wVirtualKeyCode
)
329 if (NILP (Vw32_pass_lwindow_to_system
))
331 /* Prevent system from acting on keyup (which opens the Start
332 menu if no other key was pressed) by simulating a press of
333 Space which we will ignore. */
334 if ((mod_key_state
& LEFT_WIN_PRESSED
) == 0)
336 if (NUMBERP (Vw32_phantom_key_code
))
337 faked_key
= XUINT (Vw32_phantom_key_code
) & 255;
339 faked_key
= VK_SPACE
;
340 keybd_event (faked_key
, (BYTE
) MapVirtualKey (faked_key
, 0), 0, 0);
343 mod_key_state
|= LEFT_WIN_PRESSED
;
344 if (!NILP (Vw32_lwindow_modifier
))
348 if (NILP (Vw32_pass_rwindow_to_system
))
350 if ((mod_key_state
& RIGHT_WIN_PRESSED
) == 0)
352 if (NUMBERP (Vw32_phantom_key_code
))
353 faked_key
= XUINT (Vw32_phantom_key_code
) & 255;
355 faked_key
= VK_SPACE
;
356 keybd_event (faked_key
, (BYTE
) MapVirtualKey (faked_key
, 0), 0, 0);
359 mod_key_state
|= RIGHT_WIN_PRESSED
;
360 if (!NILP (Vw32_rwindow_modifier
))
364 mod_key_state
|= APPS_PRESSED
;
365 if (!NILP (Vw32_apps_modifier
))
369 /* Decide whether to treat as modifier or function key. */
370 if (NILP (Vw32_enable_caps_lock
))
371 goto disable_lock_key
;
374 /* Decide whether to treat as modifier or function key. */
375 if (NILP (Vw32_enable_num_lock
))
376 goto disable_lock_key
;
379 /* Decide whether to treat as modifier or function key. */
380 if (NILP (Vw32_scroll_lock_modifier
))
381 goto disable_lock_key
;
384 /* Ensure the appropriate lock key state is off (and the
385 indicator light as well). */
386 wParam
= event
->wVirtualKeyCode
;
387 if (GetAsyncKeyState (wParam
) & 0x8000)
389 /* Fake another press of the relevant key. Apparently, this
390 really is the only way to turn off the indicator. */
392 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
393 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
394 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
395 KEYEVENTF_EXTENDEDKEY
| 0, 0);
396 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
397 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
405 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
406 which is confusing for purposes of key binding; convert
407 VK_CANCEL events into VK_PAUSE events. */
408 event
->wVirtualKeyCode
= VK_PAUSE
;
411 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
412 for purposes of key binding; convert these back into
413 VK_NUMLOCK events, at least when we want to see NumLock key
414 presses. (Note that there is never any possibility that
415 VK_PAUSE with Ctrl really is C-Pause as per above.) */
416 if (NILP (Vw32_enable_num_lock
)
417 && (event
->dwControlKeyState
418 & (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
)) != 0)
419 event
->wVirtualKeyCode
= VK_NUMLOCK
;
423 /* Recognize state of Windows and Apps keys. */
424 event
->dwControlKeyState
|= mod_key_state
;
426 /* Distinguish numeric keypad keys from extended keys. */
427 event
->wVirtualKeyCode
=
428 map_keypad_keys (event
->wVirtualKeyCode
,
429 (event
->dwControlKeyState
& ENHANCED_KEY
));
431 if (lispy_function_keys
[event
->wVirtualKeyCode
] == 0)
433 if (!NILP (Vw32_recognize_altgr
)
434 && (event
->dwControlKeyState
& LEFT_CTRL_PRESSED
)
435 && (event
->dwControlKeyState
& RIGHT_ALT_PRESSED
))
437 /* Don't try to interpret AltGr key chords; ToAscii seems not
438 to process them correctly. */
440 /* Handle key chords including any modifiers other than shift
441 directly, in order to preserve as much modifier information as
443 else if (event
->dwControlKeyState
444 & ( RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
445 | RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
446 | (!NILP (Vw32_lwindow_modifier
) ? LEFT_WIN_PRESSED
: 0)
447 | (!NILP (Vw32_rwindow_modifier
) ? RIGHT_WIN_PRESSED
: 0)
448 | (!NILP (Vw32_apps_modifier
) ? APPS_PRESSED
: 0)
449 | (!NILP (Vw32_scroll_lock_modifier
) ? SCROLLLOCK_ON
: 0)))
451 /* Don't translate modified alphabetic keystrokes, so the user
452 doesn't need to constantly switch layout to type control or
453 meta keystrokes when the normal layout translates
454 alphabetic characters to non-ascii characters. */
455 if ('A' <= event
->wVirtualKeyCode
&& event
->wVirtualKeyCode
<= 'Z')
457 event
->uChar
.AsciiChar
= event
->wVirtualKeyCode
;
458 if ((event
->dwControlKeyState
& SHIFT_PRESSED
) == 0)
459 event
->uChar
.AsciiChar
+= ('a' - 'A');
461 /* Try to handle unrecognized keystrokes by determining the
462 base character (ie. translating the base key plus shift
464 else if (event
->uChar
.AsciiChar
== 0)
465 w32_kbd_patch_key (event
);
468 if (event
->uChar
.AsciiChar
== 0)
470 emacs_ev
->kind
= NO_EVENT
;
473 else if (event
->uChar
.AsciiChar
> 0)
475 emacs_ev
->kind
= ASCII_KEYSTROKE_EVENT
;
476 emacs_ev
->code
= event
->uChar
.AsciiChar
;
478 else if (event
->uChar
.UnicodeChar
> 0)
480 emacs_ev
->kind
= MULTIBYTE_CHAR_KEYSTROKE_EVENT
;
481 emacs_ev
->code
= event
->uChar
.UnicodeChar
;
485 /* Fallback for non-Unicode versions of Windows. */
491 /* Get the codepage to interpret this key with. */
492 GetLocaleInfo (GetThreadLocale (),
493 LOCALE_IDEFAULTANSICODEPAGE
, cp
, 20);
497 dbcs
[1] = event
->uChar
.AsciiChar
;
501 if (!MultiByteToWideChar (cpId
, 0, dbcs
, 2, &code
, 1))
504 DebPrint (("Invalid DBCS sequence: %d %d\n",
506 emacs_ev
->kind
= NO_EVENT
;
509 else if (IsDBCSLeadByteEx (cpId
, dbcs
[1]))
512 emacs_ev
->kind
= NO_EVENT
;
516 if (!MultiByteToWideChar (cpId
, 0, &dbcs
[1], 1, &code
, 1))
519 DebPrint (("Invalid character: %d\n", dbcs
[1]));
520 emacs_ev
->kind
= NO_EVENT
;
523 emacs_ev
->kind
= MULTIBYTE_CHAR_KEYSTROKE_EVENT
;
524 emacs_ev
->code
= code
;
529 emacs_ev
->kind
= NON_ASCII_KEYSTROKE_EVENT
;
530 emacs_ev
->code
= event
->wVirtualKeyCode
;
533 XSETFRAME (emacs_ev
->frame_or_window
, get_frame ());
534 emacs_ev
->modifiers
= w32_kbd_mods_to_emacs (event
->dwControlKeyState
,
535 event
->wVirtualKeyCode
);
536 emacs_ev
->timestamp
= GetTickCount ();
541 w32_console_toggle_lock_key (int vk_code
, Lisp_Object new_state
)
543 int cur_state
= (GetKeyState (vk_code
) & 1);
546 || (NUMBERP (new_state
)
547 && ((XUINT (new_state
)) & 1) != cur_state
))
551 keybd_event ((BYTE
) vk_code
,
552 (BYTE
) MapVirtualKey (vk_code
, 0),
553 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
554 keybd_event ((BYTE
) vk_code
,
555 (BYTE
) MapVirtualKey (vk_code
, 0),
556 KEYEVENTF_EXTENDEDKEY
| 0, 0);
557 keybd_event ((BYTE
) vk_code
,
558 (BYTE
) MapVirtualKey (vk_code
, 0),
559 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
560 cur_state
= !cur_state
;
566 /* Mouse position hook. */
568 w32_console_mouse_position (FRAME_PTR
*f
,
570 Lisp_Object
*bar_window
,
571 enum scroll_bar_part
*part
,
583 SELECTED_FRAME ()->mouse_moved
= 0;
585 XSETINT (*x
, movement_pos
.X
);
586 XSETINT (*y
, movement_pos
.Y
);
587 *time
= movement_time
;
592 /* Remember mouse motion and notify emacs. */
594 mouse_moved_to (int x
, int y
)
596 /* If we're in the same place, ignore it */
597 if (x
!= movement_pos
.X
|| y
!= movement_pos
.Y
)
599 SELECTED_FRAME ()->mouse_moved
= 1;
602 movement_time
= GetTickCount ();
606 /* Consoles return button bits in a strange order:
607 least significant - Leftmost button
608 next - Rightmost button
612 Assume emacs likes three button mice, so
616 Others increase from there. */
618 #define NUM_TRANSLATED_MOUSE_BUTTONS 3
619 static int emacs_button_translation
[NUM_TRANSLATED_MOUSE_BUTTONS
] =
625 do_mouse_event (MOUSE_EVENT_RECORD
*event
,
626 struct input_event
*emacs_ev
)
628 static DWORD button_state
= 0;
629 DWORD but_change
, mask
;
632 if (event
->dwEventFlags
== MOUSE_MOVED
)
634 /* For movement events we just note that the mouse has moved
635 so that emacs will generate drag events. */
636 mouse_moved_to (event
->dwMousePosition
.X
, event
->dwMousePosition
.Y
);
640 /* It looks like the console code sends us a mouse event with
641 dwButtonState == 0 when a window is activated. Ignore this case. */
642 if (event
->dwButtonState
== button_state
)
645 emacs_ev
->kind
= MOUSE_CLICK_EVENT
;
647 /* Find out what button has changed state since the last button event. */
648 but_change
= button_state
^ event
->dwButtonState
;
650 for (i
= 0; mask
; i
++, mask
<<= 1)
651 if (but_change
& mask
)
653 if (i
< NUM_TRANSLATED_MOUSE_BUTTONS
)
654 emacs_ev
->code
= emacs_button_translation
[i
];
660 button_state
= event
->dwButtonState
;
661 emacs_ev
->timestamp
= GetTickCount ();
662 emacs_ev
->modifiers
= w32_kbd_mods_to_emacs (event
->dwControlKeyState
, 0) |
663 ((event
->dwButtonState
& mask
) ? down_modifier
: up_modifier
);
665 XSETFASTINT (emacs_ev
->x
, event
->dwMousePosition
.X
);
666 XSETFASTINT (emacs_ev
->y
, event
->dwMousePosition
.Y
);
667 /* for Mule 2.2 (Based on Emacs 19.28 */
669 XSET (emacs_ev
->frame_or_window
, Lisp_Frame
, get_frame ());
671 XSETFRAME (emacs_ev
->frame_or_window
, get_frame ());
678 resize_event (WINDOW_BUFFER_SIZE_RECORD
*event
)
680 FRAME_PTR f
= get_frame ();
682 change_frame_size (f
, event
->dwSize
.Y
, event
->dwSize
.X
, 0, 1, 0);
683 SET_FRAME_GARBAGED (f
);
687 maybe_generate_resize_event (void)
689 CONSOLE_SCREEN_BUFFER_INFO info
;
690 FRAME_PTR f
= get_frame ();
692 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE
), &info
);
694 /* It is okay to call this unconditionally, since it will do nothing
695 if the size hasn't actually changed. */
696 change_frame_size (f
,
697 1 + info
.srWindow
.Bottom
- info
.srWindow
.Top
,
698 1 + info
.srWindow
.Right
- info
.srWindow
.Left
,
703 w32_console_read_socket (struct terminal
*terminal
,
705 struct input_event
*hold_quit
)
707 BOOL no_events
= TRUE
;
708 int nev
, ret
= 0, add
;
711 if (interrupt_input_blocked
)
713 interrupt_input_pending
= 1;
717 interrupt_input_pending
= 0;
722 nev
= fill_queue (0);
725 /* If nev == -1, there was some kind of error
726 If nev == 0 then waitp must be zero and no events were available
734 struct input_event inev
;
737 inev
.kind
= NO_EVENT
;
740 switch (queue_ptr
->EventType
)
743 add
= key_event (&queue_ptr
->Event
.KeyEvent
, &inev
, &isdead
);
744 if (add
== -1) /* 95.7.25 by himi */
750 kbd_buffer_store_event_hold (&inev
, hold_quit
);
754 add
= do_mouse_event (&queue_ptr
->Event
.MouseEvent
, &inev
);
756 kbd_buffer_store_event_hold (&inev
, hold_quit
);
759 case WINDOW_BUFFER_SIZE_EVENT
:
760 if (w32_use_full_screen_buffer
)
761 resize_event (&queue_ptr
->Event
.WindowBufferSizeEvent
);
766 /* Internal event types, ignored. */
774 if (ret
> 0 || expected
== 0)
778 /* We don't get told about changes in the window size (only the buffer
779 size, which we no longer care about), so we have to check it
781 if (!w32_use_full_screen_buffer
)
782 maybe_generate_resize_event ();
788 /* arch-tag: 0bcb39b7-d085-4b85-9070-6750e8c03047
789 (do not change this comment) */