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