Merge from trunk
[bpt/emacs.git] / src / w32inevt.c
CommitLineData
e9e23e23 1/* Input event support for Emacs on the Microsoft W32 API.
9ec0b715 2 Copyright (C) 1992, 1993, 1995, 2001, 2002, 2003, 2004, 2005, 2006,
114f9c96 3 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
6cdfb6e6 4
3b7ad313
EN
5This file is part of GNU Emacs.
6
9ec0b715 7GNU Emacs is free software: you can redistribute it and/or modify
3b7ad313 8it under the terms of the GNU General Public License as published by
9ec0b715
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
3b7ad313
EN
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
9ec0b715 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
6cdfb6e6 19
9ec0b715 20/*
6cdfb6e6
RS
21 Drew Bliss 01-Oct-93
22 Adapted from ntkbd.c by Tim Fleehart
23*/
24
25
4838e624 26#include <config.h>
6cdfb6e6
RS
27#include <stdio.h>
28#include <windows.h>
d7306fe6 29#include <setjmp.h>
6cdfb6e6 30
690e96a3
AI
31#ifndef MOUSE_MOVED
32#define MOUSE_MOVED 1
33#endif
34
6cdfb6e6 35#include "lisp.h"
690e96a3 36#include "keyboard.h"
6cdfb6e6 37#include "frame.h"
2165e881 38#include "dispextern.h"
6cdfb6e6
RS
39#include "blockinput.h"
40#include "termhooks.h"
29a2c30f
GV
41#include "w32heap.h"
42#include "w32term.h"
6cdfb6e6
RS
43
44/* stdin, from ntterm */
45extern HANDLE keyboard_handle;
46
6cdfb6e6
RS
47/* Info for last mouse motion */
48static COORD movement_pos;
49static DWORD movement_time;
50
51/* from keyboard.c */
52extern void reinvoke_input_signal (void);
53
d44c074d
AI
54/* from w32console.c */
55extern int w32_use_full_screen_buffer;
56
5a6816da 57/* from w32fns.c */
fbd6baed 58extern Lisp_Object Vw32_alt_is_meta;
29a2c30f 59extern unsigned int map_keypad_keys (unsigned int, unsigned int);
5a6816da 60
59131421
GV
61/* from w32term */
62extern Lisp_Object Vw32_capslock_is_shiftlock;
29a2c30f
GV
63extern Lisp_Object Vw32_enable_caps_lock;
64extern Lisp_Object Vw32_enable_num_lock;
c0f1b02e 65extern Lisp_Object Vw32_recognize_altgr;
29a2c30f
GV
66extern Lisp_Object Vw32_pass_lwindow_to_system;
67extern Lisp_Object Vw32_pass_rwindow_to_system;
9ddef9c4 68extern Lisp_Object Vw32_phantom_key_code;
29a2c30f
GV
69extern Lisp_Object Vw32_lwindow_modifier;
70extern Lisp_Object Vw32_rwindow_modifier;
71extern Lisp_Object Vw32_apps_modifier;
72extern Lisp_Object Vw32_scroll_lock_modifier;
73extern unsigned int w32_key_to_modifier (int key);
59131421 74
6cdfb6e6
RS
75/* Event queue */
76#define EVENT_QUEUE_SIZE 50
77static INPUT_RECORD event_queue[EVENT_QUEUE_SIZE];
78static INPUT_RECORD *queue_ptr = event_queue, *queue_end = event_queue;
79
7e233730
JR
80/* Temporarily store lead byte of DBCS input sequences. */
81static char dbcs_lead = 0;
82
177c0ea7 83static int
6cdfb6e6
RS
84fill_queue (BOOL block)
85{
86 BOOL rc;
87 DWORD events_waiting;
177c0ea7 88
6cdfb6e6
RS
89 if (queue_ptr < queue_end)
90 return queue_end-queue_ptr;
177c0ea7 91
6cdfb6e6
RS
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 }
177c0ea7 101
6cdfb6e6
RS
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. */
177c0ea7 115static FRAME_PTR
6cdfb6e6
RS
116get_frame (void)
117{
4f4a5f69 118 return SELECTED_FRAME ();
6cdfb6e6
RS
119}
120
177c0ea7 121/* Translate console modifiers to emacs modifiers.
b02466e8 122 German keyboard support (Kai Morgan Zeise 2/18/95). */
407c1745 123int
59131421 124w32_kbd_mods_to_emacs (DWORD mods, WORD key)
6cdfb6e6 125{
b02466e8
KH
126 int retval = 0;
127
c0f1b02e 128 /* If we recognize right-alt and left-ctrl as AltGr, and it has been
29a2c30f 129 pressed, first remove those modifiers. */
177c0ea7
JB
130 if (!NILP (Vw32_recognize_altgr)
131 && (mods & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
b02466e8
KH
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))
fbd6baed 136 retval = ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier);
177c0ea7 137
b02466e8
KH
138 if (mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
139 {
140 retval |= ctrl_modifier;
177c0ea7 141 if ((mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
b02466e8
KH
142 == (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
143 retval |= meta_modifier;
144 }
145
29a2c30f
GV
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
fffa137c 155 /* Just in case someone wanted the original behavior, make it
59131421 156 optional by setting w32-capslock-is-shiftlock to t. */
29a2c30f
GV
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 ))
59131421 168 {
29a2c30f
GV
169 /* Only consider shift state. */
170 if ((mods & SHIFT_PRESSED) != 0)
59131421
GV
171 retval |= shift_modifier;
172 }
173 else
174 {
29a2c30f
GV
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;
59131421 180 }
b02466e8
KH
181
182 return retval;
183}
184
29a2c30f
GV
185#if 0
186/* Return nonzero if the virtual key is a dead key. */
187static int
188is_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
daf38066 197/* The return code indicates key code size. */
c0386d7e 198int
fbd6baed 199w32_kbd_patch_key (KEY_EVENT_RECORD *event)
b02466e8
KH
200{
201 unsigned int key_code = event->wVirtualKeyCode;
202 unsigned int mods = event->dwControlKeyState;
daf38066
GV
203 BYTE keystate[256];
204 static BYTE ansi_code[4];
407c1745 205 static int isdead = 0;
daf38066
GV
206
207 if (isdead == 2)
208 {
209 event->uChar.AsciiChar = ansi_code[2];
210 isdead = 0;
211 return 1;
b02466e8 212 }
177c0ea7 213 if (event->uChar.AsciiChar != 0)
daf38066 214 return 1;
c0386d7e 215
daf38066 216 memset (keystate, 0, sizeof (keystate));
29a2c30f 217 keystate[key_code] = 0x80;
177c0ea7 218 if (mods & SHIFT_PRESSED)
daf38066 219 keystate[VK_SHIFT] = 0x80;
177c0ea7 220 if (mods & CAPSLOCK_ON)
daf38066 221 keystate[VK_CAPITAL] = 1;
c0f1b02e
GV
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))
c0386d7e
GV
226 {
227 keystate[VK_CONTROL] = 0x80;
228 keystate[VK_LCONTROL] = 0x80;
229 keystate[VK_MENU] = 0x80;
230 keystate[VK_RMENU] = 0x80;
231 }
232
29a2c30f
GV
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 {
7e233730
JR
255 char cp[20];
256 int cpId;
29a2c30f 257
7e233730
JR
258 event->uChar.UnicodeChar = buf[isdead - 1];
259
260 GetLocaleInfo (GetThreadLocale (),
29a2c30f 261 LOCALE_IDEFAULTANSICODEPAGE, cp, 20);
7e233730
JR
262 cpId = atoi (cp);
263 isdead = WideCharToMultiByte (cpId, 0, buf, isdead,
29a2c30f
GV
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
177c0ea7 275 if (isdead == 0)
daf38066
GV
276 return 0;
277 event->uChar.AsciiChar = ansi_code[0];
278 return isdead;
6cdfb6e6 279}
407c1745 280
6cdfb6e6 281
24021b38 282extern const char *const lispy_function_keys[];
6cdfb6e6 283
9ddef9c4
GV
284static int faked_key = 0;
285
177c0ea7 286/* return code -1 means that event_queue_ptr won't be incremented.
daf38066 287 In other word, this event makes two key codes. (by himi) */
24f981c9 288static int
59131421 289key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
6cdfb6e6 290{
29a2c30f
GV
291 static int mod_key_state = 0;
292 int wParam;
59131421
GV
293
294 *isdead = 0;
29a2c30f 295
6cdfb6e6 296 /* Skip key-up events. */
407c1745 297 if (!event->bKeyDown)
6cdfb6e6 298 {
29a2c30f
GV
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 }
6cdfb6e6
RS
311 return 0;
312 }
b02466e8 313
29a2c30f
GV
314 /* Ignore keystrokes we fake ourself; see below. */
315 if (faked_key == event->wVirtualKeyCode)
6cdfb6e6 316 {
29a2c30f 317 faked_key = 0;
6cdfb6e6
RS
318 return 0;
319 }
29a2c30f
GV
320
321 /* To make it easier to debug this code, ignore modifier keys! */
322 switch (event->wVirtualKeyCode)
6cdfb6e6 323 {
29a2c30f
GV
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 {
9ddef9c4
GV
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);
29a2c30f
GV
337 }
338 }
339 mod_key_state |= LEFT_WIN_PRESSED;
340 if (!NILP (Vw32_lwindow_modifier))
daf38066 341 return 0;
29a2c30f
GV
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 {
9ddef9c4
GV
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);
29a2c30f
GV
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;
9ddef9c4
GV
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;
6cdfb6e6 417 }
29a2c30f
GV
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)
daf38066 428 {
29a2c30f
GV
429 if (!NILP (Vw32_recognize_altgr)
430 && (event->dwControlKeyState & LEFT_CTRL_PRESSED)
431 && (event->dwControlKeyState & RIGHT_ALT_PRESSED))
daf38066 432 {
29a2c30f
GV
433 /* Don't try to interpret AltGr key chords; ToAscii seems not
434 to process them correctly. */
daf38066 435 }
29a2c30f
GV
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 }
7e233730 463
29a2c30f 464 if (event->uChar.AsciiChar == 0)
7e233730
JR
465 {
466 emacs_ev->kind = NO_EVENT;
467 return 0;
468 }
af93af83 469 else if (event->uChar.AsciiChar > 0)
7e233730
JR
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]));
dd5de7c6 502 emacs_ev->kind = NO_EVENT;
7e233730
JR
503 }
504 }
505 else if (IsDBCSLeadByteEx (cpId, dbcs[1]))
506 {
507 dbcs_lead = dbcs[1];
dd5de7c6 508 emacs_ev->kind = NO_EVENT;
7e233730
JR
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]));
dd5de7c6 516 emacs_ev->kind = NO_EVENT;
7e233730
JR
517 }
518 }
519 emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
520 emacs_ev->code = code;
521 }
daf38066 522 }
6cdfb6e6
RS
523 else
524 {
e43bd4f5 525 emacs_ev->kind = NON_ASCII_KEYSTROKE_EVENT;
e3ec1dce 526 emacs_ev->code = event->wVirtualKeyCode;
6cdfb6e6 527 }
29a2c30f 528
b02466e8 529 XSETFRAME (emacs_ev->frame_or_window, get_frame ());
59131421
GV
530 emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState,
531 event->wVirtualKeyCode);
6cdfb6e6
RS
532 emacs_ev->timestamp = GetTickCount ();
533 return 1;
534}
535
9ddef9c4
GV
536int
537w32_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)
a1bcc85a 543 && ((XUINT (new_state)) & 1) != cur_state))
9ddef9c4
GV
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
6cdfb6e6 562/* Mouse position hook. */
177c0ea7 563void
81e3e4fd 564w32_console_mouse_position (FRAME_PTR *f,
81e3e4fd 565 int insist,
81e3e4fd
GV
566 Lisp_Object *bar_window,
567 enum scroll_bar_part *part,
568 Lisp_Object *x,
569 Lisp_Object *y,
570 unsigned long *time)
6cdfb6e6
RS
571{
572 BLOCK_INPUT;
407c1745 573
b02466e8
KH
574 insist = insist;
575
6cdfb6e6
RS
576 *f = get_frame ();
577 *bar_window = Qnil;
578 *part = 0;
4f4a5f69 579 SELECTED_FRAME ()->mouse_moved = 0;
177c0ea7 580
ed3751c8
JB
581 XSETINT (*x, movement_pos.X);
582 XSETINT (*y, movement_pos.Y);
6cdfb6e6 583 *time = movement_time;
177c0ea7 584
6cdfb6e6
RS
585 UNBLOCK_INPUT;
586}
587
588/* Remember mouse motion and notify emacs. */
177c0ea7 589static void
6cdfb6e6
RS
590mouse_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 {
4f4a5f69 595 SELECTED_FRAME ()->mouse_moved = 1;
6cdfb6e6
RS
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
1f2fca4b
JR
614#define NUM_TRANSLATED_MOUSE_BUTTONS 3
615static int emacs_button_translation[NUM_TRANSLATED_MOUSE_BUTTONS] =
6cdfb6e6 616{
1f2fca4b 617 0, 2, 1
6cdfb6e6
RS
618};
619
177c0ea7 620static int
6cdfb6e6
RS
621do_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;
177c0ea7 627
6cdfb6e6
RS
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 }
177c0ea7 635
6cdfb6e6
RS
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;
177c0ea7 640
e43bd4f5 641 emacs_ev->kind = MOUSE_CLICK_EVENT;
177c0ea7 642
6cdfb6e6
RS
643 /* Find out what button has changed state since the last button event. */
644 but_change = button_state ^ event->dwButtonState;
645 mask = 1;
1f2fca4b 646 for (i = 0; mask; i++, mask <<= 1)
6cdfb6e6
RS
647 if (but_change & mask)
648 {
1f2fca4b 649 if (i < NUM_TRANSLATED_MOUSE_BUTTONS)
e3ec1dce 650 emacs_ev->code = emacs_button_translation[i];
1f2fca4b 651 else
e3ec1dce 652 emacs_ev->code = i;
6cdfb6e6
RS
653 break;
654 }
655
6cdfb6e6
RS
656 button_state = event->dwButtonState;
657 emacs_ev->timestamp = GetTickCount ();
59131421 658 emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState, 0) |
6cdfb6e6 659 ((event->dwButtonState & mask) ? down_modifier : up_modifier);
177c0ea7 660
9e539a3c
KH
661 XSETFASTINT (emacs_ev->x, event->dwMousePosition.X);
662 XSETFASTINT (emacs_ev->y, event->dwMousePosition.Y);
daf38066
GV
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
b02466e8 667 XSETFRAME (emacs_ev->frame_or_window, get_frame ());
daf38066 668#endif
177c0ea7 669
6cdfb6e6
RS
670 return 1;
671}
672
177c0ea7 673static void
6cdfb6e6
RS
674resize_event (WINDOW_BUFFER_SIZE_RECORD *event)
675{
676 FRAME_PTR f = get_frame ();
177c0ea7 677
8d59c5ed 678 change_frame_size (f, event->dwSize.Y, event->dwSize.X, 0, 1, 0);
6cdfb6e6
RS
679 SET_FRAME_GARBAGED (f);
680}
681
b7b97897 682static void
b56ceb92 683maybe_generate_resize_event (void)
b7b97897
AI
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,
8d59c5ed 695 0, 0, 0);
b7b97897
AI
696}
697
177c0ea7 698int
9e511e9c
JR
699w32_console_read_socket (struct terminal *terminal,
700 int expected,
701 struct input_event *hold_quit)
6cdfb6e6
RS
702{
703 BOOL no_events = TRUE;
704 int nev, ret = 0, add;
59131421
GV
705 int isdead;
706
6cdfb6e6
RS
707 if (interrupt_input_blocked)
708 {
709 interrupt_input_pending = 1;
710 return -1;
711 }
177c0ea7 712
6cdfb6e6
RS
713 interrupt_input_pending = 0;
714 BLOCK_INPUT;
177c0ea7 715
6cdfb6e6
RS
716 for (;;)
717 {
06c2c73d 718 nev = fill_queue (0);
6cdfb6e6
RS
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
9cd31aaf 728 while (nev > 0)
6cdfb6e6 729 {
9cd31aaf
KS
730 struct input_event inev;
731
732 EVENT_INIT (inev);
733 inev.kind = NO_EVENT;
734 inev.arg = Qnil;
735
6cdfb6e6
RS
736 switch (queue_ptr->EventType)
737 {
738 case KEY_EVENT:
9cd31aaf 739 add = key_event (&queue_ptr->Event.KeyEvent, &inev, &isdead);
daf38066 740 if (add == -1) /* 95.7.25 by himi */
177c0ea7 741 {
daf38066
GV
742 queue_ptr--;
743 add = 1;
744 }
9cd31aaf
KS
745 if (add)
746 kbd_buffer_store_event_hold (&inev, hold_quit);
6cdfb6e6
RS
747 break;
748
749 case MOUSE_EVENT:
9cd31aaf
KS
750 add = do_mouse_event (&queue_ptr->Event.MouseEvent, &inev);
751 if (add)
752 kbd_buffer_store_event_hold (&inev, hold_quit);
6cdfb6e6
RS
753 break;
754
755 case WINDOW_BUFFER_SIZE_EVENT:
d44c074d
AI
756 if (w32_use_full_screen_buffer)
757 resize_event (&queue_ptr->Event.WindowBufferSizeEvent);
6cdfb6e6 758 break;
177c0ea7 759
6cdfb6e6
RS
760 case MENU_EVENT:
761 case FOCUS_EVENT:
762 /* Internal event types, ignored. */
763 break;
764 }
177c0ea7 765
6cdfb6e6
RS
766 queue_ptr++;
767 nev--;
768 }
769
770 if (ret > 0 || expected == 0)
771 break;
772 }
b7b97897
AI
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. */
d44c074d
AI
777 if (!w32_use_full_screen_buffer)
778 maybe_generate_resize_event ();
b7b97897 779
6cdfb6e6
RS
780 UNBLOCK_INPUT;
781 return ret;
782}
ab5796a9 783