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