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