1 /* Input event support for Emacs on the Microsoft W32 API.
2 Copyright (C) 1992, 1993, 1995 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 2, or (at your option)
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; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
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);
57 extern int change_frame_size (FRAME_PTR
, int, int, int, int);
59 /* from w32console.c */
60 extern int w32_use_full_screen_buffer
;
63 extern Lisp_Object Vw32_alt_is_meta
;
64 extern unsigned int map_keypad_keys (unsigned int, unsigned int);
67 extern Lisp_Object Vw32_capslock_is_shiftlock
;
68 extern Lisp_Object Vw32_enable_caps_lock
;
69 extern Lisp_Object Vw32_enable_num_lock
;
70 extern Lisp_Object Vw32_recognize_altgr
;
71 extern Lisp_Object Vw32_pass_lwindow_to_system
;
72 extern Lisp_Object Vw32_pass_rwindow_to_system
;
73 extern Lisp_Object Vw32_phantom_key_code
;
74 extern Lisp_Object Vw32_lwindow_modifier
;
75 extern Lisp_Object Vw32_rwindow_modifier
;
76 extern Lisp_Object Vw32_apps_modifier
;
77 extern Lisp_Object Vw32_scroll_lock_modifier
;
78 extern unsigned int w32_key_to_modifier (int key
);
81 #define EVENT_QUEUE_SIZE 50
82 static INPUT_RECORD event_queue
[EVENT_QUEUE_SIZE
];
83 static INPUT_RECORD
*queue_ptr
= event_queue
, *queue_end
= event_queue
;
86 fill_queue (BOOL block
)
91 if (queue_ptr
< queue_end
)
92 return queue_end
-queue_ptr
;
96 /* Check to see if there are some events to read before we try
97 because we can't block. */
98 if (!GetNumberOfConsoleInputEvents (keyboard_handle
, &events_waiting
))
100 if (events_waiting
== 0)
104 rc
= ReadConsoleInput (keyboard_handle
, event_queue
, EVENT_QUEUE_SIZE
,
108 queue_ptr
= event_queue
;
109 queue_end
= event_queue
+ events_waiting
;
110 return (int) events_waiting
;
113 /* In a generic, multi-frame world this should take a console handle
114 and return the frame for it
116 Right now, there's only one frame so return it. */
120 return SELECTED_FRAME ();
123 /* Translate console modifiers to emacs modifiers.
124 German keyboard support (Kai Morgan Zeise 2/18/95). */
126 w32_kbd_mods_to_emacs (DWORD mods
, WORD key
)
130 /* If we recognize right-alt and left-ctrl as AltGr, and it has been
131 pressed, first remove those modifiers. */
132 if (!NILP (Vw32_recognize_altgr
)
133 && (mods
& (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
))
134 == (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
))
135 mods
&= ~ (RIGHT_ALT_PRESSED
| LEFT_CTRL_PRESSED
);
137 if (mods
& (RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
))
138 retval
= ((NILP (Vw32_alt_is_meta
)) ? alt_modifier
: meta_modifier
);
140 if (mods
& (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
142 retval
|= ctrl_modifier
;
143 if ((mods
& (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
144 == (RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
))
145 retval
|= meta_modifier
;
148 if (mods
& LEFT_WIN_PRESSED
)
149 retval
|= w32_key_to_modifier (VK_LWIN
);
150 if (mods
& RIGHT_WIN_PRESSED
)
151 retval
|= w32_key_to_modifier (VK_RWIN
);
152 if (mods
& APPS_PRESSED
)
153 retval
|= w32_key_to_modifier (VK_APPS
);
154 if (mods
& SCROLLLOCK_ON
)
155 retval
|= w32_key_to_modifier (VK_SCROLL
);
157 /* Just in case someone wanted the original behaviour, make it
158 optional by setting w32-capslock-is-shiftlock to t. */
159 if (NILP (Vw32_capslock_is_shiftlock
)
160 /* Keys that should _not_ be affected by CapsLock. */
161 && ( (key
== VK_BACK
)
164 || (key
== VK_RETURN
)
165 || (key
== VK_ESCAPE
)
166 || ((key
>= VK_SPACE
) && (key
<= VK_HELP
))
167 || ((key
>= VK_NUMPAD0
) && (key
<= VK_F24
))
168 || ((key
>= VK_NUMPAD_CLEAR
) && (key
<= VK_NUMPAD_DELETE
))
171 /* Only consider shift state. */
172 if ((mods
& SHIFT_PRESSED
) != 0)
173 retval
|= shift_modifier
;
177 /* Ignore CapsLock state if not enabled. */
178 if (NILP (Vw32_enable_caps_lock
))
179 mods
&= ~CAPSLOCK_ON
;
180 if ((mods
& (SHIFT_PRESSED
| CAPSLOCK_ON
)) != 0)
181 retval
|= shift_modifier
;
188 /* Return nonzero if the virtual key is a dead key. */
190 is_dead_key (int wparam
)
192 unsigned int code
= MapVirtualKey (wparam
, 2);
194 /* Windows 95 returns 0x8000, NT returns 0x80000000. */
195 return (code
& 0x80008000) ? 1 : 0;
199 /* The return code indicates key code size. */
201 w32_kbd_patch_key (KEY_EVENT_RECORD
*event
)
203 unsigned int key_code
= event
->wVirtualKeyCode
;
204 unsigned int mods
= event
->dwControlKeyState
;
206 static BYTE ansi_code
[4];
207 static int isdead
= 0;
211 event
->uChar
.AsciiChar
= ansi_code
[2];
215 if (event
->uChar
.AsciiChar
!= 0)
218 memset (keystate
, 0, sizeof (keystate
));
219 keystate
[key_code
] = 0x80;
220 if (mods
& SHIFT_PRESSED
)
221 keystate
[VK_SHIFT
] = 0x80;
222 if (mods
& CAPSLOCK_ON
)
223 keystate
[VK_CAPITAL
] = 1;
224 /* If we recognize right-alt and left-ctrl as AltGr, set the key
225 states accordingly before invoking ToAscii. */
226 if (!NILP (Vw32_recognize_altgr
)
227 && (mods
& LEFT_CTRL_PRESSED
) && (mods
& RIGHT_ALT_PRESSED
))
229 keystate
[VK_CONTROL
] = 0x80;
230 keystate
[VK_LCONTROL
] = 0x80;
231 keystate
[VK_MENU
] = 0x80;
232 keystate
[VK_RMENU
] = 0x80;
236 /* Because of an OS bug, ToAscii corrupts the stack when called to
237 convert a dead key in console mode on NT4. Unfortunately, trying
238 to check for dead keys using MapVirtualKey doesn't work either -
239 these functions apparently use internal information about keyboard
240 layout which doesn't get properly updated in console programs when
241 changing layout (though apparently it gets partly updated,
242 otherwise ToAscii wouldn't crash). */
243 if (is_dead_key (event
->wVirtualKeyCode
))
247 /* On NT, call ToUnicode instead and then convert to the current
248 locale's default codepage. */
249 if (os_subtype
== OS_NT
)
253 isdead
= ToUnicode (event
->wVirtualKeyCode
, event
->wVirtualScanCode
,
254 keystate
, buf
, 128, 0);
260 GetLocaleInfo (GetThreadLocale (),
261 LOCALE_IDEFAULTANSICODEPAGE
, cp
, 20);
263 isdead
= WideCharToMultiByte (cpId
, 0, buf
, isdead
,
264 ansi_code
, 4, NULL
, NULL
);
271 isdead
= ToAscii (event
->wVirtualKeyCode
, event
->wVirtualScanCode
,
272 keystate
, (LPWORD
) ansi_code
, 0);
277 event
->uChar
.AsciiChar
= ansi_code
[0];
282 extern char *lispy_function_keys
[];
284 static int faked_key
= 0;
286 /* return code -1 means that event_queue_ptr won't be incremented.
287 In other word, this event makes two key codes. (by himi) */
289 key_event (KEY_EVENT_RECORD
*event
, struct input_event
*emacs_ev
, int *isdead
)
291 static int mod_key_state
= 0;
296 /* Skip key-up events. */
297 if (!event
->bKeyDown
)
299 switch (event
->wVirtualKeyCode
)
302 mod_key_state
&= ~LEFT_WIN_PRESSED
;
305 mod_key_state
&= ~RIGHT_WIN_PRESSED
;
308 mod_key_state
&= ~APPS_PRESSED
;
314 /* Ignore keystrokes we fake ourself; see below. */
315 if (faked_key
== event
->wVirtualKeyCode
)
321 /* To make it easier to debug this code, ignore modifier keys! */
322 switch (event
->wVirtualKeyCode
)
325 if (NILP (Vw32_pass_lwindow_to_system
))
327 /* Prevent system from acting on keyup (which opens the Start
328 menu if no other key was pressed) by simulating a press of
329 Space which we will ignore. */
330 if ((mod_key_state
& LEFT_WIN_PRESSED
) == 0)
332 if (NUMBERP (Vw32_phantom_key_code
))
333 faked_key
= XUINT (Vw32_phantom_key_code
) & 255;
335 faked_key
= VK_SPACE
;
336 keybd_event (faked_key
, (BYTE
) MapVirtualKey (faked_key
, 0), 0, 0);
339 mod_key_state
|= LEFT_WIN_PRESSED
;
340 if (!NILP (Vw32_lwindow_modifier
))
344 if (NILP (Vw32_pass_rwindow_to_system
))
346 if ((mod_key_state
& RIGHT_WIN_PRESSED
) == 0)
348 if (NUMBERP (Vw32_phantom_key_code
))
349 faked_key
= XUINT (Vw32_phantom_key_code
) & 255;
351 faked_key
= VK_SPACE
;
352 keybd_event (faked_key
, (BYTE
) MapVirtualKey (faked_key
, 0), 0, 0);
355 mod_key_state
|= RIGHT_WIN_PRESSED
;
356 if (!NILP (Vw32_rwindow_modifier
))
360 mod_key_state
|= APPS_PRESSED
;
361 if (!NILP (Vw32_apps_modifier
))
365 /* Decide whether to treat as modifier or function key. */
366 if (NILP (Vw32_enable_caps_lock
))
367 goto disable_lock_key
;
370 /* Decide whether to treat as modifier or function key. */
371 if (NILP (Vw32_enable_num_lock
))
372 goto disable_lock_key
;
375 /* Decide whether to treat as modifier or function key. */
376 if (NILP (Vw32_scroll_lock_modifier
))
377 goto disable_lock_key
;
380 /* Ensure the appropriate lock key state is off (and the
381 indicator light as well). */
382 wParam
= event
->wVirtualKeyCode
;
383 if (GetAsyncKeyState (wParam
) & 0x8000)
385 /* Fake another press of the relevant key. Apparently, this
386 really is the only way to turn off the indicator. */
388 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
389 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
390 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
391 KEYEVENTF_EXTENDEDKEY
| 0, 0);
392 keybd_event ((BYTE
) wParam
, (BYTE
) MapVirtualKey (wParam
, 0),
393 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
401 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
402 which is confusing for purposes of key binding; convert
403 VK_CANCEL events into VK_PAUSE events. */
404 event
->wVirtualKeyCode
= VK_PAUSE
;
407 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
408 for purposes of key binding; convert these back into
409 VK_NUMLOCK events, at least when we want to see NumLock key
410 presses. (Note that there is never any possibility that
411 VK_PAUSE with Ctrl really is C-Pause as per above.) */
412 if (NILP (Vw32_enable_num_lock
)
413 && (event
->dwControlKeyState
414 & (LEFT_CTRL_PRESSED
| RIGHT_CTRL_PRESSED
)) != 0)
415 event
->wVirtualKeyCode
= VK_NUMLOCK
;
419 /* Recognize state of Windows and Apps keys. */
420 event
->dwControlKeyState
|= mod_key_state
;
422 /* Distinguish numeric keypad keys from extended keys. */
423 event
->wVirtualKeyCode
=
424 map_keypad_keys (event
->wVirtualKeyCode
,
425 (event
->dwControlKeyState
& ENHANCED_KEY
));
427 if (lispy_function_keys
[event
->wVirtualKeyCode
] == 0)
429 emacs_ev
->kind
= ascii_keystroke
;
431 if (!NILP (Vw32_recognize_altgr
)
432 && (event
->dwControlKeyState
& LEFT_CTRL_PRESSED
)
433 && (event
->dwControlKeyState
& RIGHT_ALT_PRESSED
))
435 /* Don't try to interpret AltGr key chords; ToAscii seems not
436 to process them correctly. */
438 /* Handle key chords including any modifiers other than shift
439 directly, in order to preserve as much modifier information as
441 else if (event
->dwControlKeyState
442 & ( RIGHT_CTRL_PRESSED
| LEFT_CTRL_PRESSED
443 | RIGHT_ALT_PRESSED
| LEFT_ALT_PRESSED
444 | (!NILP (Vw32_lwindow_modifier
) ? LEFT_WIN_PRESSED
: 0)
445 | (!NILP (Vw32_rwindow_modifier
) ? RIGHT_WIN_PRESSED
: 0)
446 | (!NILP (Vw32_apps_modifier
) ? APPS_PRESSED
: 0)
447 | (!NILP (Vw32_scroll_lock_modifier
) ? SCROLLLOCK_ON
: 0)))
449 /* Don't translate modified alphabetic keystrokes, so the user
450 doesn't need to constantly switch layout to type control or
451 meta keystrokes when the normal layout translates
452 alphabetic characters to non-ascii characters. */
453 if ('A' <= event
->wVirtualKeyCode
&& event
->wVirtualKeyCode
<= 'Z')
455 event
->uChar
.AsciiChar
= event
->wVirtualKeyCode
;
456 if ((event
->dwControlKeyState
& SHIFT_PRESSED
) == 0)
457 event
->uChar
.AsciiChar
+= ('a' - 'A');
459 /* Try to handle unrecognized keystrokes by determining the
460 base character (ie. translating the base key plus shift
462 else if (event
->uChar
.AsciiChar
== 0)
463 w32_kbd_patch_key (event
);
465 if (event
->uChar
.AsciiChar
== 0)
467 XSETINT (emacs_ev
->code
, event
->uChar
.AsciiChar
);
471 emacs_ev
->kind
= non_ascii_keystroke
;
472 XSETINT (emacs_ev
->code
, event
->wVirtualKeyCode
);
475 XSETFRAME (emacs_ev
->frame_or_window
, get_frame ());
476 emacs_ev
->modifiers
= w32_kbd_mods_to_emacs (event
->dwControlKeyState
,
477 event
->wVirtualKeyCode
);
478 emacs_ev
->timestamp
= GetTickCount ();
483 w32_console_toggle_lock_key (int vk_code
, Lisp_Object new_state
)
485 int cur_state
= (GetKeyState (vk_code
) & 1);
488 || (NUMBERP (new_state
)
489 && ((XUINT (new_state
)) & 1) != cur_state
))
493 keybd_event ((BYTE
) vk_code
,
494 (BYTE
) MapVirtualKey (vk_code
, 0),
495 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
496 keybd_event ((BYTE
) vk_code
,
497 (BYTE
) MapVirtualKey (vk_code
, 0),
498 KEYEVENTF_EXTENDEDKEY
| 0, 0);
499 keybd_event ((BYTE
) vk_code
,
500 (BYTE
) MapVirtualKey (vk_code
, 0),
501 KEYEVENTF_EXTENDEDKEY
| KEYEVENTF_KEYUP
, 0);
502 cur_state
= !cur_state
;
508 /* Mouse position hook. */
510 w32_console_mouse_position (FRAME_PTR
*f
,
512 Lisp_Object
*bar_window
,
513 enum scroll_bar_part
*part
,
525 SELECTED_FRAME ()->mouse_moved
= 0;
529 *time
= movement_time
;
534 /* Remember mouse motion and notify emacs. */
536 mouse_moved_to (int x
, int y
)
538 /* If we're in the same place, ignore it */
539 if (x
!= movement_pos
.X
|| y
!= movement_pos
.Y
)
541 SELECTED_FRAME ()->mouse_moved
= 1;
544 movement_time
= GetTickCount ();
548 /* Consoles return button bits in a strange order:
549 least significant - Leftmost button
550 next - Rightmost button
554 Assume emacs likes three button mice, so
558 Others increase from there. */
560 #define NUM_TRANSLATED_MOUSE_BUTTONS 3
561 static int emacs_button_translation
[NUM_TRANSLATED_MOUSE_BUTTONS
] =
567 do_mouse_event (MOUSE_EVENT_RECORD
*event
,
568 struct input_event
*emacs_ev
)
570 static DWORD button_state
= 0;
571 DWORD but_change
, mask
;
574 if (event
->dwEventFlags
== MOUSE_MOVED
)
576 /* For movement events we just note that the mouse has moved
577 so that emacs will generate drag events. */
578 mouse_moved_to (event
->dwMousePosition
.X
, event
->dwMousePosition
.Y
);
582 /* It looks like the console code sends us a mouse event with
583 dwButtonState == 0 when a window is activated. Ignore this case. */
584 if (event
->dwButtonState
== button_state
)
587 emacs_ev
->kind
= mouse_click
;
589 /* Find out what button has changed state since the last button event. */
590 but_change
= button_state
^ event
->dwButtonState
;
592 for (i
= 0; mask
; i
++, mask
<<= 1)
593 if (but_change
& mask
)
595 if (i
< NUM_TRANSLATED_MOUSE_BUTTONS
)
596 XSETINT (emacs_ev
->code
, emacs_button_translation
[i
]);
598 XSETINT (emacs_ev
->code
, i
);
602 button_state
= event
->dwButtonState
;
603 emacs_ev
->timestamp
= GetTickCount ();
604 emacs_ev
->modifiers
= w32_kbd_mods_to_emacs (event
->dwControlKeyState
, 0) |
605 ((event
->dwButtonState
& mask
) ? down_modifier
: up_modifier
);
607 XSETFASTINT (emacs_ev
->x
, event
->dwMousePosition
.X
);
608 XSETFASTINT (emacs_ev
->y
, event
->dwMousePosition
.Y
);
609 /* for Mule 2.2 (Based on Emacs 19.28 */
611 XSET (emacs_ev
->frame_or_window
, Lisp_Frame
, get_frame ());
613 XSETFRAME (emacs_ev
->frame_or_window
, get_frame ());
620 resize_event (WINDOW_BUFFER_SIZE_RECORD
*event
)
622 FRAME_PTR f
= get_frame ();
624 change_frame_size (f
, event
->dwSize
.Y
, event
->dwSize
.X
, 0, 1);
625 SET_FRAME_GARBAGED (f
);
629 maybe_generate_resize_event ()
631 CONSOLE_SCREEN_BUFFER_INFO info
;
632 FRAME_PTR f
= get_frame ();
634 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE
), &info
);
636 /* It is okay to call this unconditionally, since it will do nothing
637 if the size hasn't actually changed. */
638 change_frame_size (f
,
639 1 + info
.srWindow
.Bottom
- info
.srWindow
.Top
,
640 1 + info
.srWindow
.Right
- info
.srWindow
.Left
,
645 w32_console_read_socket (int sd
, struct input_event
*bufp
, int numchars
,
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
673 while (nev
> 0 && numchars
> 0)
675 switch (queue_ptr
->EventType
)
678 add
= key_event (&queue_ptr
->Event
.KeyEvent
, bufp
, &isdead
);
679 if (add
== -1) /* 95.7.25 by himi */
690 add
= do_mouse_event (&queue_ptr
->Event
.MouseEvent
, bufp
);
696 case WINDOW_BUFFER_SIZE_EVENT
:
697 if (w32_use_full_screen_buffer
)
698 resize_event (&queue_ptr
->Event
.WindowBufferSizeEvent
);
703 /* Internal event types, ignored. */
711 if (ret
> 0 || expected
== 0)
715 /* We don't get told about changes in the window size (only the buffer
716 size, which we no longer care about), so we have to check it
718 if (!w32_use_full_screen_buffer
)
719 maybe_generate_resize_event ();