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