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