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