]> code.delx.au - gnu-emacs/blob - src/w32inevt.c
Fix removal of variables from process-environment
[gnu-emacs] / src / w32inevt.c
1 /* Input event support for Emacs on the Microsoft Windows API.
2 Copyright (C) 1992-1993, 1995, 2001-2016 Free Software Foundation,
3 Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19
20 /*
21 Drew Bliss 01-Oct-93
22 Adapted from ntkbd.c by Tim Fleehart
23 */
24
25
26 #include <config.h>
27 #include <stdio.h>
28 #include <windows.h>
29
30 #ifndef MOUSE_MOVED
31 #define MOUSE_MOVED 1
32 #endif
33 #ifndef MOUSE_HWHEELED
34 #define MOUSE_HWHEELED 8
35 #endif
36
37 #include "lisp.h"
38 #include "keyboard.h"
39 #include "frame.h"
40 #include "blockinput.h"
41 #include "termchar.h" /* for Mouse_HLInfo, tty_display_info */
42 #include "w32term.h"
43 #include "w32inevt.h"
44
45 /* stdin, from w32console.c */
46 extern HANDLE keyboard_handle;
47
48 /* Info for last mouse motion */
49 static COORD movement_pos;
50 static Time movement_time;
51
52 /* from w32fns.c */
53 extern unsigned int map_keypad_keys (unsigned int, unsigned int);
54 extern unsigned int w32_key_to_modifier (int key);
55
56 /* Event queue */
57 #define EVENT_QUEUE_SIZE 50
58 static INPUT_RECORD event_queue[EVENT_QUEUE_SIZE];
59 static INPUT_RECORD *queue_ptr = event_queue, *queue_end = event_queue;
60
61 /* Temporarily store lead byte of DBCS input sequences. */
62 static char dbcs_lead = 0;
63
64 static inline BOOL
65 w32_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
73 /* Set by w32_console_toggle_lock_key. */
74 int faked_key;
75
76 static int
77 fill_queue (BOOL block)
78 {
79 BOOL rc;
80 DWORD events_waiting;
81
82 if (queue_ptr < queue_end)
83 return queue_end-queue_ptr;
84
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 }
94
95 rc = w32_read_console_input (keyboard_handle, event_queue, EVENT_QUEUE_SIZE,
96 &events_waiting);
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. */
108 static struct frame *
109 get_frame (void)
110 {
111 return SELECTED_FRAME ();
112 }
113
114 /* Translate console modifiers to emacs modifiers.
115 German keyboard support (Kai Morgan Zeise 2/18/95). */
116
117
118 #if 0
119 /* Return nonzero if the virtual key is a dead key. */
120 static int
121 is_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
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. */
133
134
135 /* return code -1 means that event_queue_ptr won't be incremented.
136 In other word, this event makes two key codes. (by himi) */
137 static int
138 key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
139 {
140 static int mod_key_state = 0;
141 int wParam;
142
143 *isdead = 0;
144
145 /* Skip key-up events. */
146 if (!event->bKeyDown)
147 {
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 }
160 return 0;
161 }
162
163 /* Ignore keystrokes we fake ourself; see below. */
164 if (faked_key == event->wVirtualKeyCode)
165 {
166 faked_key = 0;
167 return 0;
168 }
169
170 /* To make it easier to debug this code, ignore modifier keys! */
171 switch (event->wVirtualKeyCode)
172 {
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 {
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);
186 }
187 }
188 mod_key_state |= LEFT_WIN_PRESSED;
189 if (!NILP (Vw32_lwindow_modifier))
190 return 0;
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 {
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);
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;
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;
266 }
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)
277 {
278 if (!NILP (Vw32_recognize_altgr)
279 && (event->dwControlKeyState & LEFT_CTRL_PRESSED)
280 && (event->dwControlKeyState & RIGHT_ALT_PRESSED))
281 {
282 /* Don't try to interpret AltGr key chords; ToAscii seems not
283 to process them correctly. */
284 }
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)
310 w32_kbd_patch_key (event, -1);
311 }
312
313 if (event->uChar.AsciiChar == 0)
314 {
315 emacs_ev->kind = NO_EVENT;
316 return 0;
317 }
318 else if (event->uChar.AsciiChar > 0)
319 {
320 /* Pure ASCII characters < 128. */
321 emacs_ev->kind = ASCII_KEYSTROKE_EVENT;
322 emacs_ev->code = event->uChar.AsciiChar;
323 }
324 else if (event->uChar.UnicodeChar > 0
325 && w32_console_unicode_input)
326 {
327 /* Unicode codepoint; only valid if we are using Unicode
328 console input mode. */
329 emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
330 emacs_ev->code = event->uChar.UnicodeChar;
331 }
332 else
333 {
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. */
338 wchar_t code;
339 char dbcs[2];
340 int cpId;
341
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 ();
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]));
359 emacs_ev->kind = NO_EVENT;
360 }
361 }
362 else if (IsDBCSLeadByteEx (cpId, dbcs[1]))
363 {
364 dbcs_lead = dbcs[1];
365 emacs_ev->kind = NO_EVENT;
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]));
373 emacs_ev->kind = NO_EVENT;
374 }
375 }
376 emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
377 emacs_ev->code = code;
378 }
379 }
380 else
381 {
382 /* Function keys and other non-character keys. */
383 emacs_ev->kind = NON_ASCII_KEYSTROKE_EVENT;
384 emacs_ev->code = event->wVirtualKeyCode;
385 }
386
387 XSETFRAME (emacs_ev->frame_or_window, get_frame ());
388 emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState,
389 event->wVirtualKeyCode);
390 emacs_ev->timestamp = GetTickCount ();
391 return 1;
392 }
393
394 /* Mouse position hook. */
395 void
396 w32_console_mouse_position (struct frame **f,
397 int insist,
398 Lisp_Object *bar_window,
399 enum scroll_bar_part *part,
400 Lisp_Object *x,
401 Lisp_Object *y,
402 Time *time)
403 {
404 block_input ();
405
406 insist = insist;
407
408 *f = get_frame ();
409 *bar_window = Qnil;
410 *part = scroll_bar_above_handle;
411 SELECTED_FRAME ()->mouse_moved = 0;
412
413 XSETINT (*x, movement_pos.X);
414 XSETINT (*y, movement_pos.Y);
415 *time = movement_time;
416
417 unblock_input ();
418 }
419
420 /* Remember mouse motion and notify emacs. */
421 static void
422 mouse_moved_to (int x, int y)
423 {
424 /* If we're in the same place, ignore it. */
425 if (x != movement_pos.X || y != movement_pos.Y)
426 {
427 SELECTED_FRAME ()->mouse_moved = 1;
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 For the 3 standard buttons, we have:
441 Left == 0
442 Middle == 1
443 Right == 2
444 Others increase from there. */
445
446 #define NUM_TRANSLATED_MOUSE_BUTTONS 5
447 static int emacs_button_translation[NUM_TRANSLATED_MOUSE_BUTTONS] =
448 {
449 0, 2, 1, 3, 4
450 };
451
452 static int
453 do_mouse_event (MOUSE_EVENT_RECORD *event,
454 struct input_event *emacs_ev)
455 {
456 static DWORD button_state = 0;
457 static Lisp_Object last_mouse_window;
458 DWORD but_change, mask, flags = event->dwEventFlags;
459 int i;
460
461 switch (flags)
462 {
463 case MOUSE_MOVED:
464 {
465 struct frame *f = get_frame ();
466 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
467 int mx = event->dwMousePosition.X, my = event->dwMousePosition.Y;
468
469 mouse_moved_to (mx, my);
470
471 if (f->mouse_moved)
472 {
473 if (hlinfo->mouse_face_hidden)
474 {
475 hlinfo->mouse_face_hidden = 0;
476 clear_mouse_face (hlinfo);
477 }
478
479 /* Generate SELECT_WINDOW_EVENTs when needed. */
480 if (!NILP (Vmouse_autoselect_window))
481 {
482 Lisp_Object mouse_window = window_from_coordinates (f, mx, my,
483 0, 0);
484 /* A window will be selected only when it is not
485 selected now, and the last mouse movement event was
486 not in it. A minibuffer window will be selected iff
487 it is active. */
488 if (WINDOWP (mouse_window)
489 && !EQ (mouse_window, last_mouse_window)
490 && !EQ (mouse_window, selected_window))
491 {
492 struct input_event event;
493
494 EVENT_INIT (event);
495 event.kind = SELECT_WINDOW_EVENT;
496 event.frame_or_window = mouse_window;
497 event.arg = Qnil;
498 event.timestamp = movement_time;
499 kbd_buffer_store_event (&event);
500 }
501 last_mouse_window = mouse_window;
502 }
503 else
504 last_mouse_window = Qnil;
505
506 previous_help_echo_string = help_echo_string;
507 help_echo_string = help_echo_object = help_echo_window = Qnil;
508 help_echo_pos = -1;
509 note_mouse_highlight (f, mx, my);
510 /* If the contents of the global variable help_echo has
511 changed (inside note_mouse_highlight), generate a HELP_EVENT. */
512 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
513 gen_help_event (help_echo_string, selected_frame,
514 help_echo_window, help_echo_object,
515 help_echo_pos);
516 }
517 /* We already called kbd_buffer_store_event, so indicate the
518 the caller it shouldn't. */
519 return 0;
520 }
521 case MOUSE_WHEELED:
522 case MOUSE_HWHEELED:
523 {
524 struct frame *f = get_frame ();
525 int mx = event->dwMousePosition.X, my = event->dwMousePosition.Y;
526 bool down_p = (event->dwButtonState & 0x10000000) != 0;
527
528 emacs_ev->kind =
529 flags == MOUSE_HWHEELED ? HORIZ_WHEEL_EVENT : WHEEL_EVENT;
530 emacs_ev->code = 0;
531 emacs_ev->modifiers = down_p ? down_modifier : up_modifier;
532 emacs_ev->modifiers |=
533 w32_kbd_mods_to_emacs (event->dwControlKeyState, 0);
534 XSETINT (emacs_ev->x, mx);
535 XSETINT (emacs_ev->y, my);
536 XSETFRAME (emacs_ev->frame_or_window, f);
537 emacs_ev->arg = Qnil;
538 emacs_ev->timestamp = GetTickCount ();
539 return 1;
540 }
541 case DOUBLE_CLICK:
542 default: /* mouse pressed or released */
543 /* It looks like the console code sends us a button-release
544 mouse event with dwButtonState == 0 when a window is
545 activated and when the mouse is first clicked. Ignore this
546 case. */
547 if (event->dwButtonState == button_state)
548 return 0;
549
550 emacs_ev->kind = MOUSE_CLICK_EVENT;
551
552 /* Find out what button has changed state since the last button
553 event. */
554 but_change = button_state ^ event->dwButtonState;
555 mask = 1;
556 for (i = 0; mask; i++, mask <<= 1)
557 if (but_change & mask)
558 {
559 if (i < NUM_TRANSLATED_MOUSE_BUTTONS)
560 emacs_ev->code = emacs_button_translation[i];
561 else
562 emacs_ev->code = i;
563 break;
564 }
565
566 button_state = event->dwButtonState;
567 emacs_ev->modifiers =
568 w32_kbd_mods_to_emacs (event->dwControlKeyState, 0)
569 | ((event->dwButtonState & mask) ? down_modifier : up_modifier);
570
571 XSETFASTINT (emacs_ev->x, event->dwMousePosition.X);
572 XSETFASTINT (emacs_ev->y, event->dwMousePosition.Y);
573 XSETFRAME (emacs_ev->frame_or_window, get_frame ());
574 emacs_ev->arg = Qnil;
575 emacs_ev->timestamp = GetTickCount ();
576
577 return 1;
578 }
579 }
580
581 static void
582 resize_event (WINDOW_BUFFER_SIZE_RECORD *event)
583 {
584 struct frame *f = get_frame ();
585
586 change_frame_size (f, event->dwSize.X, event->dwSize.Y
587 - FRAME_MENU_BAR_LINES (f), 0, 1, 0, 0);
588 SET_FRAME_GARBAGED (f);
589 }
590
591 static void
592 maybe_generate_resize_event (void)
593 {
594 CONSOLE_SCREEN_BUFFER_INFO info;
595 struct frame *f = get_frame ();
596
597 GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);
598
599 /* It is okay to call this unconditionally, since it will do nothing
600 if the size hasn't actually changed. */
601 change_frame_size (f,
602 1 + info.srWindow.Right - info.srWindow.Left,
603 1 + info.srWindow.Bottom - info.srWindow.Top
604 - FRAME_MENU_BAR_LINES (f), 0, 1, 0, 0);
605 }
606
607 #if HAVE_W32NOTIFY
608 int
609 handle_file_notifications (struct input_event *hold_quit)
610 {
611 BYTE *p = file_notifications;
612 FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p;
613 const DWORD min_size
614 = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t);
615 struct input_event inev;
616 int nevents = 0;
617
618 /* We cannot process notification before Emacs is fully initialized,
619 since we need the UTF-16LE coding-system to be set up. */
620 if (!initialized)
621 {
622 notification_buffer_in_use = 0;
623 return nevents;
624 }
625
626 enter_crit ();
627 if (notification_buffer_in_use)
628 {
629 DWORD info_size = notifications_size;
630 Lisp_Object cs = Qutf_16le;
631 Lisp_Object obj = w32_get_watch_object (notifications_desc);
632
633 /* notifications_size could be zero when the buffer of
634 notifications overflowed on the OS level, or when the
635 directory being watched was itself deleted. Do nothing in
636 that case. */
637 if (info_size
638 && !NILP (obj) && CONSP (obj))
639 {
640 Lisp_Object callback = XCDR (obj);
641
642 EVENT_INIT (inev);
643
644 while (info_size >= min_size)
645 {
646 Lisp_Object utf_16_fn
647 = make_unibyte_string ((char *)fni->FileName,
648 fni->FileNameLength);
649 /* Note: mule-conf is preloaded, so utf-16le must
650 already be defined at this point. */
651 Lisp_Object fname
652 = code_convert_string_norecord (utf_16_fn, cs, 0);
653 Lisp_Object action = lispy_file_action (fni->Action);
654
655 inev.kind = FILE_NOTIFY_EVENT;
656 inev.timestamp = GetTickCount ();
657 inev.modifiers = 0;
658 inev.frame_or_window = callback;
659 inev.arg = Fcons (action, fname);
660 inev.arg = list3 (make_pointer_integer (notifications_desc),
661 action, fname);
662 kbd_buffer_store_event_hold (&inev, hold_quit);
663 nevents++;
664
665 if (!fni->NextEntryOffset)
666 break;
667 p += fni->NextEntryOffset;
668 fni = (PFILE_NOTIFY_INFORMATION)p;
669 info_size -= fni->NextEntryOffset;
670 }
671 }
672 notification_buffer_in_use = 0;
673 }
674 leave_crit ();
675 return nevents;
676 }
677 #else /* !HAVE_W32NOTIFY */
678 int
679 handle_file_notifications (struct input_event *hold_quit)
680 {
681 return 0;
682 }
683 #endif /* !HAVE_W32NOTIFY */
684
685 /* Here's an overview of how Emacs input works in non-GUI sessions on
686 MS-Windows. (For description of the GUI input, see the commentary
687 before w32_msg_pump in w32fns.c.)
688
689 When Emacs is idle, it loops inside wait_reading_process_output,
690 calling pselect periodically to check whether any input is
691 available. On Windows, pselect is redirected to sys_select, which
692 uses MsgWaitForMultipleObjects to wait for input, either from the
693 keyboard or from any of the Emacs subprocesses. In addition,
694 MsgWaitForMultipleObjects wakes up when some Windows message is
695 posted to the input queue of the Emacs's main thread (which is the
696 thread in which sys_select runs).
697
698 When the Emacs's console window has focus, Windows sends input
699 events that originate from the keyboard or the mouse; these events
700 wake up MsgWaitForMultipleObjects, which reports that input is
701 available. Emacs then calls w32_console_read_socket, below, to
702 read the input. w32_console_read_socket uses
703 GetNumberOfConsoleInputEvents and ReadConsoleInput to peek at and
704 read the console input events.
705
706 One type of non-keyboard input event that gets reported as input
707 available is due to the Emacs's console window receiving focus.
708 When that happens, Emacs gets the FOCUS_EVENT event and sys_select
709 reports some input; however, w32_console_read_socket ignores such
710 events when called to read them.
711
712 Note that any other Windows message sent to the main thread will
713 also wake up MsgWaitForMultipleObjects. These messages get
714 immediately dispatched to their destinations by calling
715 drain_message_queue. */
716
717 int
718 w32_console_read_socket (struct terminal *terminal,
719 struct input_event *hold_quit)
720 {
721 int nev, add;
722 int isdead;
723
724 block_input ();
725
726 for (;;)
727 {
728 int nfnotify = handle_file_notifications (hold_quit);
729
730 nev = fill_queue (0);
731 if (nev <= 0)
732 {
733 /* If nev == -1, there was some kind of error
734 If nev == 0 then no events were available
735 so return. */
736 if (nfnotify)
737 nev = 0;
738 break;
739 }
740
741 while (nev > 0)
742 {
743 struct input_event inev;
744 /* Having a separate variable with this value makes
745 debugging easier, as otherwise the compiler might
746 rearrange the switch below in a way that makes it hard to
747 track the event type. */
748 unsigned evtype = queue_ptr->EventType;
749
750 EVENT_INIT (inev);
751 inev.kind = NO_EVENT;
752 inev.arg = Qnil;
753
754 switch (evtype)
755 {
756 case KEY_EVENT:
757 add = key_event (&queue_ptr->Event.KeyEvent, &inev, &isdead);
758 if (add == -1) /* 95.7.25 by himi */
759 {
760 queue_ptr--;
761 add = 1;
762 }
763 if (add)
764 kbd_buffer_store_event_hold (&inev, hold_quit);
765 break;
766
767 case MOUSE_EVENT:
768 add = do_mouse_event (&queue_ptr->Event.MouseEvent, &inev);
769 if (add)
770 kbd_buffer_store_event_hold (&inev, hold_quit);
771 break;
772
773 case WINDOW_BUFFER_SIZE_EVENT:
774 if (w32_use_full_screen_buffer)
775 resize_event (&queue_ptr->Event.WindowBufferSizeEvent);
776 break;
777
778 case MENU_EVENT:
779 case FOCUS_EVENT:
780 /* Internal event types, ignored. */
781 break;
782 }
783
784 queue_ptr++;
785 nev--;
786 }
787 }
788
789 /* We don't get told about changes in the window size (only the buffer
790 size, which we no longer care about), so we have to check it
791 periodically. */
792 if (!w32_use_full_screen_buffer)
793 maybe_generate_resize_event ();
794
795 unblock_input ();
796 return nev;
797 }