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 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
;
85 fill_queue (BOOL block
)
90 if (queue_ptr
< queue_end
)
91 return queue_end
-queue_ptr
;
95 /* Check to see if there are some events to read before we try
96 because we can't block. */
97 if (!GetNumberOfConsoleInputEvents (keyboard_handle
, &events_waiting
))
99 if (events_waiting
== 0)
103 rc
= ReadConsoleInput (keyboard_handle
, event_queue
, EVENT_QUEUE_SIZE
,
107 queue_ptr
= event_queue
;
108 queue_end
= event_queue
+ events_waiting
;
109 return (int) events_waiting
;
112 /* In a generic, multi-frame world this should take a console handle
113 and return the frame for it
115 Right now, there's only one frame so return it. */
119 return SELECTED_FRAME ();
122 /* Translate console modifiers to emacs modifiers.
123 German keyboard support (Kai Morgan Zeise 2/18/95). */
125 w32_kbd_mods_to_emacs (DWORD mods
, WORD key
)
129 /* If we recognize right-alt and left-ctrl as AltGr, and it has been
130 pressed, first remove those modifiers. */
131 if (!NILP (Vw32_recognize_altgr
)
132 && (mods
& (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
))
133 == (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
))
134 mods
&= ~ (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
);
136 if (mods
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
))
137 retval
= ((NILP (Vw32_alt_is_meta
)) ? alt_modifier
: meta_modifier
);
139 if (mods
& (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
141 retval
|= ctrl_modifier
;
142 if ((mods
& (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
143 == (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
144 retval
|= meta_modifier
;
147 if (mods
& LEFT_WIN_PRESSED
)
148 retval
|= w32_key_to_modifier (VK_LWIN
);
149 if (mods
& RIGHT_WIN_PRESSED
)
150 retval
|= w32_key_to_modifier (VK_RWIN
);
151 if (mods
& APPS_PRESSED
)
152 retval
|= w32_key_to_modifier (VK_APPS
);
153 if (mods
& SCROLLLOCK_ON
)
154 retval
|= w32_key_to_modifier (VK_SCROLL
);
156 /* Just in case someone wanted the original behavior, make it
157 optional by setting w32-capslock-is-shiftlock to t. */
158 if (NILP (Vw32_capslock_is_shiftlock
)
159 /* Keys that should _not_ be affected by CapsLock. */
160 && ( (key
== VK_BACK
)
163 || (key
== VK_RETURN
)
164 || (key
== VK_ESCAPE
)
165 || ((key
>= VK_SPACE
) && (key
<= VK_HELP
))
166 || ((key
>= VK_NUMPAD0
) && (key
<= VK_F24
))
167 || ((key
>= VK_NUMPAD_CLEAR
) && (key
<= VK_NUMPAD_DELETE
))
170 /* Only consider shift state. */
171 if ((mods
& SHIFT_PRESSED
) != 0)
172 retval
|= shift_modifier
;
176 /* Ignore CapsLock state if not enabled. */
177 if (NILP (Vw32_enable_caps_lock
))
178 mods
&= ~CAPSLOCK_ON
;
179 if ((mods
& (SHIFT_PRESSED
| CAPSLOCK_ON
)) != 0)
180 retval
|= shift_modifier
;
187 /* Return nonzero if the virtual key is a dead key. */
189 is_dead_key (int wparam
)
191 unsigned int code
= MapVirtualKey (wparam
, 2);
193 /* Windows 95 returns 0x8000, NT returns 0x80000000. */
194 return (code
& 0x80008000) ? 1 : 0;
198 /* The return code indicates key code size. */
200 w32_kbd_patch_key (KEY_EVENT_RECORD
*event
)
202 unsigned int key_code
= event
->wVirtualKeyCode
;
203 unsigned int mods
= event
->dwControlKeyState
;
205 static BYTE ansi_code
[4];
206 static int isdead
= 0;
210 event
->uChar
.AsciiChar
= ansi_code
[2];
214 if (event
->uChar
.AsciiChar
!= 0)
217 memset (keystate
, 0, sizeof (keystate
));
218 keystate
[key_code
] = 0x80;
219 if (mods
& SHIFT_PRESSED
)
220 keystate
[VK_SHIFT
] = 0x80;
221 if (mods
& CAPSLOCK_ON
)
222 keystate
[VK_CAPITAL
] = 1;
223 /* If we recognize right-alt and left-ctrl as AltGr, set the key
224 states accordingly before invoking ToAscii. */
225 if (!NILP (Vw32_recognize_altgr
)
226 && (mods
& LEFT_CTRL_PRESSED
) && (mods
& RIGHT_ALT_PRESSED
))
228 keystate
[VK_CONTROL
] = 0x80;
229 keystate
[VK_LCONTROL
] = 0x80;
230 keystate
[VK_MENU
] = 0x80;
231 keystate
[VK_RMENU
] = 0x80;
235 /* Because of an OS bug, ToAscii corrupts the stack when called to
236 convert a dead key in console mode on NT4. Unfortunately, trying
237 to check for dead keys using MapVirtualKey doesn't work either -
238 these functions apparently use internal information about keyboard
239 layout which doesn't get properly updated in console programs when
240 changing layout (though apparently it gets partly updated,
241 otherwise ToAscii wouldn't crash). */
242 if (is_dead_key (event
->wVirtualKeyCode
))
246 /* On NT, call ToUnicode instead and then convert to the current
247 locale's default codepage. */
248 if (os_subtype
== OS_NT
)
252 isdead
= ToUnicode (event
->wVirtualKeyCode
, event
->wVirtualScanCode
,
253 keystate
, buf
, 128, 0);
259 GetLocaleInfo (GetThreadLocale (),
260 LOCALE_IDEFAULTANSICODEPAGE
, cp
, 20);
262 isdead
= WideCharToMultiByte (cpId
, 0, buf
, isdead
,
263 ansi_code
, 4, NULL
, NULL
);
270 isdead
= ToAscii (event
->wVirtualKeyCode
, event
->wVirtualScanCode
,
271 keystate
, (LPWORD
) ansi_code
, 0);
276 event
->uChar
.AsciiChar
= ansi_code
[0];
281 extern char *lispy_function_keys
[];
283 static int faked_key
= 0;
285 /* return code -1 means that event_queue_ptr won't be incremented.
286 In other word, this event makes two key codes. (by himi) */
288 key_event (KEY_EVENT_RECORD
*event
, struct input_event
*emacs_ev
, int *isdead
)
290 static int mod_key_state
= 0;
295 /* Skip key-up events. */
296 if (!event
->bKeyDown
)
298 switch (event
->wVirtualKeyCode
)
301 mod_key_state
&= ~LEFT_WIN_PRESSED
;
304 mod_key_state
&= ~RIGHT_WIN_PRESSED
;
307 mod_key_state
&= ~APPS_PRESSED
;
313 /* Ignore keystrokes we fake ourself; see below. */
314 if (faked_key
== event
->wVirtualKeyCode
)
320 /* To make it easier to debug this code, ignore modifier keys! */
321 switch (event
->wVirtualKeyCode
)
324 if (NILP (Vw32_pass_lwindow_to_system
))
326 /* Prevent system from acting on keyup (which opens the Start
327 menu if no other key was pressed) by simulating a press of
328 Space which we will ignore. */
329 if ((mod_key_state
& LEFT_WIN_PRESSED
) == 0)
331 if (NUMBERP (Vw32_phantom_key_code
))
332 faked_key
= XUINT (Vw32_phantom_key_code
) & 255;
334 faked_key
= VK_SPACE
;
335 keybd_event (faked_key
, (BYTE
) MapVirtualKey (faked_key
, 0), 0, 0);
338 mod_key_state
|= LEFT_WIN_PRESSED
;
339 if (!NILP (Vw32_lwindow_modifier
))
343 if (NILP (Vw32_pass_rwindow_to_system
))
345 if ((mod_key_state
& RIGHT_WIN_PRESSED
) == 0)
347 if (NUMBERP (Vw32_phantom_key_code
))
348 faked_key
= XUINT (Vw32_phantom_key_code
) & 255;
350 faked_key
= VK_SPACE
;
351 keybd_event (faked_key
, (BYTE
) MapVirtualKey (faked_key
, 0), 0, 0);
354 mod_key_state
|= RIGHT_WIN_PRESSED
;
355 if (!NILP (Vw32_rwindow_modifier
))
359 mod_key_state
|= APPS_PRESSED
;
360 if (!NILP (Vw32_apps_modifier
))
364 /* Decide whether to treat as modifier or function key. */
365 if (NILP (Vw32_enable_caps_lock
))
366 goto disable_lock_key
;
369 /* Decide whether to treat as modifier or function key. */
370 if (NILP (Vw32_enable_num_lock
))
371 goto disable_lock_key
;
374 /* Decide whether to treat as modifier or function key. */
375 if (NILP (Vw32_scroll_lock_modifier
))
376 goto disable_lock_key
;
379 /* Ensure the appropriate lock key state is off (and the
380 indicator light as well). */
381 wParam
= event
->wVirtualKeyCode
;
382 if (GetAsyncKeyState (wParam
) & 0x8000)
384 /* Fake another press of the relevant key. Apparently, this
385 really is the only way to turn off the indicator. */
387 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
388 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
389 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
390 KEYEVENTF_EXTENDEDKEY
| 0, 0);
391 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
392 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
400 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
401 which is confusing for purposes of key binding; convert
402 VK_CANCEL events into VK_PAUSE events. */
403 event
->wVirtualKeyCode
= VK_PAUSE
;
406 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
407 for purposes of key binding; convert these back into
408 VK_NUMLOCK events, at least when we want to see NumLock key
409 presses. (Note that there is never any possibility that
410 VK_PAUSE with Ctrl really is C-Pause as per above.) */
411 if (NILP (Vw32_enable_num_lock
)
412 && (event
->dwControlKeyState
413 & (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
)) != 0)
414 event
->wVirtualKeyCode
= VK_NUMLOCK
;
418 /* Recognize state of Windows and Apps keys. */
419 event
->dwControlKeyState
|= mod_key_state
;
421 /* Distinguish numeric keypad keys from extended keys. */
422 event
->wVirtualKeyCode
=
423 map_keypad_keys (event
->wVirtualKeyCode
,
424 (event
->dwControlKeyState
& ENHANCED_KEY
));
426 if (lispy_function_keys
[event
->wVirtualKeyCode
] == 0)
428 emacs_ev
->kind
= ASCII_KEYSTROKE_EVENT
;
430 if (!NILP (Vw32_recognize_altgr
)
431 && (event
->dwControlKeyState
& LEFT_CTRL_PRESSED
)
432 && (event
->dwControlKeyState
& RIGHT_ALT_PRESSED
))
434 /* Don't try to interpret AltGr key chords; ToAscii seems not
435 to process them correctly. */
437 /* Handle key chords including any modifiers other than shift
438 directly, in order to preserve as much modifier information as
440 else if (event
->dwControlKeyState
441 & ( RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
442 | RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
443 | (!NILP (Vw32_lwindow_modifier
) ? LEFT_WIN_PRESSED
: 0)
444 | (!NILP (Vw32_rwindow_modifier
) ? RIGHT_WIN_PRESSED
: 0)
445 | (!NILP (Vw32_apps_modifier
) ? APPS_PRESSED
: 0)
446 | (!NILP (Vw32_scroll_lock_modifier
) ? SCROLLLOCK_ON
: 0)))
448 /* Don't translate modified alphabetic keystrokes, so the user
449 doesn't need to constantly switch layout to type control or
450 meta keystrokes when the normal layout translates
451 alphabetic characters to non-ascii characters. */
452 if ('A' <= event
->wVirtualKeyCode
&& event
->wVirtualKeyCode
<= 'Z')
454 event
->uChar
.AsciiChar
= event
->wVirtualKeyCode
;
455 if ((event
->dwControlKeyState
& SHIFT_PRESSED
) == 0)
456 event
->uChar
.AsciiChar
+= ('a' - 'A');
458 /* Try to handle unrecognized keystrokes by determining the
459 base character (ie. translating the base key plus shift
461 else if (event
->uChar
.AsciiChar
== 0)
462 w32_kbd_patch_key (event
);
464 if (event
->uChar
.AsciiChar
== 0)
466 emacs_ev
->code
= event
->uChar
.AsciiChar
;
470 emacs_ev
->kind
= NON_ASCII_KEYSTROKE_EVENT
;
471 emacs_ev
->code
= event
->wVirtualKeyCode
;
474 XSETFRAME (emacs_ev
->frame_or_window
, get_frame ());
475 emacs_ev
->modifiers
= w32_kbd_mods_to_emacs (event
->dwControlKeyState
,
476 event
->wVirtualKeyCode
);
477 emacs_ev
->timestamp
= GetTickCount ();
482 w32_console_toggle_lock_key (int vk_code
, Lisp_Object new_state
)
484 int cur_state
= (GetKeyState (vk_code
) & 1);
487 || (NUMBERP (new_state
)
488 && ((XUINT (new_state
)) & 1) != cur_state
))
492 keybd_event ((BYTE
) vk_code
,
493 (BYTE
) MapVirtualKey (vk_code
, 0),
494 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
495 keybd_event ((BYTE
) vk_code
,
496 (BYTE
) MapVirtualKey (vk_code
, 0),
497 KEYEVENTF_EXTENDEDKEY
| 0, 0);
498 keybd_event ((BYTE
) vk_code
,
499 (BYTE
) MapVirtualKey (vk_code
, 0),
500 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
501 cur_state
= !cur_state
;
507 /* Mouse position hook. */
509 w32_console_mouse_position (FRAME_PTR
*f
,
511 Lisp_Object
*bar_window
,
512 enum scroll_bar_part
*part
,
524 SELECTED_FRAME ()->mouse_moved
= 0;
526 XSETINT(*x
, movement_pos
.X
);
527 XSETINT(*y
, movement_pos
.Y
);
528 *time
= movement_time
;
533 /* Remember mouse motion and notify emacs. */
535 mouse_moved_to (int x
, int y
)
537 /* If we're in the same place, ignore it */
538 if (x
!= movement_pos
.X
|| y
!= movement_pos
.Y
)
540 SELECTED_FRAME ()->mouse_moved
= 1;
543 movement_time
= GetTickCount ();
547 /* Consoles return button bits in a strange order:
548 least significant - Leftmost button
549 next - Rightmost button
553 Assume emacs likes three button mice, so
557 Others increase from there. */
559 #define NUM_TRANSLATED_MOUSE_BUTTONS 3
560 static int emacs_button_translation
[NUM_TRANSLATED_MOUSE_BUTTONS
] =
566 do_mouse_event (MOUSE_EVENT_RECORD
*event
,
567 struct input_event
*emacs_ev
)
569 static DWORD button_state
= 0;
570 DWORD but_change
, mask
;
573 if (event
->dwEventFlags
== MOUSE_MOVED
)
575 /* For movement events we just note that the mouse has moved
576 so that emacs will generate drag events. */
577 mouse_moved_to (event
->dwMousePosition
.X
, event
->dwMousePosition
.Y
);
581 /* It looks like the console code sends us a mouse event with
582 dwButtonState == 0 when a window is activated. Ignore this case. */
583 if (event
->dwButtonState
== button_state
)
586 emacs_ev
->kind
= MOUSE_CLICK_EVENT
;
588 /* Find out what button has changed state since the last button event. */
589 but_change
= button_state
^ event
->dwButtonState
;
591 for (i
= 0; mask
; i
++, mask
<<= 1)
592 if (but_change
& mask
)
594 if (i
< NUM_TRANSLATED_MOUSE_BUTTONS
)
595 emacs_ev
->code
= emacs_button_translation
[i
];
601 button_state
= event
->dwButtonState
;
602 emacs_ev
->timestamp
= GetTickCount ();
603 emacs_ev
->modifiers
= w32_kbd_mods_to_emacs (event
->dwControlKeyState
, 0) |
604 ((event
->dwButtonState
& mask
) ? down_modifier
: up_modifier
);
606 XSETFASTINT (emacs_ev
->x
, event
->dwMousePosition
.X
);
607 XSETFASTINT (emacs_ev
->y
, event
->dwMousePosition
.Y
);
608 /* for Mule 2.2 (Based on Emacs 19.28 */
610 XSET (emacs_ev
->frame_or_window
, Lisp_Frame
, get_frame ());
612 XSETFRAME (emacs_ev
->frame_or_window
, get_frame ());
619 resize_event (WINDOW_BUFFER_SIZE_RECORD
*event
)
621 FRAME_PTR f
= get_frame ();
623 change_frame_size (f
, event
->dwSize
.Y
, event
->dwSize
.X
, 0, 1, 0);
624 SET_FRAME_GARBAGED (f
);
628 maybe_generate_resize_event ()
630 CONSOLE_SCREEN_BUFFER_INFO info
;
631 FRAME_PTR f
= get_frame ();
633 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE
), &info
);
635 /* It is okay to call this unconditionally, since it will do nothing
636 if the size hasn't actually changed. */
637 change_frame_size (f
,
638 1 + info
.srWindow
.Bottom
- info
.srWindow
.Top
,
639 1 + info
.srWindow
.Right
- info
.srWindow
.Left
,
644 w32_console_read_socket (struct terminal
*terminal
,
646 struct input_event
*hold_quit
)
648 BOOL no_events
= TRUE
;
649 int nev
, ret
= 0, add
;
652 if (interrupt_input_blocked
)
654 interrupt_input_pending
= 1;
658 interrupt_input_pending
= 0;
663 nev
= fill_queue (0);
666 /* If nev == -1, there was some kind of error
667 If nev == 0 then waitp must be zero and no events were available
675 struct input_event inev
;
678 inev
.kind
= NO_EVENT
;
681 switch (queue_ptr
->EventType
)
684 add
= key_event (&queue_ptr
->Event
.KeyEvent
, &inev
, &isdead
);
685 if (add
== -1) /* 95.7.25 by himi */
691 kbd_buffer_store_event_hold (&inev
, hold_quit
);
695 add
= do_mouse_event (&queue_ptr
->Event
.MouseEvent
, &inev
);
697 kbd_buffer_store_event_hold (&inev
, hold_quit
);
700 case WINDOW_BUFFER_SIZE_EVENT
:
701 if (w32_use_full_screen_buffer
)
702 resize_event (&queue_ptr
->Event
.WindowBufferSizeEvent
);
707 /* Internal event types, ignored. */
715 if (ret
> 0 || expected
== 0)
719 /* We don't get told about changes in the window size (only the buffer
720 size, which we no longer care about), so we have to check it
722 if (!w32_use_full_screen_buffer
)
723 maybe_generate_resize_event ();
729 /* arch-tag: 0bcb39b7-d085-4b85-9070-6750e8c03047
730 (do not change this comment) */