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