]> code.delx.au - gnu-emacs/blob - src/w32inevt.c
(Qouter_window_id): New variable.
[gnu-emacs] / src / w32inevt.c
1 /* Input event support for Emacs on the Microsoft W32 API.
2 Copyright (C) 1992, 1993, 1995 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
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)
9 any later version.
10
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.
15
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.
20
21 Drew Bliss 01-Oct-93
22 Adapted from ntkbd.c by Tim Fleehart
23 */
24
25
26 #include "config.h"
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <windows.h>
31
32 #include "lisp.h"
33 #include "frame.h"
34 #include "blockinput.h"
35 #include "termhooks.h"
36 #include "w32heap.h"
37 #include "w32term.h"
38
39 /* stdin, from ntterm */
40 extern HANDLE keyboard_handle;
41
42 /* Info for last mouse motion */
43 static COORD movement_pos;
44 static DWORD movement_time;
45
46 /* from keyboard.c */
47 extern void reinvoke_input_signal (void);
48
49 /* from dispnew.c */
50 extern int change_frame_size (FRAME_PTR, int, int, int, int);
51
52 /* from w32fns.c */
53 extern Lisp_Object Vw32_alt_is_meta;
54 extern unsigned int map_keypad_keys (unsigned int, unsigned int);
55
56 /* from w32term */
57 extern Lisp_Object Vw32_capslock_is_shiftlock;
58 extern Lisp_Object Vw32_enable_caps_lock;
59 extern Lisp_Object Vw32_enable_num_lock;
60 extern Lisp_Object Vw32_recognize_altgr;
61 extern Lisp_Object Vw32_pass_lwindow_to_system;
62 extern Lisp_Object Vw32_pass_rwindow_to_system;
63 extern Lisp_Object Vw32_lwindow_modifier;
64 extern Lisp_Object Vw32_rwindow_modifier;
65 extern Lisp_Object Vw32_apps_modifier;
66 extern Lisp_Object Vw32_scroll_lock_modifier;
67 extern unsigned int w32_key_to_modifier (int key);
68
69 /* Event queue */
70 #define EVENT_QUEUE_SIZE 50
71 static INPUT_RECORD event_queue[EVENT_QUEUE_SIZE];
72 static INPUT_RECORD *queue_ptr = event_queue, *queue_end = event_queue;
73
74 static int
75 fill_queue (BOOL block)
76 {
77 BOOL rc;
78 DWORD events_waiting;
79
80 if (queue_ptr < queue_end)
81 return queue_end-queue_ptr;
82
83 if (!block)
84 {
85 /* Check to see if there are some events to read before we try
86 because we can't block. */
87 if (!GetNumberOfConsoleInputEvents (keyboard_handle, &events_waiting))
88 return -1;
89 if (events_waiting == 0)
90 return 0;
91 }
92
93 rc = ReadConsoleInput (keyboard_handle, event_queue, EVENT_QUEUE_SIZE,
94 &events_waiting);
95 if (!rc)
96 return -1;
97 queue_ptr = event_queue;
98 queue_end = event_queue + events_waiting;
99 return (int) events_waiting;
100 }
101
102 /* In a generic, multi-frame world this should take a console handle
103 and return the frame for it
104
105 Right now, there's only one frame so return it. */
106 static FRAME_PTR
107 get_frame (void)
108 {
109 return selected_frame;
110 }
111
112 /* Translate console modifiers to emacs modifiers.
113 German keyboard support (Kai Morgan Zeise 2/18/95). */
114 int
115 w32_kbd_mods_to_emacs (DWORD mods, WORD key)
116 {
117 int retval = 0;
118
119 /* If we recognize right-alt and left-ctrl as AltGr, and it has been
120 pressed, first remove those modifiers. */
121 if (!NILP (Vw32_recognize_altgr)
122 && (mods & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
123 == (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
124 mods &= ~ (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED);
125
126 if (mods & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
127 retval = ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier);
128
129 if (mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
130 {
131 retval |= ctrl_modifier;
132 if ((mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
133 == (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
134 retval |= meta_modifier;
135 }
136
137 if (mods & LEFT_WIN_PRESSED)
138 retval |= w32_key_to_modifier (VK_LWIN);
139 if (mods & RIGHT_WIN_PRESSED)
140 retval |= w32_key_to_modifier (VK_RWIN);
141 if (mods & APPS_PRESSED)
142 retval |= w32_key_to_modifier (VK_APPS);
143 if (mods & SCROLLLOCK_ON)
144 retval |= w32_key_to_modifier (VK_SCROLL);
145
146 /* Just in case someone wanted the original behaviour, make it
147 optional by setting w32-capslock-is-shiftlock to t. */
148 if (NILP (Vw32_capslock_is_shiftlock)
149 /* Keys that should _not_ be affected by CapsLock. */
150 && ( (key == VK_BACK)
151 || (key == VK_TAB)
152 || (key == VK_CLEAR)
153 || (key == VK_RETURN)
154 || (key == VK_ESCAPE)
155 || ((key >= VK_SPACE) && (key <= VK_HELP))
156 || ((key >= VK_NUMPAD0) && (key <= VK_F24))
157 || ((key >= VK_NUMPAD_CLEAR) && (key <= VK_NUMPAD_DELETE))
158 ))
159 {
160 /* Only consider shift state. */
161 if ((mods & SHIFT_PRESSED) != 0)
162 retval |= shift_modifier;
163 }
164 else
165 {
166 /* Ignore CapsLock state if not enabled. */
167 if (NILP (Vw32_enable_caps_lock))
168 mods &= ~CAPSLOCK_ON;
169 if ((mods & (SHIFT_PRESSED | CAPSLOCK_ON)) != 0)
170 retval |= shift_modifier;
171 }
172
173 return retval;
174 }
175
176 #if 0
177 /* Return nonzero if the virtual key is a dead key. */
178 static int
179 is_dead_key (int wparam)
180 {
181 unsigned int code = MapVirtualKey (wparam, 2);
182
183 /* Windows 95 returns 0x8000, NT returns 0x80000000. */
184 return (code & 0x80008000) ? 1 : 0;
185 }
186 #endif
187
188 /* The return code indicates key code size. */
189 int
190 w32_kbd_patch_key (KEY_EVENT_RECORD *event)
191 {
192 unsigned int key_code = event->wVirtualKeyCode;
193 unsigned int mods = event->dwControlKeyState;
194 BYTE keystate[256];
195 static BYTE ansi_code[4];
196 static int isdead = 0;
197
198 if (isdead == 2)
199 {
200 event->uChar.AsciiChar = ansi_code[2];
201 isdead = 0;
202 return 1;
203 }
204 if (event->uChar.AsciiChar != 0)
205 return 1;
206
207 memset (keystate, 0, sizeof (keystate));
208 keystate[key_code] = 0x80;
209 if (mods & SHIFT_PRESSED)
210 keystate[VK_SHIFT] = 0x80;
211 if (mods & CAPSLOCK_ON)
212 keystate[VK_CAPITAL] = 1;
213 /* If we recognize right-alt and left-ctrl as AltGr, set the key
214 states accordingly before invoking ToAscii. */
215 if (!NILP (Vw32_recognize_altgr)
216 && (mods & LEFT_CTRL_PRESSED) && (mods & RIGHT_ALT_PRESSED))
217 {
218 keystate[VK_CONTROL] = 0x80;
219 keystate[VK_LCONTROL] = 0x80;
220 keystate[VK_MENU] = 0x80;
221 keystate[VK_RMENU] = 0x80;
222 }
223
224 #if 0
225 /* Because of an OS bug, ToAscii corrupts the stack when called to
226 convert a dead key in console mode on NT4. Unfortunately, trying
227 to check for dead keys using MapVirtualKey doesn't work either -
228 these functions apparently use internal information about keyboard
229 layout which doesn't get properly updated in console programs when
230 changing layout (though apparently it gets partly updated,
231 otherwise ToAscii wouldn't crash). */
232 if (is_dead_key (event->wVirtualKeyCode))
233 return 0;
234 #endif
235
236 /* On NT, call ToUnicode instead and then convert to the current
237 locale's default codepage. */
238 if (os_subtype == OS_NT)
239 {
240 WCHAR buf[128];
241
242 isdead = ToUnicode (event->wVirtualKeyCode, event->wVirtualScanCode,
243 keystate, buf, 128, 0);
244 if (isdead > 0)
245 {
246 char cp[20];
247 int cpId;
248
249 GetLocaleInfo (GetThreadLocale (),
250 LOCALE_IDEFAULTANSICODEPAGE, cp, 20);
251 cpId = atoi (cp);
252 isdead = WideCharToMultiByte (cpId, 0, buf, isdead,
253 ansi_code, 4, NULL, NULL);
254 }
255 else
256 isdead = 0;
257 }
258 else
259 {
260 isdead = ToAscii (event->wVirtualKeyCode, event->wVirtualScanCode,
261 keystate, (LPWORD) ansi_code, 0);
262 }
263
264 if (isdead == 0)
265 return 0;
266 event->uChar.AsciiChar = ansi_code[0];
267 return isdead;
268 }
269
270
271 extern char *lispy_function_keys[];
272
273 /* return code -1 means that event_queue_ptr won't be incremented.
274 In other word, this event makes two key codes. (by himi) */
275 int
276 key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
277 {
278 static int faked_key = 0;
279 static int mod_key_state = 0;
280 int wParam;
281
282 *isdead = 0;
283
284 /* Skip key-up events. */
285 if (!event->bKeyDown)
286 {
287 switch (event->wVirtualKeyCode)
288 {
289 case VK_LWIN:
290 mod_key_state &= ~LEFT_WIN_PRESSED;
291 break;
292 case VK_RWIN:
293 mod_key_state &= ~RIGHT_WIN_PRESSED;
294 break;
295 case VK_APPS:
296 mod_key_state &= ~APPS_PRESSED;
297 break;
298 }
299 return 0;
300 }
301
302 /* Ignore keystrokes we fake ourself; see below. */
303 if (faked_key == event->wVirtualKeyCode)
304 {
305 faked_key = 0;
306 return 0;
307 }
308
309 /* To make it easier to debug this code, ignore modifier keys! */
310 switch (event->wVirtualKeyCode)
311 {
312 case VK_LWIN:
313 if (NILP (Vw32_pass_lwindow_to_system))
314 {
315 /* Prevent system from acting on keyup (which opens the Start
316 menu if no other key was pressed) by simulating a press of
317 Space which we will ignore. */
318 if ((mod_key_state & LEFT_WIN_PRESSED) == 0)
319 {
320 faked_key = VK_SPACE;
321 keybd_event (VK_SPACE, (BYTE) MapVirtualKey (VK_SPACE, 0), 0, 0);
322 }
323 }
324 mod_key_state |= LEFT_WIN_PRESSED;
325 if (!NILP (Vw32_lwindow_modifier))
326 return 0;
327 break;
328 case VK_RWIN:
329 if (NILP (Vw32_pass_rwindow_to_system))
330 {
331 if ((mod_key_state & RIGHT_WIN_PRESSED) == 0)
332 {
333 faked_key = VK_SPACE;
334 keybd_event (VK_SPACE, (BYTE) MapVirtualKey (VK_SPACE, 0), 0, 0);
335 }
336 }
337 mod_key_state |= RIGHT_WIN_PRESSED;
338 if (!NILP (Vw32_rwindow_modifier))
339 return 0;
340 break;
341 case VK_APPS:
342 mod_key_state |= APPS_PRESSED;
343 if (!NILP (Vw32_apps_modifier))
344 return 0;
345 break;
346 case VK_CAPITAL:
347 /* Decide whether to treat as modifier or function key. */
348 if (NILP (Vw32_enable_caps_lock))
349 goto disable_lock_key;
350 return 0;
351 case VK_NUMLOCK:
352 /* Decide whether to treat as modifier or function key. */
353 if (NILP (Vw32_enable_num_lock))
354 goto disable_lock_key;
355 return 0;
356 case VK_SCROLL:
357 /* Decide whether to treat as modifier or function key. */
358 if (NILP (Vw32_scroll_lock_modifier))
359 goto disable_lock_key;
360 return 0;
361 disable_lock_key:
362 /* Ensure the appropriate lock key state is off (and the
363 indicator light as well). */
364 wParam = event->wVirtualKeyCode;
365 if (GetAsyncKeyState (wParam) & 0x8000)
366 {
367 /* Fake another press of the relevant key. Apparently, this
368 really is the only way to turn off the indicator. */
369 faked_key = wParam;
370 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
371 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
372 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
373 KEYEVENTF_EXTENDEDKEY | 0, 0);
374 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
375 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
376 }
377 break;
378 case VK_MENU:
379 case VK_CONTROL:
380 case VK_SHIFT:
381 return 0;
382 }
383
384 /* Recognize state of Windows and Apps keys. */
385 event->dwControlKeyState |= mod_key_state;
386
387 /* Distinguish numeric keypad keys from extended keys. */
388 event->wVirtualKeyCode =
389 map_keypad_keys (event->wVirtualKeyCode,
390 (event->dwControlKeyState & ENHANCED_KEY));
391
392 if (lispy_function_keys[event->wVirtualKeyCode] == 0)
393 {
394 emacs_ev->kind = ascii_keystroke;
395
396 if (!NILP (Vw32_recognize_altgr)
397 && (event->dwControlKeyState & LEFT_CTRL_PRESSED)
398 && (event->dwControlKeyState & RIGHT_ALT_PRESSED))
399 {
400 /* Don't try to interpret AltGr key chords; ToAscii seems not
401 to process them correctly. */
402 }
403 /* Handle key chords including any modifiers other than shift
404 directly, in order to preserve as much modifier information as
405 possible. */
406 else if (event->dwControlKeyState
407 & ( RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED
408 | RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED
409 | (!NILP (Vw32_lwindow_modifier) ? LEFT_WIN_PRESSED : 0)
410 | (!NILP (Vw32_rwindow_modifier) ? RIGHT_WIN_PRESSED : 0)
411 | (!NILP (Vw32_apps_modifier) ? APPS_PRESSED : 0)
412 | (!NILP (Vw32_scroll_lock_modifier) ? SCROLLLOCK_ON : 0)))
413 {
414 /* Don't translate modified alphabetic keystrokes, so the user
415 doesn't need to constantly switch layout to type control or
416 meta keystrokes when the normal layout translates
417 alphabetic characters to non-ascii characters. */
418 if ('A' <= event->wVirtualKeyCode && event->wVirtualKeyCode <= 'Z')
419 {
420 event->uChar.AsciiChar = event->wVirtualKeyCode;
421 if ((event->dwControlKeyState & SHIFT_PRESSED) == 0)
422 event->uChar.AsciiChar += ('a' - 'A');
423 }
424 /* Try to handle unrecognized keystrokes by determining the
425 base character (ie. translating the base key plus shift
426 modifier). */
427 else if (event->uChar.AsciiChar == 0)
428 w32_kbd_patch_key (event);
429 }
430 if (event->uChar.AsciiChar == 0)
431 return 0;
432 XSETINT (emacs_ev->code, event->uChar.AsciiChar);
433 }
434 else
435 {
436 emacs_ev->kind = non_ascii_keystroke;
437 XSETINT (emacs_ev->code, event->wVirtualKeyCode);
438 }
439
440 XSETFRAME (emacs_ev->frame_or_window, get_frame ());
441 emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState,
442 event->wVirtualKeyCode);
443 emacs_ev->timestamp = GetTickCount ();
444 return 1;
445 }
446
447 /* Mouse position hook. */
448 void
449 w32_console_mouse_position (FRAME_PTR *f,
450 #ifndef MULE
451 int insist,
452 #endif
453 Lisp_Object *bar_window,
454 enum scroll_bar_part *part,
455 Lisp_Object *x,
456 Lisp_Object *y,
457 unsigned long *time)
458 {
459 BLOCK_INPUT;
460
461 #ifndef MULE
462 insist = insist;
463 #endif
464
465 *f = get_frame ();
466 *bar_window = Qnil;
467 *part = 0;
468 selected_frame->mouse_moved = 0;
469
470 *x = movement_pos.X;
471 *y = movement_pos.Y;
472 *time = movement_time;
473
474 UNBLOCK_INPUT;
475 }
476
477 /* Remember mouse motion and notify emacs. */
478 static void
479 mouse_moved_to (int x, int y)
480 {
481 /* If we're in the same place, ignore it */
482 if (x != movement_pos.X || y != movement_pos.Y)
483 {
484 selected_frame->mouse_moved = 1;
485 movement_pos.X = x;
486 movement_pos.Y = y;
487 movement_time = GetTickCount ();
488 }
489 }
490
491 /* Consoles return button bits in a strange order:
492 least significant - Leftmost button
493 next - Rightmost button
494 next - Leftmost+1
495 next - Leftmost+2...
496
497 Assume emacs likes three button mice, so
498 Left == 0
499 Middle == 1
500 Right == 2
501 Others increase from there. */
502
503 static int emacs_button_translation[NUM_MOUSE_BUTTONS] =
504 {
505 0, 2, 1, 3, 4,
506 };
507
508 static int
509 do_mouse_event (MOUSE_EVENT_RECORD *event,
510 struct input_event *emacs_ev)
511 {
512 static DWORD button_state = 0;
513 DWORD but_change, mask;
514 int i;
515
516 if (event->dwEventFlags == MOUSE_MOVED)
517 {
518 /* For movement events we just note that the mouse has moved
519 so that emacs will generate drag events. */
520 mouse_moved_to (event->dwMousePosition.X, event->dwMousePosition.Y);
521 return 0;
522 }
523
524 /* It looks like the console code sends us a mouse event with
525 dwButtonState == 0 when a window is activated. Ignore this case. */
526 if (event->dwButtonState == button_state)
527 return 0;
528
529 emacs_ev->kind = mouse_click;
530
531 /* Find out what button has changed state since the last button event. */
532 but_change = button_state ^ event->dwButtonState;
533 mask = 1;
534 for (i = 0; i < NUM_MOUSE_BUTTONS; i++, mask <<= 1)
535 if (but_change & mask)
536 {
537 XSETINT (emacs_ev->code, emacs_button_translation[i]);
538 break;
539 }
540
541 /* If the changed button is out of emacs' range (highly unlikely)
542 ignore this event. */
543 if (i == NUM_MOUSE_BUTTONS)
544 return 0;
545
546 button_state = event->dwButtonState;
547 emacs_ev->timestamp = GetTickCount ();
548 emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState, 0) |
549 ((event->dwButtonState & mask) ? down_modifier : up_modifier);
550
551 XSETFASTINT (emacs_ev->x, event->dwMousePosition.X);
552 XSETFASTINT (emacs_ev->y, event->dwMousePosition.Y);
553 /* for Mule 2.2 (Based on Emacs 19.28 */
554 #ifdef MULE
555 XSET (emacs_ev->frame_or_window, Lisp_Frame, get_frame ());
556 #else
557 XSETFRAME (emacs_ev->frame_or_window, get_frame ());
558 #endif
559
560 return 1;
561 }
562
563 static void
564 resize_event (WINDOW_BUFFER_SIZE_RECORD *event)
565 {
566 FRAME_PTR f = get_frame ();
567
568 change_frame_size (f, event->dwSize.Y, event->dwSize.X, 0, 1);
569 SET_FRAME_GARBAGED (f);
570 }
571
572 int
573 w32_console_read_socket (int sd, struct input_event *bufp, int numchars,
574 int expected)
575 {
576 BOOL no_events = TRUE;
577 int nev, ret = 0, add;
578 int isdead;
579
580 if (interrupt_input_blocked)
581 {
582 interrupt_input_pending = 1;
583 return -1;
584 }
585
586 interrupt_input_pending = 0;
587 BLOCK_INPUT;
588
589 for (;;)
590 {
591 nev = fill_queue (0);
592 if (nev <= 0)
593 {
594 /* If nev == -1, there was some kind of error
595 If nev == 0 then waitp must be zero and no events were available
596 so return. */
597 UNBLOCK_INPUT;
598 return nev;
599 }
600
601 while (nev > 0 && numchars > 0)
602 {
603 switch (queue_ptr->EventType)
604 {
605 case KEY_EVENT:
606 add = key_event (&queue_ptr->Event.KeyEvent, bufp, &isdead);
607 if (add == -1) /* 95.7.25 by himi */
608 {
609 queue_ptr--;
610 add = 1;
611 }
612 bufp += add;
613 ret += add;
614 numchars -= add;
615 break;
616
617 case MOUSE_EVENT:
618 add = do_mouse_event (&queue_ptr->Event.MouseEvent, bufp);
619 bufp += add;
620 ret += add;
621 numchars -= add;
622 break;
623
624 case WINDOW_BUFFER_SIZE_EVENT:
625 resize_event (&queue_ptr->Event.WindowBufferSizeEvent);
626 break;
627
628 case MENU_EVENT:
629 case FOCUS_EVENT:
630 /* Internal event types, ignored. */
631 break;
632 }
633
634 queue_ptr++;
635 nev--;
636 }
637
638 if (ret > 0 || expected == 0)
639 break;
640 }
641
642 UNBLOCK_INPUT;
643 return ret;
644 }