The TTY case is resolved: notifications now work even if Emacs
[bpt/emacs.git] / src / w32inevt.c
CommitLineData
b46a6a83 1/* Input event support for Emacs on the Microsoft Windows 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>
28
690e96a3
AI
29#ifndef MOUSE_MOVED
30#define MOUSE_MOVED 1
31#endif
32
6cdfb6e6 33#include "lisp.h"
690e96a3 34#include "keyboard.h"
6cdfb6e6 35#include "frame.h"
2165e881 36#include "dispextern.h"
f12fdf02 37#include "window.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"
01bd1b0d 43#include "w32inevt.h"
6cdfb6e6 44
7684e57b 45/* stdin, from w32console.c */
6cdfb6e6
RS
46extern HANDLE keyboard_handle;
47
6cdfb6e6
RS
48/* Info for last mouse motion */
49static COORD movement_pos;
9fbd6841 50static Time movement_time;
6cdfb6e6 51
7684e57b 52/* from w32fns.c */
29a2c30f 53extern unsigned int map_keypad_keys (unsigned int, unsigned int);
29a2c30f 54extern unsigned int w32_key_to_modifier (int key);
59131421 55
6cdfb6e6
RS
56/* Event queue */
57#define EVENT_QUEUE_SIZE 50
58static INPUT_RECORD event_queue[EVENT_QUEUE_SIZE];
59static INPUT_RECORD *queue_ptr = event_queue, *queue_end = event_queue;
60
7e233730
JR
61/* Temporarily store lead byte of DBCS input sequences. */
62static char dbcs_lead = 0;
63
01bd1b0d
EZ
64static inline BOOL
65w32_read_console_input (HANDLE h, INPUT_RECORD *rec, DWORD recsize,
66 DWORD *waiting)
67{
68 return (w32_console_unicode_input
69 ? ReadConsoleInputW (h, rec, recsize, waiting)
70 : ReadConsoleInputA (h, rec, recsize, waiting));
71}
72
0fda9b75
DC
73/* Set by w32_console_toggle_lock_key. */
74int faked_key;
75
177c0ea7 76static int
6cdfb6e6
RS
77fill_queue (BOOL block)
78{
79 BOOL rc;
80 DWORD events_waiting;
177c0ea7 81
6cdfb6e6
RS
82 if (queue_ptr < queue_end)
83 return queue_end-queue_ptr;
177c0ea7 84
6cdfb6e6
RS
85 if (!block)
86 {
87 /* Check to see if there are some events to read before we try
88 because we can't block. */
89 if (!GetNumberOfConsoleInputEvents (keyboard_handle, &events_waiting))
90 return -1;
91 if (events_waiting == 0)
92 return 0;
93 }
177c0ea7 94
01bd1b0d
EZ
95 rc = w32_read_console_input (keyboard_handle, event_queue, EVENT_QUEUE_SIZE,
96 &events_waiting);
6cdfb6e6
RS
97 if (!rc)
98 return -1;
99 queue_ptr = event_queue;
100 queue_end = event_queue + events_waiting;
101 return (int) events_waiting;
102}
103
104/* In a generic, multi-frame world this should take a console handle
105 and return the frame for it
106
107 Right now, there's only one frame so return it. */
177c0ea7 108static FRAME_PTR
6cdfb6e6
RS
109get_frame (void)
110{
4f4a5f69 111 return SELECTED_FRAME ();
6cdfb6e6
RS
112}
113
177c0ea7 114/* Translate console modifiers to emacs modifiers.
b02466e8 115 German keyboard support (Kai Morgan Zeise 2/18/95). */
b02466e8 116
b02466e8 117
29a2c30f
GV
118#if 0
119/* Return nonzero if the virtual key is a dead key. */
120static int
121is_dead_key (int wparam)
122{
123 unsigned int code = MapVirtualKey (wparam, 2);
124
125 /* Windows 95 returns 0x8000, NT returns 0x80000000. */
126 return (code & 0x80008000) ? 1 : 0;
127}
128#endif
129
302fc036
EZ
130/* The return code indicates key code size. cpID is the codepage to
131 use for translation to Unicode; -1 means use the current console
132 input codepage. */
407c1745 133
6cdfb6e6 134
177c0ea7 135/* return code -1 means that event_queue_ptr won't be incremented.
daf38066 136 In other word, this event makes two key codes. (by himi) */
24f981c9 137static int
59131421 138key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
6cdfb6e6 139{
29a2c30f
GV
140 static int mod_key_state = 0;
141 int wParam;
59131421
GV
142
143 *isdead = 0;
29a2c30f 144
6cdfb6e6 145 /* Skip key-up events. */
407c1745 146 if (!event->bKeyDown)
6cdfb6e6 147 {
29a2c30f
GV
148 switch (event->wVirtualKeyCode)
149 {
150 case VK_LWIN:
151 mod_key_state &= ~LEFT_WIN_PRESSED;
152 break;
153 case VK_RWIN:
154 mod_key_state &= ~RIGHT_WIN_PRESSED;
155 break;
156 case VK_APPS:
157 mod_key_state &= ~APPS_PRESSED;
158 break;
159 }
6cdfb6e6
RS
160 return 0;
161 }
b02466e8 162
29a2c30f
GV
163 /* Ignore keystrokes we fake ourself; see below. */
164 if (faked_key == event->wVirtualKeyCode)
6cdfb6e6 165 {
29a2c30f 166 faked_key = 0;
6cdfb6e6
RS
167 return 0;
168 }
29a2c30f
GV
169
170 /* To make it easier to debug this code, ignore modifier keys! */
171 switch (event->wVirtualKeyCode)
6cdfb6e6 172 {
29a2c30f
GV
173 case VK_LWIN:
174 if (NILP (Vw32_pass_lwindow_to_system))
175 {
176 /* Prevent system from acting on keyup (which opens the Start
177 menu if no other key was pressed) by simulating a press of
178 Space which we will ignore. */
179 if ((mod_key_state & LEFT_WIN_PRESSED) == 0)
180 {
9ddef9c4
GV
181 if (NUMBERP (Vw32_phantom_key_code))
182 faked_key = XUINT (Vw32_phantom_key_code) & 255;
183 else
184 faked_key = VK_SPACE;
185 keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0);
29a2c30f
GV
186 }
187 }
188 mod_key_state |= LEFT_WIN_PRESSED;
189 if (!NILP (Vw32_lwindow_modifier))
daf38066 190 return 0;
29a2c30f
GV
191 break;
192 case VK_RWIN:
193 if (NILP (Vw32_pass_rwindow_to_system))
194 {
195 if ((mod_key_state & RIGHT_WIN_PRESSED) == 0)
196 {
9ddef9c4
GV
197 if (NUMBERP (Vw32_phantom_key_code))
198 faked_key = XUINT (Vw32_phantom_key_code) & 255;
199 else
200 faked_key = VK_SPACE;
201 keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0);
29a2c30f
GV
202 }
203 }
204 mod_key_state |= RIGHT_WIN_PRESSED;
205 if (!NILP (Vw32_rwindow_modifier))
206 return 0;
207 break;
208 case VK_APPS:
209 mod_key_state |= APPS_PRESSED;
210 if (!NILP (Vw32_apps_modifier))
211 return 0;
212 break;
213 case VK_CAPITAL:
214 /* Decide whether to treat as modifier or function key. */
215 if (NILP (Vw32_enable_caps_lock))
216 goto disable_lock_key;
217 return 0;
218 case VK_NUMLOCK:
219 /* Decide whether to treat as modifier or function key. */
220 if (NILP (Vw32_enable_num_lock))
221 goto disable_lock_key;
222 return 0;
223 case VK_SCROLL:
224 /* Decide whether to treat as modifier or function key. */
225 if (NILP (Vw32_scroll_lock_modifier))
226 goto disable_lock_key;
227 return 0;
228 disable_lock_key:
229 /* Ensure the appropriate lock key state is off (and the
230 indicator light as well). */
231 wParam = event->wVirtualKeyCode;
232 if (GetAsyncKeyState (wParam) & 0x8000)
233 {
234 /* Fake another press of the relevant key. Apparently, this
235 really is the only way to turn off the indicator. */
236 faked_key = wParam;
237 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
238 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
239 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
240 KEYEVENTF_EXTENDEDKEY | 0, 0);
241 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
242 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
243 }
244 break;
245 case VK_MENU:
246 case VK_CONTROL:
247 case VK_SHIFT:
248 return 0;
9ddef9c4
GV
249 case VK_CANCEL:
250 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
251 which is confusing for purposes of key binding; convert
252 VK_CANCEL events into VK_PAUSE events. */
253 event->wVirtualKeyCode = VK_PAUSE;
254 break;
255 case VK_PAUSE:
256 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
257 for purposes of key binding; convert these back into
258 VK_NUMLOCK events, at least when we want to see NumLock key
259 presses. (Note that there is never any possibility that
260 VK_PAUSE with Ctrl really is C-Pause as per above.) */
261 if (NILP (Vw32_enable_num_lock)
262 && (event->dwControlKeyState
263 & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0)
264 event->wVirtualKeyCode = VK_NUMLOCK;
265 break;
6cdfb6e6 266 }
29a2c30f
GV
267
268 /* Recognize state of Windows and Apps keys. */
269 event->dwControlKeyState |= mod_key_state;
270
271 /* Distinguish numeric keypad keys from extended keys. */
272 event->wVirtualKeyCode =
273 map_keypad_keys (event->wVirtualKeyCode,
274 (event->dwControlKeyState & ENHANCED_KEY));
275
276 if (lispy_function_keys[event->wVirtualKeyCode] == 0)
daf38066 277 {
29a2c30f
GV
278 if (!NILP (Vw32_recognize_altgr)
279 && (event->dwControlKeyState & LEFT_CTRL_PRESSED)
280 && (event->dwControlKeyState & RIGHT_ALT_PRESSED))
daf38066 281 {
29a2c30f
GV
282 /* Don't try to interpret AltGr key chords; ToAscii seems not
283 to process them correctly. */
daf38066 284 }
29a2c30f
GV
285 /* Handle key chords including any modifiers other than shift
286 directly, in order to preserve as much modifier information as
287 possible. */
288 else if (event->dwControlKeyState
289 & ( RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED
290 | RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED
291 | (!NILP (Vw32_lwindow_modifier) ? LEFT_WIN_PRESSED : 0)
292 | (!NILP (Vw32_rwindow_modifier) ? RIGHT_WIN_PRESSED : 0)
293 | (!NILP (Vw32_apps_modifier) ? APPS_PRESSED : 0)
294 | (!NILP (Vw32_scroll_lock_modifier) ? SCROLLLOCK_ON : 0)))
295 {
296 /* Don't translate modified alphabetic keystrokes, so the user
297 doesn't need to constantly switch layout to type control or
298 meta keystrokes when the normal layout translates
299 alphabetic characters to non-ascii characters. */
300 if ('A' <= event->wVirtualKeyCode && event->wVirtualKeyCode <= 'Z')
301 {
302 event->uChar.AsciiChar = event->wVirtualKeyCode;
303 if ((event->dwControlKeyState & SHIFT_PRESSED) == 0)
304 event->uChar.AsciiChar += ('a' - 'A');
305 }
306 /* Try to handle unrecognized keystrokes by determining the
307 base character (ie. translating the base key plus shift
308 modifier). */
309 else if (event->uChar.AsciiChar == 0)
302fc036 310 w32_kbd_patch_key (event, -1);
29a2c30f 311 }
7e233730 312
29a2c30f 313 if (event->uChar.AsciiChar == 0)
7e233730
JR
314 {
315 emacs_ev->kind = NO_EVENT;
316 return 0;
317 }
af93af83 318 else if (event->uChar.AsciiChar > 0)
7e233730 319 {
01bd1b0d 320 /* Pure ASCII characters < 128. */
7e233730
JR
321 emacs_ev->kind = ASCII_KEYSTROKE_EVENT;
322 emacs_ev->code = event->uChar.AsciiChar;
323 }
01bd1b0d
EZ
324 else if (event->uChar.UnicodeChar > 0
325 && w32_console_unicode_input)
7e233730 326 {
01bd1b0d
EZ
327 /* Unicode codepoint; only valid if we are using Unicode
328 console input mode. */
7e233730
JR
329 emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
330 emacs_ev->code = event->uChar.UnicodeChar;
331 }
332 else
333 {
01bd1b0d
EZ
334 /* Fallback handling of non-ASCII characters for non-Unicode
335 versions of Windows, and for non-Unicode input on NT
336 family of Windows. Only characters in the current
337 console codepage are supported by this fallback. */
7e233730
JR
338 wchar_t code;
339 char dbcs[2];
7e233730
JR
340 int cpId;
341
01bd1b0d
EZ
342 /* Get the current console input codepage to interpret this
343 key with. Note that the system defaults for the OEM
344 codepage could have been changed by calling SetConsoleCP
345 or w32-set-console-codepage, so using GetLocaleInfo to
346 get LOCALE_IDEFAULTCODEPAGE is not TRT here. */
347 cpId = GetConsoleCP ();
7e233730
JR
348
349 dbcs[0] = dbcs_lead;
350 dbcs[1] = event->uChar.AsciiChar;
351 if (dbcs_lead)
352 {
353 dbcs_lead = 0;
354 if (!MultiByteToWideChar (cpId, 0, dbcs, 2, &code, 1))
355 {
356 /* Garbage */
357 DebPrint (("Invalid DBCS sequence: %d %d\n",
358 dbcs[0], dbcs[1]));
dd5de7c6 359 emacs_ev->kind = NO_EVENT;
7e233730
JR
360 }
361 }
362 else if (IsDBCSLeadByteEx (cpId, dbcs[1]))
363 {
364 dbcs_lead = dbcs[1];
dd5de7c6 365 emacs_ev->kind = NO_EVENT;
7e233730
JR
366 }
367 else
368 {
369 if (!MultiByteToWideChar (cpId, 0, &dbcs[1], 1, &code, 1))
370 {
371 /* Garbage */
372 DebPrint (("Invalid character: %d\n", dbcs[1]));
dd5de7c6 373 emacs_ev->kind = NO_EVENT;
7e233730
JR
374 }
375 }
376 emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
377 emacs_ev->code = code;
378 }
daf38066 379 }
6cdfb6e6
RS
380 else
381 {
01bd1b0d 382 /* Function keys and other non-character keys. */
e43bd4f5 383 emacs_ev->kind = NON_ASCII_KEYSTROKE_EVENT;
e3ec1dce 384 emacs_ev->code = event->wVirtualKeyCode;
6cdfb6e6 385 }
29a2c30f 386
b02466e8 387 XSETFRAME (emacs_ev->frame_or_window, get_frame ());
59131421
GV
388 emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState,
389 event->wVirtualKeyCode);
6cdfb6e6
RS
390 emacs_ev->timestamp = GetTickCount ();
391 return 1;
392}
393
394/* Mouse position hook. */
177c0ea7 395void
81e3e4fd 396w32_console_mouse_position (FRAME_PTR *f,
81e3e4fd 397 int insist,
81e3e4fd
GV
398 Lisp_Object *bar_window,
399 enum scroll_bar_part *part,
400 Lisp_Object *x,
401 Lisp_Object *y,
9fbd6841 402 Time *time)
6cdfb6e6 403{
4d7e6e51 404 block_input ();
407c1745 405
b02466e8
KH
406 insist = insist;
407
6cdfb6e6
RS
408 *f = get_frame ();
409 *bar_window = Qnil;
410 *part = 0;
4f4a5f69 411 SELECTED_FRAME ()->mouse_moved = 0;
177c0ea7 412
ed3751c8
JB
413 XSETINT (*x, movement_pos.X);
414 XSETINT (*y, movement_pos.Y);
6cdfb6e6 415 *time = movement_time;
177c0ea7 416
4d7e6e51 417 unblock_input ();
6cdfb6e6
RS
418}
419
42e3a361 420/* Remember mouse motion and notify emacs. */
177c0ea7 421static void
6cdfb6e6
RS
422mouse_moved_to (int x, int y)
423{
eb3f6f01 424 /* If we're in the same place, ignore it. */
6cdfb6e6
RS
425 if (x != movement_pos.X || y != movement_pos.Y)
426 {
42e3a361 427 SELECTED_FRAME ()->mouse_moved = 1;
6cdfb6e6
RS
428 movement_pos.X = x;
429 movement_pos.Y = y;
430 movement_time = GetTickCount ();
431 }
432}
433
434/* Consoles return button bits in a strange order:
435 least significant - Leftmost button
436 next - Rightmost button
437 next - Leftmost+1
438 next - Leftmost+2...
439
440 Assume emacs likes three button mice, so
441 Left == 0
442 Middle == 1
443 Right == 2
444 Others increase from there. */
445
1f2fca4b
JR
446#define NUM_TRANSLATED_MOUSE_BUTTONS 3
447static int emacs_button_translation[NUM_TRANSLATED_MOUSE_BUTTONS] =
6cdfb6e6 448{
1f2fca4b 449 0, 2, 1
6cdfb6e6
RS
450};
451
177c0ea7 452static int
6cdfb6e6
RS
453do_mouse_event (MOUSE_EVENT_RECORD *event,
454 struct input_event *emacs_ev)
455{
456 static DWORD button_state = 0;
f12fdf02 457 static Lisp_Object last_mouse_window;
6cdfb6e6
RS
458 DWORD but_change, mask;
459 int i;
177c0ea7 460
6cdfb6e6
RS
461 if (event->dwEventFlags == MOUSE_MOVED)
462 {
42e3a361
EZ
463 FRAME_PTR f = SELECTED_FRAME ();
464 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
f12fdf02 465 int mx = event->dwMousePosition.X, my = event->dwMousePosition.Y;
42e3a361 466
f12fdf02 467 mouse_moved_to (mx, my);
42e3a361
EZ
468
469 if (f->mouse_moved)
470 {
471 if (hlinfo->mouse_face_hidden)
472 {
473 hlinfo->mouse_face_hidden = 0;
474 clear_mouse_face (hlinfo);
475 }
476
f12fdf02
EZ
477 /* Generate SELECT_WINDOW_EVENTs when needed. */
478 if (!NILP (Vmouse_autoselect_window))
479 {
480 Lisp_Object mouse_window = window_from_coordinates (f, mx, my,
481 0, 0);
482 /* A window will be selected only when it is not
483 selected now, and the last mouse movement event was
484 not in it. A minibuffer window will be selected iff
485 it is active. */
486 if (WINDOWP (mouse_window)
487 && !EQ (mouse_window, last_mouse_window)
488 && !EQ (mouse_window, selected_window))
489 {
490 struct input_event event;
491
492 EVENT_INIT (event);
493 event.kind = SELECT_WINDOW_EVENT;
494 event.frame_or_window = mouse_window;
495 event.arg = Qnil;
496 event.timestamp = movement_time;
497 kbd_buffer_store_event (&event);
498 }
499 last_mouse_window = mouse_window;
500 }
501 else
502 last_mouse_window = Qnil;
c4aeb92a
EZ
503
504 previous_help_echo_string = help_echo_string;
505 help_echo_string = help_echo_object = help_echo_window = Qnil;
506 help_echo_pos = -1;
507 note_mouse_highlight (f, mx, my);
508 /* If the contents of the global variable help_echo has
509 changed (inside note_mouse_highlight), generate a HELP_EVENT. */
510 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
511 gen_help_event (help_echo_string, selected_frame, help_echo_window,
512 help_echo_object, help_echo_pos);
42e3a361 513 }
6cdfb6e6
RS
514 return 0;
515 }
177c0ea7 516
6cdfb6e6
RS
517 /* It looks like the console code sends us a mouse event with
518 dwButtonState == 0 when a window is activated. Ignore this case. */
519 if (event->dwButtonState == button_state)
520 return 0;
177c0ea7 521
e43bd4f5 522 emacs_ev->kind = MOUSE_CLICK_EVENT;
177c0ea7 523
6cdfb6e6
RS
524 /* Find out what button has changed state since the last button event. */
525 but_change = button_state ^ event->dwButtonState;
526 mask = 1;
1f2fca4b 527 for (i = 0; mask; i++, mask <<= 1)
6cdfb6e6
RS
528 if (but_change & mask)
529 {
1f2fca4b 530 if (i < NUM_TRANSLATED_MOUSE_BUTTONS)
e3ec1dce 531 emacs_ev->code = emacs_button_translation[i];
1f2fca4b 532 else
e3ec1dce 533 emacs_ev->code = i;
6cdfb6e6
RS
534 break;
535 }
536
6cdfb6e6
RS
537 button_state = event->dwButtonState;
538 emacs_ev->timestamp = GetTickCount ();
59131421 539 emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState, 0) |
6cdfb6e6 540 ((event->dwButtonState & mask) ? down_modifier : up_modifier);
177c0ea7 541
9e539a3c
KH
542 XSETFASTINT (emacs_ev->x, event->dwMousePosition.X);
543 XSETFASTINT (emacs_ev->y, event->dwMousePosition.Y);
daf38066
GV
544/* for Mule 2.2 (Based on Emacs 19.28 */
545#ifdef MULE
546 XSET (emacs_ev->frame_or_window, Lisp_Frame, get_frame ());
547#else
b02466e8 548 XSETFRAME (emacs_ev->frame_or_window, get_frame ());
daf38066 549#endif
177c0ea7 550
6cdfb6e6
RS
551 return 1;
552}
553
177c0ea7 554static void
6cdfb6e6
RS
555resize_event (WINDOW_BUFFER_SIZE_RECORD *event)
556{
557 FRAME_PTR f = get_frame ();
177c0ea7 558
8d59c5ed 559 change_frame_size (f, event->dwSize.Y, event->dwSize.X, 0, 1, 0);
6cdfb6e6
RS
560 SET_FRAME_GARBAGED (f);
561}
562
b7b97897 563static void
b56ceb92 564maybe_generate_resize_event (void)
b7b97897
AI
565{
566 CONSOLE_SCREEN_BUFFER_INFO info;
567 FRAME_PTR f = get_frame ();
568
569 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);
570
571 /* It is okay to call this unconditionally, since it will do nothing
572 if the size hasn't actually changed. */
573 change_frame_size (f,
574 1 + info.srWindow.Bottom - info.srWindow.Top,
575 1 + info.srWindow.Right - info.srWindow.Left,
8d59c5ed 576 0, 0, 0);
b7b97897
AI
577}
578
182b170f
EZ
579static void
580handle_file_notifications (struct input_event *hold_quit)
581{
582 BYTE *p = file_notifications;
583 FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p;
584 const DWORD min_size
585 = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t);
586 struct input_event inev;
587
588 /* We cannot process notification before Emacs is fully initialized,
589 since we need the UTF-16LE coding-system to be set up. */
590 if (!initialized)
591 {
592 notification_buffer_in_use = 0;
593 return;
594 }
595
596 enter_crit ();
597 if (notification_buffer_in_use)
598 {
599 DWORD info_size = notifications_size;
600
601 /* notifications_size could be zero when the buffer of
602 notifications overflowed on the OS level, or when the
603 directory being watched was itself deleted. Do nothing in
604 that case. */
605 if (info_size)
606 {
607 EVENT_INIT (inev);
608
609 while (info_size >= min_size)
610 {
611 Lisp_Object utf_16_fn
612 = make_unibyte_string ((char *)fni->FileName,
613 fni->FileNameLength);
614 /* Note: mule-conf is preloaded, so utf-16le must
615 already be defined at this point. */
616 Lisp_Object fname
617 = code_convert_string_norecord (utf_16_fn,
618 intern ("utf-16le"), 0);
619 Lisp_Object action = lispy_file_action (fni->Action);
620 Lisp_Object obj;
621
622 obj = get_watch_object (make_number (notifications_desc));
623 if (!NILP (obj) && CONSP (obj))
624 {
625 inev.kind = FILE_NOTIFY_EVENT;
626 inev.code = (ptrdiff_t)notifications_desc;
627 inev.timestamp = GetTickCount ();
628 inev.modifiers = 0;
629 inev.frame_or_window = XCDR (obj);
630 inev.arg = Fcons (action, fname);
631 kbd_buffer_store_event_hold (&inev, hold_quit);
632 }
633
634 if (!fni->NextEntryOffset)
635 break;
636 p += fni->NextEntryOffset;
637 fni = (PFILE_NOTIFY_INFORMATION)p;
638 info_size -= fni->NextEntryOffset;
639 }
640 }
641 notification_buffer_in_use = 0;
642 }
643 leave_crit ();
644}
645
177c0ea7 646int
9e511e9c 647w32_console_read_socket (struct terminal *terminal,
9e511e9c 648 struct input_event *hold_quit)
6cdfb6e6 649{
e4bce92a 650 int nev, add;
59131421
GV
651 int isdead;
652
4d7e6e51 653 block_input ();
177c0ea7 654
6cdfb6e6
RS
655 for (;;)
656 {
182b170f 657 handle_file_notifications (hold_quit);
06c2c73d 658 nev = fill_queue (0);
6cdfb6e6
RS
659 if (nev <= 0)
660 {
661 /* If nev == -1, there was some kind of error
662 If nev == 0 then waitp must be zero and no events were available
663 so return. */
e4bce92a 664 break;
6cdfb6e6
RS
665 }
666
9cd31aaf 667 while (nev > 0)
6cdfb6e6 668 {
9cd31aaf
KS
669 struct input_event inev;
670
671 EVENT_INIT (inev);
672 inev.kind = NO_EVENT;
673 inev.arg = Qnil;
674
6cdfb6e6
RS
675 switch (queue_ptr->EventType)
676 {
677 case KEY_EVENT:
9cd31aaf 678 add = key_event (&queue_ptr->Event.KeyEvent, &inev, &isdead);
daf38066 679 if (add == -1) /* 95.7.25 by himi */
177c0ea7 680 {
daf38066
GV
681 queue_ptr--;
682 add = 1;
683 }
9cd31aaf
KS
684 if (add)
685 kbd_buffer_store_event_hold (&inev, hold_quit);
6cdfb6e6
RS
686 break;
687
688 case MOUSE_EVENT:
9cd31aaf
KS
689 add = do_mouse_event (&queue_ptr->Event.MouseEvent, &inev);
690 if (add)
691 kbd_buffer_store_event_hold (&inev, hold_quit);
6cdfb6e6
RS
692 break;
693
694 case WINDOW_BUFFER_SIZE_EVENT:
d44c074d
AI
695 if (w32_use_full_screen_buffer)
696 resize_event (&queue_ptr->Event.WindowBufferSizeEvent);
6cdfb6e6 697 break;
177c0ea7 698
6cdfb6e6
RS
699 case MENU_EVENT:
700 case FOCUS_EVENT:
701 /* Internal event types, ignored. */
702 break;
703 }
177c0ea7 704
6cdfb6e6
RS
705 queue_ptr++;
706 nev--;
707 }
6cdfb6e6 708 }
b7b97897
AI
709
710 /* We don't get told about changes in the window size (only the buffer
711 size, which we no longer care about), so we have to check it
712 periodically. */
d44c074d
AI
713 if (!w32_use_full_screen_buffer)
714 maybe_generate_resize_event ();
b7b97897 715
4d7e6e51 716 unblock_input ();
e4bce92a 717 return nev;
6cdfb6e6 718}