]> code.delx.au - gnu-emacs/blob - src/w32inevt.c
Merge from emacs-23
[gnu-emacs] / src / w32inevt.c
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, 2011 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
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.
11
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.
16
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/>. */
19
20 /*
21 Drew Bliss 01-Oct-93
22 Adapted from ntkbd.c by Tim Fleehart
23 */
24
25
26 #include <config.h>
27 #include <stdio.h>
28 #include <windows.h>
29 #include <setjmp.h>
30
31 #ifndef MOUSE_MOVED
32 #define MOUSE_MOVED 1
33 #endif
34
35 #include "lisp.h"
36 #include "keyboard.h"
37 #include "frame.h"
38 #include "dispextern.h"
39 #include "blockinput.h"
40 #include "termhooks.h"
41 #include "w32heap.h"
42 #include "w32term.h"
43
44 /* stdin, from ntterm */
45 extern HANDLE keyboard_handle;
46
47 /* Info for last mouse motion */
48 static COORD movement_pos;
49 static DWORD movement_time;
50
51 /* from keyboard.c */
52 extern void reinvoke_input_signal (void);
53
54 /* from w32console.c */
55 extern int w32_use_full_screen_buffer;
56
57 /* from w32fns.c */
58 extern Lisp_Object Vw32_alt_is_meta;
59 extern unsigned int map_keypad_keys (unsigned int, unsigned int);
60
61 /* from w32term */
62 extern Lisp_Object Vw32_capslock_is_shiftlock;
63 extern Lisp_Object Vw32_enable_caps_lock;
64 extern Lisp_Object Vw32_enable_num_lock;
65 extern Lisp_Object Vw32_recognize_altgr;
66 extern Lisp_Object Vw32_pass_lwindow_to_system;
67 extern Lisp_Object Vw32_pass_rwindow_to_system;
68 extern Lisp_Object Vw32_phantom_key_code;
69 extern Lisp_Object Vw32_lwindow_modifier;
70 extern Lisp_Object Vw32_rwindow_modifier;
71 extern Lisp_Object Vw32_apps_modifier;
72 extern Lisp_Object Vw32_scroll_lock_modifier;
73 extern unsigned int w32_key_to_modifier (int key);
74
75 /* Event queue */
76 #define EVENT_QUEUE_SIZE 50
77 static INPUT_RECORD event_queue[EVENT_QUEUE_SIZE];
78 static INPUT_RECORD *queue_ptr = event_queue, *queue_end = event_queue;
79
80 /* Temporarily store lead byte of DBCS input sequences. */
81 static char dbcs_lead = 0;
82
83 static int
84 fill_queue (BOOL block)
85 {
86 BOOL rc;
87 DWORD events_waiting;
88
89 if (queue_ptr < queue_end)
90 return queue_end-queue_ptr;
91
92 if (!block)
93 {
94 /* Check to see if there are some events to read before we try
95 because we can't block. */
96 if (!GetNumberOfConsoleInputEvents (keyboard_handle, &events_waiting))
97 return -1;
98 if (events_waiting == 0)
99 return 0;
100 }
101
102 rc = ReadConsoleInput (keyboard_handle, event_queue, EVENT_QUEUE_SIZE,
103 &events_waiting);
104 if (!rc)
105 return -1;
106 queue_ptr = event_queue;
107 queue_end = event_queue + events_waiting;
108 return (int) events_waiting;
109 }
110
111 /* In a generic, multi-frame world this should take a console handle
112 and return the frame for it
113
114 Right now, there's only one frame so return it. */
115 static FRAME_PTR
116 get_frame (void)
117 {
118 return SELECTED_FRAME ();
119 }
120
121 /* Translate console modifiers to emacs modifiers.
122 German keyboard support (Kai Morgan Zeise 2/18/95). */
123 int
124 w32_kbd_mods_to_emacs (DWORD mods, WORD key)
125 {
126 int retval = 0;
127
128 /* If we recognize right-alt and left-ctrl as AltGr, and it has been
129 pressed, first remove those modifiers. */
130 if (!NILP (Vw32_recognize_altgr)
131 && (mods & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
132 == (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
133 mods &= ~ (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED);
134
135 if (mods & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
136 retval = ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier);
137
138 if (mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
139 {
140 retval |= ctrl_modifier;
141 if ((mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
142 == (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
143 retval |= meta_modifier;
144 }
145
146 if (mods & LEFT_WIN_PRESSED)
147 retval |= w32_key_to_modifier (VK_LWIN);
148 if (mods & RIGHT_WIN_PRESSED)
149 retval |= w32_key_to_modifier (VK_RWIN);
150 if (mods & APPS_PRESSED)
151 retval |= w32_key_to_modifier (VK_APPS);
152 if (mods & SCROLLLOCK_ON)
153 retval |= w32_key_to_modifier (VK_SCROLL);
154
155 /* Just in case someone wanted the original behavior, make it
156 optional by setting w32-capslock-is-shiftlock to t. */
157 if (NILP (Vw32_capslock_is_shiftlock)
158 /* Keys that should _not_ be affected by CapsLock. */
159 && ( (key == VK_BACK)
160 || (key == VK_TAB)
161 || (key == VK_CLEAR)
162 || (key == VK_RETURN)
163 || (key == VK_ESCAPE)
164 || ((key >= VK_SPACE) && (key <= VK_HELP))
165 || ((key >= VK_NUMPAD0) && (key <= VK_F24))
166 || ((key >= VK_NUMPAD_CLEAR) && (key <= VK_NUMPAD_DELETE))
167 ))
168 {
169 /* Only consider shift state. */
170 if ((mods & SHIFT_PRESSED) != 0)
171 retval |= shift_modifier;
172 }
173 else
174 {
175 /* Ignore CapsLock state if not enabled. */
176 if (NILP (Vw32_enable_caps_lock))
177 mods &= ~CAPSLOCK_ON;
178 if ((mods & (SHIFT_PRESSED | CAPSLOCK_ON)) != 0)
179 retval |= shift_modifier;
180 }
181
182 return retval;
183 }
184
185 #if 0
186 /* Return nonzero if the virtual key is a dead key. */
187 static int
188 is_dead_key (int wparam)
189 {
190 unsigned int code = MapVirtualKey (wparam, 2);
191
192 /* Windows 95 returns 0x8000, NT returns 0x80000000. */
193 return (code & 0x80008000) ? 1 : 0;
194 }
195 #endif
196
197 /* The return code indicates key code size. */
198 int
199 w32_kbd_patch_key (KEY_EVENT_RECORD *event)
200 {
201 unsigned int key_code = event->wVirtualKeyCode;
202 unsigned int mods = event->dwControlKeyState;
203 BYTE keystate[256];
204 static BYTE ansi_code[4];
205 static int isdead = 0;
206
207 if (isdead == 2)
208 {
209 event->uChar.AsciiChar = ansi_code[2];
210 isdead = 0;
211 return 1;
212 }
213 if (event->uChar.AsciiChar != 0)
214 return 1;
215
216 memset (keystate, 0, sizeof (keystate));
217 keystate[key_code] = 0x80;
218 if (mods & SHIFT_PRESSED)
219 keystate[VK_SHIFT] = 0x80;
220 if (mods & CAPSLOCK_ON)
221 keystate[VK_CAPITAL] = 1;
222 /* If we recognize right-alt and left-ctrl as AltGr, set the key
223 states accordingly before invoking ToAscii. */
224 if (!NILP (Vw32_recognize_altgr)
225 && (mods & LEFT_CTRL_PRESSED) && (mods & RIGHT_ALT_PRESSED))
226 {
227 keystate[VK_CONTROL] = 0x80;
228 keystate[VK_LCONTROL] = 0x80;
229 keystate[VK_MENU] = 0x80;
230 keystate[VK_RMENU] = 0x80;
231 }
232
233 #if 0
234 /* Because of an OS bug, ToAscii corrupts the stack when called to
235 convert a dead key in console mode on NT4. Unfortunately, trying
236 to check for dead keys using MapVirtualKey doesn't work either -
237 these functions apparently use internal information about keyboard
238 layout which doesn't get properly updated in console programs when
239 changing layout (though apparently it gets partly updated,
240 otherwise ToAscii wouldn't crash). */
241 if (is_dead_key (event->wVirtualKeyCode))
242 return 0;
243 #endif
244
245 /* On NT, call ToUnicode instead and then convert to the current
246 locale's default codepage. */
247 if (os_subtype == OS_NT)
248 {
249 WCHAR buf[128];
250
251 isdead = ToUnicode (event->wVirtualKeyCode, event->wVirtualScanCode,
252 keystate, buf, 128, 0);
253 if (isdead > 0)
254 {
255 char cp[20];
256 int cpId;
257
258 event->uChar.UnicodeChar = buf[isdead - 1];
259
260 GetLocaleInfo (GetThreadLocale (),
261 LOCALE_IDEFAULTANSICODEPAGE, cp, 20);
262 cpId = atoi (cp);
263 isdead = WideCharToMultiByte (cpId, 0, buf, isdead,
264 ansi_code, 4, NULL, NULL);
265 }
266 else
267 isdead = 0;
268 }
269 else
270 {
271 isdead = ToAscii (event->wVirtualKeyCode, event->wVirtualScanCode,
272 keystate, (LPWORD) ansi_code, 0);
273 }
274
275 if (isdead == 0)
276 return 0;
277 event->uChar.AsciiChar = ansi_code[0];
278 return isdead;
279 }
280
281
282 extern const char *const lispy_function_keys[];
283
284 static int faked_key = 0;
285
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) */
288 static int
289 key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
290 {
291 static int mod_key_state = 0;
292 int wParam;
293
294 *isdead = 0;
295
296 /* Skip key-up events. */
297 if (!event->bKeyDown)
298 {
299 switch (event->wVirtualKeyCode)
300 {
301 case VK_LWIN:
302 mod_key_state &= ~LEFT_WIN_PRESSED;
303 break;
304 case VK_RWIN:
305 mod_key_state &= ~RIGHT_WIN_PRESSED;
306 break;
307 case VK_APPS:
308 mod_key_state &= ~APPS_PRESSED;
309 break;
310 }
311 return 0;
312 }
313
314 /* Ignore keystrokes we fake ourself; see below. */
315 if (faked_key == event->wVirtualKeyCode)
316 {
317 faked_key = 0;
318 return 0;
319 }
320
321 /* To make it easier to debug this code, ignore modifier keys! */
322 switch (event->wVirtualKeyCode)
323 {
324 case VK_LWIN:
325 if (NILP (Vw32_pass_lwindow_to_system))
326 {
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)
331 {
332 if (NUMBERP (Vw32_phantom_key_code))
333 faked_key = XUINT (Vw32_phantom_key_code) & 255;
334 else
335 faked_key = VK_SPACE;
336 keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0);
337 }
338 }
339 mod_key_state |= LEFT_WIN_PRESSED;
340 if (!NILP (Vw32_lwindow_modifier))
341 return 0;
342 break;
343 case VK_RWIN:
344 if (NILP (Vw32_pass_rwindow_to_system))
345 {
346 if ((mod_key_state & RIGHT_WIN_PRESSED) == 0)
347 {
348 if (NUMBERP (Vw32_phantom_key_code))
349 faked_key = XUINT (Vw32_phantom_key_code) & 255;
350 else
351 faked_key = VK_SPACE;
352 keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0);
353 }
354 }
355 mod_key_state |= RIGHT_WIN_PRESSED;
356 if (!NILP (Vw32_rwindow_modifier))
357 return 0;
358 break;
359 case VK_APPS:
360 mod_key_state |= APPS_PRESSED;
361 if (!NILP (Vw32_apps_modifier))
362 return 0;
363 break;
364 case VK_CAPITAL:
365 /* Decide whether to treat as modifier or function key. */
366 if (NILP (Vw32_enable_caps_lock))
367 goto disable_lock_key;
368 return 0;
369 case VK_NUMLOCK:
370 /* Decide whether to treat as modifier or function key. */
371 if (NILP (Vw32_enable_num_lock))
372 goto disable_lock_key;
373 return 0;
374 case VK_SCROLL:
375 /* Decide whether to treat as modifier or function key. */
376 if (NILP (Vw32_scroll_lock_modifier))
377 goto disable_lock_key;
378 return 0;
379 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)
384 {
385 /* Fake another press of the relevant key. Apparently, this
386 really is the only way to turn off the indicator. */
387 faked_key = wParam;
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);
394 }
395 break;
396 case VK_MENU:
397 case VK_CONTROL:
398 case VK_SHIFT:
399 return 0;
400 case VK_CANCEL:
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;
405 break;
406 case 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;
416 break;
417 }
418
419 /* Recognize state of Windows and Apps keys. */
420 event->dwControlKeyState |= mod_key_state;
421
422 /* Distinguish numeric keypad keys from extended keys. */
423 event->wVirtualKeyCode =
424 map_keypad_keys (event->wVirtualKeyCode,
425 (event->dwControlKeyState & ENHANCED_KEY));
426
427 if (lispy_function_keys[event->wVirtualKeyCode] == 0)
428 {
429 if (!NILP (Vw32_recognize_altgr)
430 && (event->dwControlKeyState & LEFT_CTRL_PRESSED)
431 && (event->dwControlKeyState & RIGHT_ALT_PRESSED))
432 {
433 /* Don't try to interpret AltGr key chords; ToAscii seems not
434 to process them correctly. */
435 }
436 /* Handle key chords including any modifiers other than shift
437 directly, in order to preserve as much modifier information as
438 possible. */
439 else if (event->dwControlKeyState
440 & ( RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED
441 | RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED
442 | (!NILP (Vw32_lwindow_modifier) ? LEFT_WIN_PRESSED : 0)
443 | (!NILP (Vw32_rwindow_modifier) ? RIGHT_WIN_PRESSED : 0)
444 | (!NILP (Vw32_apps_modifier) ? APPS_PRESSED : 0)
445 | (!NILP (Vw32_scroll_lock_modifier) ? SCROLLLOCK_ON : 0)))
446 {
447 /* Don't translate modified alphabetic keystrokes, so the user
448 doesn't need to constantly switch layout to type control or
449 meta keystrokes when the normal layout translates
450 alphabetic characters to non-ascii characters. */
451 if ('A' <= event->wVirtualKeyCode && event->wVirtualKeyCode <= 'Z')
452 {
453 event->uChar.AsciiChar = event->wVirtualKeyCode;
454 if ((event->dwControlKeyState & SHIFT_PRESSED) == 0)
455 event->uChar.AsciiChar += ('a' - 'A');
456 }
457 /* Try to handle unrecognized keystrokes by determining the
458 base character (ie. translating the base key plus shift
459 modifier). */
460 else if (event->uChar.AsciiChar == 0)
461 w32_kbd_patch_key (event);
462 }
463
464 if (event->uChar.AsciiChar == 0)
465 {
466 emacs_ev->kind = NO_EVENT;
467 return 0;
468 }
469 else if (event->uChar.AsciiChar > 0)
470 {
471 emacs_ev->kind = ASCII_KEYSTROKE_EVENT;
472 emacs_ev->code = event->uChar.AsciiChar;
473 }
474 else if (event->uChar.UnicodeChar > 0)
475 {
476 emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
477 emacs_ev->code = event->uChar.UnicodeChar;
478 }
479 else
480 {
481 /* Fallback for non-Unicode versions of Windows. */
482 wchar_t code;
483 char dbcs[2];
484 char cp[20];
485 int cpId;
486
487 /* Get the codepage to interpret this key with. */
488 GetLocaleInfo (GetThreadLocale (),
489 LOCALE_IDEFAULTANSICODEPAGE, cp, 20);
490 cpId = atoi (cp);
491
492 dbcs[0] = dbcs_lead;
493 dbcs[1] = event->uChar.AsciiChar;
494 if (dbcs_lead)
495 {
496 dbcs_lead = 0;
497 if (!MultiByteToWideChar (cpId, 0, dbcs, 2, &code, 1))
498 {
499 /* Garbage */
500 DebPrint (("Invalid DBCS sequence: %d %d\n",
501 dbcs[0], dbcs[1]));
502 emacs_ev->kind = NO_EVENT;
503 }
504 }
505 else if (IsDBCSLeadByteEx (cpId, dbcs[1]))
506 {
507 dbcs_lead = dbcs[1];
508 emacs_ev->kind = NO_EVENT;
509 }
510 else
511 {
512 if (!MultiByteToWideChar (cpId, 0, &dbcs[1], 1, &code, 1))
513 {
514 /* Garbage */
515 DebPrint (("Invalid character: %d\n", dbcs[1]));
516 emacs_ev->kind = NO_EVENT;
517 }
518 }
519 emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
520 emacs_ev->code = code;
521 }
522 }
523 else
524 {
525 emacs_ev->kind = NON_ASCII_KEYSTROKE_EVENT;
526 emacs_ev->code = event->wVirtualKeyCode;
527 }
528
529 XSETFRAME (emacs_ev->frame_or_window, get_frame ());
530 emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState,
531 event->wVirtualKeyCode);
532 emacs_ev->timestamp = GetTickCount ();
533 return 1;
534 }
535
536 int
537 w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state)
538 {
539 int cur_state = (GetKeyState (vk_code) & 1);
540
541 if (NILP (new_state)
542 || (NUMBERP (new_state)
543 && ((XUINT (new_state)) & 1) != cur_state))
544 {
545 faked_key = vk_code;
546
547 keybd_event ((BYTE) vk_code,
548 (BYTE) MapVirtualKey (vk_code, 0),
549 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
550 keybd_event ((BYTE) vk_code,
551 (BYTE) MapVirtualKey (vk_code, 0),
552 KEYEVENTF_EXTENDEDKEY | 0, 0);
553 keybd_event ((BYTE) vk_code,
554 (BYTE) MapVirtualKey (vk_code, 0),
555 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
556 cur_state = !cur_state;
557 }
558
559 return cur_state;
560 }
561
562 /* Mouse position hook. */
563 void
564 w32_console_mouse_position (FRAME_PTR *f,
565 int insist,
566 Lisp_Object *bar_window,
567 enum scroll_bar_part *part,
568 Lisp_Object *x,
569 Lisp_Object *y,
570 unsigned long *time)
571 {
572 BLOCK_INPUT;
573
574 insist = insist;
575
576 *f = get_frame ();
577 *bar_window = Qnil;
578 *part = 0;
579 SELECTED_FRAME ()->mouse_moved = 0;
580
581 XSETINT (*x, movement_pos.X);
582 XSETINT (*y, movement_pos.Y);
583 *time = movement_time;
584
585 UNBLOCK_INPUT;
586 }
587
588 /* Remember mouse motion and notify emacs. */
589 static void
590 mouse_moved_to (int x, int y)
591 {
592 /* If we're in the same place, ignore it */
593 if (x != movement_pos.X || y != movement_pos.Y)
594 {
595 SELECTED_FRAME ()->mouse_moved = 1;
596 movement_pos.X = x;
597 movement_pos.Y = y;
598 movement_time = GetTickCount ();
599 }
600 }
601
602 /* Consoles return button bits in a strange order:
603 least significant - Leftmost button
604 next - Rightmost button
605 next - Leftmost+1
606 next - Leftmost+2...
607
608 Assume emacs likes three button mice, so
609 Left == 0
610 Middle == 1
611 Right == 2
612 Others increase from there. */
613
614 #define NUM_TRANSLATED_MOUSE_BUTTONS 3
615 static int emacs_button_translation[NUM_TRANSLATED_MOUSE_BUTTONS] =
616 {
617 0, 2, 1
618 };
619
620 static int
621 do_mouse_event (MOUSE_EVENT_RECORD *event,
622 struct input_event *emacs_ev)
623 {
624 static DWORD button_state = 0;
625 DWORD but_change, mask;
626 int i;
627
628 if (event->dwEventFlags == MOUSE_MOVED)
629 {
630 /* For movement events we just note that the mouse has moved
631 so that emacs will generate drag events. */
632 mouse_moved_to (event->dwMousePosition.X, event->dwMousePosition.Y);
633 return 0;
634 }
635
636 /* It looks like the console code sends us a mouse event with
637 dwButtonState == 0 when a window is activated. Ignore this case. */
638 if (event->dwButtonState == button_state)
639 return 0;
640
641 emacs_ev->kind = MOUSE_CLICK_EVENT;
642
643 /* Find out what button has changed state since the last button event. */
644 but_change = button_state ^ event->dwButtonState;
645 mask = 1;
646 for (i = 0; mask; i++, mask <<= 1)
647 if (but_change & mask)
648 {
649 if (i < NUM_TRANSLATED_MOUSE_BUTTONS)
650 emacs_ev->code = emacs_button_translation[i];
651 else
652 emacs_ev->code = i;
653 break;
654 }
655
656 button_state = event->dwButtonState;
657 emacs_ev->timestamp = GetTickCount ();
658 emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState, 0) |
659 ((event->dwButtonState & mask) ? down_modifier : up_modifier);
660
661 XSETFASTINT (emacs_ev->x, event->dwMousePosition.X);
662 XSETFASTINT (emacs_ev->y, event->dwMousePosition.Y);
663 /* for Mule 2.2 (Based on Emacs 19.28 */
664 #ifdef MULE
665 XSET (emacs_ev->frame_or_window, Lisp_Frame, get_frame ());
666 #else
667 XSETFRAME (emacs_ev->frame_or_window, get_frame ());
668 #endif
669
670 return 1;
671 }
672
673 static void
674 resize_event (WINDOW_BUFFER_SIZE_RECORD *event)
675 {
676 FRAME_PTR f = get_frame ();
677
678 change_frame_size (f, event->dwSize.Y, event->dwSize.X, 0, 1, 0);
679 SET_FRAME_GARBAGED (f);
680 }
681
682 static void
683 maybe_generate_resize_event (void)
684 {
685 CONSOLE_SCREEN_BUFFER_INFO info;
686 FRAME_PTR f = get_frame ();
687
688 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);
689
690 /* It is okay to call this unconditionally, since it will do nothing
691 if the size hasn't actually changed. */
692 change_frame_size (f,
693 1 + info.srWindow.Bottom - info.srWindow.Top,
694 1 + info.srWindow.Right - info.srWindow.Left,
695 0, 0, 0);
696 }
697
698 int
699 w32_console_read_socket (struct terminal *terminal,
700 int expected,
701 struct input_event *hold_quit)
702 {
703 BOOL no_events = TRUE;
704 int nev, ret = 0, add;
705 int isdead;
706
707 if (interrupt_input_blocked)
708 {
709 interrupt_input_pending = 1;
710 return -1;
711 }
712
713 interrupt_input_pending = 0;
714 BLOCK_INPUT;
715
716 for (;;)
717 {
718 nev = fill_queue (0);
719 if (nev <= 0)
720 {
721 /* If nev == -1, there was some kind of error
722 If nev == 0 then waitp must be zero and no events were available
723 so return. */
724 UNBLOCK_INPUT;
725 return nev;
726 }
727
728 while (nev > 0)
729 {
730 struct input_event inev;
731
732 EVENT_INIT (inev);
733 inev.kind = NO_EVENT;
734 inev.arg = Qnil;
735
736 switch (queue_ptr->EventType)
737 {
738 case KEY_EVENT:
739 add = key_event (&queue_ptr->Event.KeyEvent, &inev, &isdead);
740 if (add == -1) /* 95.7.25 by himi */
741 {
742 queue_ptr--;
743 add = 1;
744 }
745 if (add)
746 kbd_buffer_store_event_hold (&inev, hold_quit);
747 break;
748
749 case MOUSE_EVENT:
750 add = do_mouse_event (&queue_ptr->Event.MouseEvent, &inev);
751 if (add)
752 kbd_buffer_store_event_hold (&inev, hold_quit);
753 break;
754
755 case WINDOW_BUFFER_SIZE_EVENT:
756 if (w32_use_full_screen_buffer)
757 resize_event (&queue_ptr->Event.WindowBufferSizeEvent);
758 break;
759
760 case MENU_EVENT:
761 case FOCUS_EVENT:
762 /* Internal event types, ignored. */
763 break;
764 }
765
766 queue_ptr++;
767 nev--;
768 }
769
770 if (ret > 0 || expected == 0)
771 break;
772 }
773
774 /* We don't get told about changes in the window size (only the buffer
775 size, which we no longer care about), so we have to check it
776 periodically. */
777 if (!w32_use_full_screen_buffer)
778 maybe_generate_resize_event ();
779
780 UNBLOCK_INPUT;
781 return ret;
782 }
783