1 /* Input event support for Emacs on the Microsoft W32 API.
2 Copyright (C) 1992, 1993, 1995, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007 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, or (at your option)
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; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
23 Adapted from ntkbd.c by Tim Fleehart
42 #include "blockinput.h"
43 #include "termhooks.h"
47 /* stdin, from ntterm */
48 extern HANDLE keyboard_handle
;
50 /* Info for last mouse motion */
51 static COORD movement_pos
;
52 static DWORD movement_time
;
55 extern void reinvoke_input_signal (void);
58 extern int change_frame_size (FRAME_PTR
, int, int, int, int);
60 /* from w32console.c */
61 extern int w32_use_full_screen_buffer
;
64 extern Lisp_Object Vw32_alt_is_meta
;
65 extern unsigned int map_keypad_keys (unsigned int, unsigned int);
68 extern Lisp_Object Vw32_capslock_is_shiftlock
;
69 extern Lisp_Object Vw32_enable_caps_lock
;
70 extern Lisp_Object Vw32_enable_num_lock
;
71 extern Lisp_Object Vw32_recognize_altgr
;
72 extern Lisp_Object Vw32_pass_lwindow_to_system
;
73 extern Lisp_Object Vw32_pass_rwindow_to_system
;
74 extern Lisp_Object Vw32_phantom_key_code
;
75 extern Lisp_Object Vw32_lwindow_modifier
;
76 extern Lisp_Object Vw32_rwindow_modifier
;
77 extern Lisp_Object Vw32_apps_modifier
;
78 extern Lisp_Object Vw32_scroll_lock_modifier
;
79 extern unsigned int w32_key_to_modifier (int key
);
82 #define EVENT_QUEUE_SIZE 50
83 static INPUT_RECORD event_queue
[EVENT_QUEUE_SIZE
];
84 static INPUT_RECORD
*queue_ptr
= event_queue
, *queue_end
= event_queue
;
87 fill_queue (BOOL block
)
92 if (queue_ptr
< queue_end
)
93 return queue_end
-queue_ptr
;
97 /* Check to see if there are some events to read before we try
98 because we can't block. */
99 if (!GetNumberOfConsoleInputEvents (keyboard_handle
, &events_waiting
))
101 if (events_waiting
== 0)
105 rc
= ReadConsoleInput (keyboard_handle
, event_queue
, EVENT_QUEUE_SIZE
,
109 queue_ptr
= event_queue
;
110 queue_end
= event_queue
+ events_waiting
;
111 return (int) events_waiting
;
114 /* In a generic, multi-frame world this should take a console handle
115 and return the frame for it
117 Right now, there's only one frame so return it. */
121 return SELECTED_FRAME ();
124 /* Translate console modifiers to emacs modifiers.
125 German keyboard support (Kai Morgan Zeise 2/18/95). */
127 w32_kbd_mods_to_emacs (DWORD mods
, WORD key
)
131 /* If we recognize right-alt and left-ctrl as AltGr, and it has been
132 pressed, first remove those modifiers. */
133 if (!NILP (Vw32_recognize_altgr
)
134 && (mods
& (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
))
135 == (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
))
136 mods
&= ~ (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
);
138 if (mods
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
))
139 retval
= ((NILP (Vw32_alt_is_meta
)) ? alt_modifier
: meta_modifier
);
141 if (mods
& (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
143 retval
|= ctrl_modifier
;
144 if ((mods
& (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
145 == (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
146 retval
|= meta_modifier
;
149 if (mods
& LEFT_WIN_PRESSED
)
150 retval
|= w32_key_to_modifier (VK_LWIN
);
151 if (mods
& RIGHT_WIN_PRESSED
)
152 retval
|= w32_key_to_modifier (VK_RWIN
);
153 if (mods
& APPS_PRESSED
)
154 retval
|= w32_key_to_modifier (VK_APPS
);
155 if (mods
& SCROLLLOCK_ON
)
156 retval
|= w32_key_to_modifier (VK_SCROLL
);
158 /* Just in case someone wanted the original behaviour, make it
159 optional by setting w32-capslock-is-shiftlock to t. */
160 if (NILP (Vw32_capslock_is_shiftlock
)
161 /* Keys that should _not_ be affected by CapsLock. */
162 && ( (key
== VK_BACK
)
165 || (key
== VK_RETURN
)
166 || (key
== VK_ESCAPE
)
167 || ((key
>= VK_SPACE
) && (key
<= VK_HELP
))
168 || ((key
>= VK_NUMPAD0
) && (key
<= VK_F24
))
169 || ((key
>= VK_NUMPAD_CLEAR
) && (key
<= VK_NUMPAD_DELETE
))
172 /* Only consider shift state. */
173 if ((mods
& SHIFT_PRESSED
) != 0)
174 retval
|= shift_modifier
;
178 /* Ignore CapsLock state if not enabled. */
179 if (NILP (Vw32_enable_caps_lock
))
180 mods
&= ~CAPSLOCK_ON
;
181 if ((mods
& (SHIFT_PRESSED
| CAPSLOCK_ON
)) != 0)
182 retval
|= shift_modifier
;
189 /* Return nonzero if the virtual key is a dead key. */
191 is_dead_key (int wparam
)
193 unsigned int code
= MapVirtualKey (wparam
, 2);
195 /* Windows 95 returns 0x8000, NT returns 0x80000000. */
196 return (code
& 0x80008000) ? 1 : 0;
200 /* The return code indicates key code size. */
202 w32_kbd_patch_key (KEY_EVENT_RECORD
*event
)
204 unsigned int key_code
= event
->wVirtualKeyCode
;
205 unsigned int mods
= event
->dwControlKeyState
;
207 static BYTE ansi_code
[4];
208 static int isdead
= 0;
212 event
->uChar
.AsciiChar
= ansi_code
[2];
216 if (event
->uChar
.AsciiChar
!= 0)
219 memset (keystate
, 0, sizeof (keystate
));
220 keystate
[key_code
] = 0x80;
221 if (mods
& SHIFT_PRESSED
)
222 keystate
[VK_SHIFT
] = 0x80;
223 if (mods
& CAPSLOCK_ON
)
224 keystate
[VK_CAPITAL
] = 1;
225 /* If we recognize right-alt and left-ctrl as AltGr, set the key
226 states accordingly before invoking ToAscii. */
227 if (!NILP (Vw32_recognize_altgr
)
228 && (mods
& LEFT_CTRL_PRESSED
) && (mods
& RIGHT_ALT_PRESSED
))
230 keystate
[VK_CONTROL
] = 0x80;
231 keystate
[VK_LCONTROL
] = 0x80;
232 keystate
[VK_MENU
] = 0x80;
233 keystate
[VK_RMENU
] = 0x80;
237 /* Because of an OS bug, ToAscii corrupts the stack when called to
238 convert a dead key in console mode on NT4. Unfortunately, trying
239 to check for dead keys using MapVirtualKey doesn't work either -
240 these functions apparently use internal information about keyboard
241 layout which doesn't get properly updated in console programs when
242 changing layout (though apparently it gets partly updated,
243 otherwise ToAscii wouldn't crash). */
244 if (is_dead_key (event
->wVirtualKeyCode
))
248 /* On NT, call ToUnicode instead and then convert to the current
249 locale's default codepage. */
250 if (os_subtype
== OS_NT
)
254 isdead
= ToUnicode (event
->wVirtualKeyCode
, event
->wVirtualScanCode
,
255 keystate
, buf
, 128, 0);
261 GetLocaleInfo (GetThreadLocale (),
262 LOCALE_IDEFAULTANSICODEPAGE
, cp
, 20);
264 isdead
= WideCharToMultiByte (cpId
, 0, buf
, isdead
,
265 ansi_code
, 4, NULL
, NULL
);
272 isdead
= ToAscii (event
->wVirtualKeyCode
, event
->wVirtualScanCode
,
273 keystate
, (LPWORD
) ansi_code
, 0);
278 event
->uChar
.AsciiChar
= ansi_code
[0];
283 extern char *lispy_function_keys
[];
285 static int faked_key
= 0;
287 /* return code -1 means that event_queue_ptr won't be incremented.
288 In other word, this event makes two key codes. (by himi) */
290 key_event (KEY_EVENT_RECORD
*event
, struct input_event
*emacs_ev
, int *isdead
)
292 static int mod_key_state
= 0;
297 /* Skip key-up events. */
298 if (!event
->bKeyDown
)
300 switch (event
->wVirtualKeyCode
)
303 mod_key_state
&= ~LEFT_WIN_PRESSED
;
306 mod_key_state
&= ~RIGHT_WIN_PRESSED
;
309 mod_key_state
&= ~APPS_PRESSED
;
315 /* Ignore keystrokes we fake ourself; see below. */
316 if (faked_key
== event
->wVirtualKeyCode
)
322 /* To make it easier to debug this code, ignore modifier keys! */
323 switch (event
->wVirtualKeyCode
)
326 if (NILP (Vw32_pass_lwindow_to_system
))
328 /* Prevent system from acting on keyup (which opens the Start
329 menu if no other key was pressed) by simulating a press of
330 Space which we will ignore. */
331 if ((mod_key_state
& LEFT_WIN_PRESSED
) == 0)
333 if (NUMBERP (Vw32_phantom_key_code
))
334 faked_key
= XUINT (Vw32_phantom_key_code
) & 255;
336 faked_key
= VK_SPACE
;
337 keybd_event (faked_key
, (BYTE
) MapVirtualKey (faked_key
, 0), 0, 0);
340 mod_key_state
|= LEFT_WIN_PRESSED
;
341 if (!NILP (Vw32_lwindow_modifier
))
345 if (NILP (Vw32_pass_rwindow_to_system
))
347 if ((mod_key_state
& RIGHT_WIN_PRESSED
) == 0)
349 if (NUMBERP (Vw32_phantom_key_code
))
350 faked_key
= XUINT (Vw32_phantom_key_code
) & 255;
352 faked_key
= VK_SPACE
;
353 keybd_event (faked_key
, (BYTE
) MapVirtualKey (faked_key
, 0), 0, 0);
356 mod_key_state
|= RIGHT_WIN_PRESSED
;
357 if (!NILP (Vw32_rwindow_modifier
))
361 mod_key_state
|= APPS_PRESSED
;
362 if (!NILP (Vw32_apps_modifier
))
366 /* Decide whether to treat as modifier or function key. */
367 if (NILP (Vw32_enable_caps_lock
))
368 goto disable_lock_key
;
371 /* Decide whether to treat as modifier or function key. */
372 if (NILP (Vw32_enable_num_lock
))
373 goto disable_lock_key
;
376 /* Decide whether to treat as modifier or function key. */
377 if (NILP (Vw32_scroll_lock_modifier
))
378 goto disable_lock_key
;
381 /* Ensure the appropriate lock key state is off (and the
382 indicator light as well). */
383 wParam
= event
->wVirtualKeyCode
;
384 if (GetAsyncKeyState (wParam
) & 0x8000)
386 /* Fake another press of the relevant key. Apparently, this
387 really is the only way to turn off the indicator. */
389 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
390 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
391 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
392 KEYEVENTF_EXTENDEDKEY
| 0, 0);
393 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
394 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
402 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
403 which is confusing for purposes of key binding; convert
404 VK_CANCEL events into VK_PAUSE events. */
405 event
->wVirtualKeyCode
= VK_PAUSE
;
408 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
409 for purposes of key binding; convert these back into
410 VK_NUMLOCK events, at least when we want to see NumLock key
411 presses. (Note that there is never any possibility that
412 VK_PAUSE with Ctrl really is C-Pause as per above.) */
413 if (NILP (Vw32_enable_num_lock
)
414 && (event
->dwControlKeyState
415 & (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
)) != 0)
416 event
->wVirtualKeyCode
= VK_NUMLOCK
;
420 /* Recognize state of Windows and Apps keys. */
421 event
->dwControlKeyState
|= mod_key_state
;
423 /* Distinguish numeric keypad keys from extended keys. */
424 event
->wVirtualKeyCode
=
425 map_keypad_keys (event
->wVirtualKeyCode
,
426 (event
->dwControlKeyState
& ENHANCED_KEY
));
428 if (lispy_function_keys
[event
->wVirtualKeyCode
] == 0)
430 emacs_ev
->kind
= ASCII_KEYSTROKE_EVENT
;
432 if (!NILP (Vw32_recognize_altgr
)
433 && (event
->dwControlKeyState
& LEFT_CTRL_PRESSED
)
434 && (event
->dwControlKeyState
& RIGHT_ALT_PRESSED
))
436 /* Don't try to interpret AltGr key chords; ToAscii seems not
437 to process them correctly. */
439 /* Handle key chords including any modifiers other than shift
440 directly, in order to preserve as much modifier information as
442 else if (event
->dwControlKeyState
443 & ( RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
444 | RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
445 | (!NILP (Vw32_lwindow_modifier
) ? LEFT_WIN_PRESSED
: 0)
446 | (!NILP (Vw32_rwindow_modifier
) ? RIGHT_WIN_PRESSED
: 0)
447 | (!NILP (Vw32_apps_modifier
) ? APPS_PRESSED
: 0)
448 | (!NILP (Vw32_scroll_lock_modifier
) ? SCROLLLOCK_ON
: 0)))
450 /* Don't translate modified alphabetic keystrokes, so the user
451 doesn't need to constantly switch layout to type control or
452 meta keystrokes when the normal layout translates
453 alphabetic characters to non-ascii characters. */
454 if ('A' <= event
->wVirtualKeyCode
&& event
->wVirtualKeyCode
<= 'Z')
456 event
->uChar
.AsciiChar
= event
->wVirtualKeyCode
;
457 if ((event
->dwControlKeyState
& SHIFT_PRESSED
) == 0)
458 event
->uChar
.AsciiChar
+= ('a' - 'A');
460 /* Try to handle unrecognized keystrokes by determining the
461 base character (ie. translating the base key plus shift
463 else if (event
->uChar
.AsciiChar
== 0)
464 w32_kbd_patch_key (event
);
466 if (event
->uChar
.AsciiChar
== 0)
468 emacs_ev
->code
= event
->uChar
.AsciiChar
;
472 emacs_ev
->kind
= NON_ASCII_KEYSTROKE_EVENT
;
473 emacs_ev
->code
= event
->wVirtualKeyCode
;
476 XSETFRAME (emacs_ev
->frame_or_window
, get_frame ());
477 emacs_ev
->modifiers
= w32_kbd_mods_to_emacs (event
->dwControlKeyState
,
478 event
->wVirtualKeyCode
);
479 emacs_ev
->timestamp
= GetTickCount ();
484 w32_console_toggle_lock_key (int vk_code
, Lisp_Object new_state
)
486 int cur_state
= (GetKeyState (vk_code
) & 1);
489 || (NUMBERP (new_state
)
490 && ((XUINT (new_state
)) & 1) != cur_state
))
494 keybd_event ((BYTE
) vk_code
,
495 (BYTE
) MapVirtualKey (vk_code
, 0),
496 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
497 keybd_event ((BYTE
) vk_code
,
498 (BYTE
) MapVirtualKey (vk_code
, 0),
499 KEYEVENTF_EXTENDEDKEY
| 0, 0);
500 keybd_event ((BYTE
) vk_code
,
501 (BYTE
) MapVirtualKey (vk_code
, 0),
502 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
503 cur_state
= !cur_state
;
509 /* Mouse position hook. */
511 w32_console_mouse_position (FRAME_PTR
*f
,
513 Lisp_Object
*bar_window
,
514 enum scroll_bar_part
*part
,
526 SELECTED_FRAME ()->mouse_moved
= 0;
528 XSETINT(*x
, movement_pos
.X
);
529 XSETINT(*y
, movement_pos
.Y
);
530 *time
= movement_time
;
535 /* Remember mouse motion and notify emacs. */
537 mouse_moved_to (int x
, int y
)
539 /* If we're in the same place, ignore it */
540 if (x
!= movement_pos
.X
|| y
!= movement_pos
.Y
)
542 SELECTED_FRAME ()->mouse_moved
= 1;
545 movement_time
= GetTickCount ();
549 /* Consoles return button bits in a strange order:
550 least significant - Leftmost button
551 next - Rightmost button
555 Assume emacs likes three button mice, so
559 Others increase from there. */
561 #define NUM_TRANSLATED_MOUSE_BUTTONS 3
562 static int emacs_button_translation
[NUM_TRANSLATED_MOUSE_BUTTONS
] =
568 do_mouse_event (MOUSE_EVENT_RECORD
*event
,
569 struct input_event
*emacs_ev
)
571 static DWORD button_state
= 0;
572 DWORD but_change
, mask
;
575 if (event
->dwEventFlags
== MOUSE_MOVED
)
577 /* For movement events we just note that the mouse has moved
578 so that emacs will generate drag events. */
579 mouse_moved_to (event
->dwMousePosition
.X
, event
->dwMousePosition
.Y
);
583 /* It looks like the console code sends us a mouse event with
584 dwButtonState == 0 when a window is activated. Ignore this case. */
585 if (event
->dwButtonState
== button_state
)
588 emacs_ev
->kind
= MOUSE_CLICK_EVENT
;
590 /* Find out what button has changed state since the last button event. */
591 but_change
= button_state
^ event
->dwButtonState
;
593 for (i
= 0; mask
; i
++, mask
<<= 1)
594 if (but_change
& mask
)
596 if (i
< NUM_TRANSLATED_MOUSE_BUTTONS
)
597 emacs_ev
->code
= emacs_button_translation
[i
];
603 button_state
= event
->dwButtonState
;
604 emacs_ev
->timestamp
= GetTickCount ();
605 emacs_ev
->modifiers
= w32_kbd_mods_to_emacs (event
->dwControlKeyState
, 0) |
606 ((event
->dwButtonState
& mask
) ? down_modifier
: up_modifier
);
608 XSETFASTINT (emacs_ev
->x
, event
->dwMousePosition
.X
);
609 XSETFASTINT (emacs_ev
->y
, event
->dwMousePosition
.Y
);
610 /* for Mule 2.2 (Based on Emacs 19.28 */
612 XSET (emacs_ev
->frame_or_window
, Lisp_Frame
, get_frame ());
614 XSETFRAME (emacs_ev
->frame_or_window
, get_frame ());
621 resize_event (WINDOW_BUFFER_SIZE_RECORD
*event
)
623 FRAME_PTR f
= get_frame ();
625 change_frame_size (f
, event
->dwSize
.Y
, event
->dwSize
.X
, 0, 1);
626 SET_FRAME_GARBAGED (f
);
630 maybe_generate_resize_event ()
632 CONSOLE_SCREEN_BUFFER_INFO info
;
633 FRAME_PTR f
= get_frame ();
635 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE
), &info
);
637 /* It is okay to call this unconditionally, since it will do nothing
638 if the size hasn't actually changed. */
639 change_frame_size (f
,
640 1 + info
.srWindow
.Bottom
- info
.srWindow
.Top
,
641 1 + info
.srWindow
.Right
- info
.srWindow
.Left
,
646 w32_console_read_socket (struct terminal
*terminal
,
648 struct input_event
*hold_quit
)
650 BOOL no_events
= TRUE
;
651 int nev
, ret
= 0, add
;
654 if (interrupt_input_blocked
)
656 interrupt_input_pending
= 1;
660 interrupt_input_pending
= 0;
665 nev
= fill_queue (0);
668 /* If nev == -1, there was some kind of error
669 If nev == 0 then waitp must be zero and no events were available
677 struct input_event inev
;
680 inev
.kind
= NO_EVENT
;
683 switch (queue_ptr
->EventType
)
686 add
= key_event (&queue_ptr
->Event
.KeyEvent
, &inev
, &isdead
);
687 if (add
== -1) /* 95.7.25 by himi */
693 kbd_buffer_store_event_hold (&inev
, hold_quit
);
697 add
= do_mouse_event (&queue_ptr
->Event
.MouseEvent
, &inev
);
699 kbd_buffer_store_event_hold (&inev
, hold_quit
);
702 case WINDOW_BUFFER_SIZE_EVENT
:
703 if (w32_use_full_screen_buffer
)
704 resize_event (&queue_ptr
->Event
.WindowBufferSizeEvent
);
709 /* Internal event types, ignored. */
717 if (ret
> 0 || expected
== 0)
721 /* We don't get told about changes in the window size (only the buffer
722 size, which we no longer care about), so we have to check it
724 if (!w32_use_full_screen_buffer
)
725 maybe_generate_resize_event ();
731 /* arch-tag: 0bcb39b7-d085-4b85-9070-6750e8c03047
732 (do not change this comment) */