w32inevt.c 20.1 KB
Newer Older
1
/* Input event support for Emacs on the Microsoft W32 API.
2
   Copyright (C) 1992, 1993, 1995, 2001, 2002, 2003, 2004, 2005, 2006,
Glenn Morris's avatar
Glenn Morris committed
3
                 2007, 2008, 2009  Free Software Foundation, Inc.
Richard M. Stallman's avatar
Richard M. Stallman committed
4

5 6
This file is part of GNU Emacs.

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 10
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
11 12 13 14 15 16 17

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

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/>.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
19

20
/*
Richard M. Stallman's avatar
Richard M. Stallman committed
21 22 23 24 25
   Drew Bliss                   01-Oct-93
     Adapted from ntkbd.c by Tim Fleehart
*/


Pavel Janík's avatar
Pavel Janík committed
26 27 28
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
Richard M. Stallman's avatar
Richard M. Stallman committed
29 30 31 32 33

#include <stdlib.h>
#include <stdio.h>
#include <windows.h>

34 35 36 37
#ifndef MOUSE_MOVED
#define MOUSE_MOVED   1
#endif

Richard M. Stallman's avatar
Richard M. Stallman committed
38
#include "lisp.h"
39
#include "keyboard.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
40
#include "frame.h"
41
#include "dispextern.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
42 43
#include "blockinput.h"
#include "termhooks.h"
44 45
#include "w32heap.h"
#include "w32term.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
46 47 48 49 50 51 52 53 54 55 56

/* stdin, from ntterm */
extern HANDLE keyboard_handle;

/* Info for last mouse motion */
static COORD movement_pos;
static DWORD movement_time;

/* from keyboard.c */
extern void reinvoke_input_signal (void);

57 58 59
/* from w32console.c */
extern int w32_use_full_screen_buffer;

60
/* from w32fns.c */
61
extern Lisp_Object Vw32_alt_is_meta;
62
extern unsigned int map_keypad_keys (unsigned int, unsigned int);
63

64 65
/* from w32term */
extern Lisp_Object Vw32_capslock_is_shiftlock;
66 67
extern Lisp_Object Vw32_enable_caps_lock;
extern Lisp_Object Vw32_enable_num_lock;
68
extern Lisp_Object Vw32_recognize_altgr;
69 70
extern Lisp_Object Vw32_pass_lwindow_to_system;
extern Lisp_Object Vw32_pass_rwindow_to_system;
71
extern Lisp_Object Vw32_phantom_key_code;
72 73 74 75 76
extern Lisp_Object Vw32_lwindow_modifier;
extern Lisp_Object Vw32_rwindow_modifier;
extern Lisp_Object Vw32_apps_modifier;
extern Lisp_Object Vw32_scroll_lock_modifier;
extern unsigned int w32_key_to_modifier (int key);
77

Richard M. Stallman's avatar
Richard M. Stallman committed
78 79 80 81 82
/* Event queue */
#define EVENT_QUEUE_SIZE 50
static INPUT_RECORD event_queue[EVENT_QUEUE_SIZE];
static INPUT_RECORD *queue_ptr = event_queue, *queue_end = event_queue;

83
static int
Richard M. Stallman's avatar
Richard M. Stallman committed
84 85 86 87
fill_queue (BOOL block)
{
  BOOL rc;
  DWORD events_waiting;
88

Richard M. Stallman's avatar
Richard M. Stallman committed
89 90
  if (queue_ptr < queue_end)
    return queue_end-queue_ptr;
91

Richard M. Stallman's avatar
Richard M. Stallman committed
92 93 94 95 96 97 98 99 100
  if (!block)
    {
      /* Check to see if there are some events to read before we try
	 because we can't block.  */
      if (!GetNumberOfConsoleInputEvents (keyboard_handle, &events_waiting))
	return -1;
      if (events_waiting == 0)
	return 0;
    }
101

Richard M. Stallman's avatar
Richard M. Stallman committed
102 103 104 105 106 107 108 109 110 111 112 113 114
  rc = ReadConsoleInput (keyboard_handle, event_queue, EVENT_QUEUE_SIZE,
			 &events_waiting);
  if (!rc)
    return -1;
  queue_ptr = event_queue;
  queue_end = event_queue + events_waiting;
  return (int) events_waiting;
}

/* In a generic, multi-frame world this should take a console handle
   and return the frame for it

   Right now, there's only one frame so return it.  */
115
static FRAME_PTR
Richard M. Stallman's avatar
Richard M. Stallman committed
116 117
get_frame (void)
{
118
  return SELECTED_FRAME ();
Richard M. Stallman's avatar
Richard M. Stallman committed
119 120
}

121
/* Translate console modifiers to emacs modifiers.
122
   German keyboard support (Kai Morgan Zeise 2/18/95).  */
123
int
124
w32_kbd_mods_to_emacs (DWORD mods, WORD key)
Richard M. Stallman's avatar
Richard M. Stallman committed
125
{
126 127
  int retval = 0;

128
  /* If we recognize right-alt and left-ctrl as AltGr, and it has been
129
     pressed, first remove those modifiers.  */
130 131
  if (!NILP (Vw32_recognize_altgr)
      && (mods & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
132 133 134 135
      == (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
    mods &= ~ (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED);

  if (mods & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
136
    retval = ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier);
137

138 139 140
  if (mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
    {
      retval |= ctrl_modifier;
141
      if ((mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
142 143 144 145
	  == (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
	retval |= meta_modifier;
    }

146 147 148 149 150 151 152 153 154
  if (mods & LEFT_WIN_PRESSED)
    retval |= w32_key_to_modifier (VK_LWIN);
  if (mods & RIGHT_WIN_PRESSED)
    retval |= w32_key_to_modifier (VK_RWIN);
  if (mods & APPS_PRESSED)
    retval |= w32_key_to_modifier (VK_APPS);
  if (mods & SCROLLLOCK_ON)
    retval |= w32_key_to_modifier (VK_SCROLL);

Glenn Morris's avatar
Glenn Morris committed
155
  /* Just in case someone wanted the original behavior, make it
156
     optional by setting w32-capslock-is-shiftlock to t.  */
157 158 159 160 161 162 163 164 165 166 167
  if (NILP (Vw32_capslock_is_shiftlock)
      /* Keys that should _not_ be affected by CapsLock.  */
      && (    (key == VK_BACK)
	   || (key == VK_TAB)
	   || (key == VK_CLEAR)
	   || (key == VK_RETURN)
	   || (key == VK_ESCAPE)
	   || ((key >= VK_SPACE) && (key <= VK_HELP))
	   || ((key >= VK_NUMPAD0) && (key <= VK_F24))
	   || ((key >= VK_NUMPAD_CLEAR) && (key <= VK_NUMPAD_DELETE))
	 ))
168
    {
169 170
      /* Only consider shift state.  */
      if ((mods & SHIFT_PRESSED) != 0)
171 172 173 174
	retval |= shift_modifier;
    }
  else
    {
175 176 177 178 179
      /* Ignore CapsLock state if not enabled.  */
      if (NILP (Vw32_enable_caps_lock))
	mods &= ~CAPSLOCK_ON;
      if ((mods & (SHIFT_PRESSED | CAPSLOCK_ON)) != 0)
	retval |= shift_modifier;
180
    }
181 182 183 184

  return retval;
}

185 186 187 188 189 190 191 192 193 194 195 196
#if 0
/* Return nonzero if the virtual key is a dead key.  */
static int
is_dead_key (int wparam)
{
  unsigned int code = MapVirtualKey (wparam, 2);

  /* Windows 95 returns 0x8000, NT returns 0x80000000.  */
  return (code & 0x80008000) ? 1 : 0;
}
#endif

197
/* The return code indicates key code size. */
198
int
199
w32_kbd_patch_key (KEY_EVENT_RECORD *event)
200 201 202
{
  unsigned int key_code = event->wVirtualKeyCode;
  unsigned int mods = event->dwControlKeyState;
203 204
  BYTE keystate[256];
  static BYTE ansi_code[4];
205
  static int isdead = 0;
206 207 208 209 210 211

  if (isdead == 2)
    {
      event->uChar.AsciiChar = ansi_code[2];
      isdead = 0;
      return 1;
212
    }
213
  if (event->uChar.AsciiChar != 0)
214
    return 1;
215

216
  memset (keystate, 0, sizeof (keystate));
217
  keystate[key_code] = 0x80;
218
  if (mods & SHIFT_PRESSED)
219
    keystate[VK_SHIFT] = 0x80;
220
  if (mods & CAPSLOCK_ON)
221
    keystate[VK_CAPITAL] = 1;
222 223 224 225
  /* If we recognize right-alt and left-ctrl as AltGr, set the key
     states accordingly before invoking ToAscii.  */
  if (!NILP (Vw32_recognize_altgr)
      && (mods & LEFT_CTRL_PRESSED) && (mods & RIGHT_ALT_PRESSED))
226 227 228 229 230 231 232
    {
      keystate[VK_CONTROL] = 0x80;
      keystate[VK_LCONTROL] = 0x80;
      keystate[VK_MENU] = 0x80;
      keystate[VK_RMENU] = 0x80;
    }

233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
#if 0
  /* Because of an OS bug, ToAscii corrupts the stack when called to
     convert a dead key in console mode on NT4.  Unfortunately, trying
     to check for dead keys using MapVirtualKey doesn't work either -
     these functions apparently use internal information about keyboard
     layout which doesn't get properly updated in console programs when
     changing layout (though apparently it gets partly updated,
     otherwise ToAscii wouldn't crash).  */
  if (is_dead_key (event->wVirtualKeyCode))
    return 0;
#endif

  /* On NT, call ToUnicode instead and then convert to the current
     locale's default codepage.  */
  if (os_subtype == OS_NT)
    {
      WCHAR buf[128];

      isdead = ToUnicode (event->wVirtualKeyCode, event->wVirtualScanCode,
			  keystate, buf, 128, 0);
      if (isdead > 0)
	{
          char cp[20];
          int cpId;

          GetLocaleInfo (GetThreadLocale (),
			 LOCALE_IDEFAULTANSICODEPAGE, cp, 20);
          cpId = atoi (cp);
          isdead = WideCharToMultiByte (cpId, 0, buf, isdead,
					ansi_code, 4, NULL, NULL);
	}
      else
	isdead = 0;
    }
  else
    {
      isdead = ToAscii (event->wVirtualKeyCode, event->wVirtualScanCode,
                        keystate, (LPWORD) ansi_code, 0);
    }

273
  if (isdead == 0)
274 275 276
    return 0;
  event->uChar.AsciiChar = ansi_code[0];
  return isdead;
Richard M. Stallman's avatar
Richard M. Stallman committed
277
}
278

Richard M. Stallman's avatar
Richard M. Stallman committed
279

280
extern char *lispy_function_keys[];
Richard M. Stallman's avatar
Richard M. Stallman committed
281

282 283
static int faked_key = 0;

284
/* return code -1 means that event_queue_ptr won't be incremented.
285
   In other word, this event makes two key codes.   (by himi)       */
286
int
287
key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
Richard M. Stallman's avatar
Richard M. Stallman committed
288
{
289 290
  static int mod_key_state = 0;
  int wParam;
291 292

  *isdead = 0;
293

Richard M. Stallman's avatar
Richard M. Stallman committed
294
  /* Skip key-up events.  */
295
  if (!event->bKeyDown)
Richard M. Stallman's avatar
Richard M. Stallman committed
296
    {
297 298 299 300 301 302 303 304 305 306 307 308
      switch (event->wVirtualKeyCode)
	{
	case VK_LWIN:
	  mod_key_state &= ~LEFT_WIN_PRESSED;
	  break;
	case VK_RWIN:
	  mod_key_state &= ~RIGHT_WIN_PRESSED;
	  break;
	case VK_APPS:
	  mod_key_state &= ~APPS_PRESSED;
	  break;
	}
Richard M. Stallman's avatar
Richard M. Stallman committed
309 310
      return 0;
    }
311

312 313
  /* Ignore keystrokes we fake ourself; see below.  */
  if (faked_key == event->wVirtualKeyCode)
Richard M. Stallman's avatar
Richard M. Stallman committed
314
    {
315
      faked_key = 0;
Richard M. Stallman's avatar
Richard M. Stallman committed
316 317
      return 0;
    }
318 319 320

  /* To make it easier to debug this code, ignore modifier keys!  */
  switch (event->wVirtualKeyCode)
Richard M. Stallman's avatar
Richard M. Stallman committed
321
    {
322 323 324 325 326 327 328 329
    case VK_LWIN:
      if (NILP (Vw32_pass_lwindow_to_system))
	{
	  /* Prevent system from acting on keyup (which opens the Start
	     menu if no other key was pressed) by simulating a press of
	     Space which we will ignore.  */
	  if ((mod_key_state & LEFT_WIN_PRESSED) == 0)
	    {
330 331 332 333 334
	      if (NUMBERP (Vw32_phantom_key_code))
		faked_key = XUINT (Vw32_phantom_key_code) & 255;
	      else
		faked_key = VK_SPACE;
	      keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0);
335 336 337 338
	    }
	}
      mod_key_state |= LEFT_WIN_PRESSED;
      if (!NILP (Vw32_lwindow_modifier))
339
	return 0;
340 341 342 343 344 345
      break;
    case VK_RWIN:
      if (NILP (Vw32_pass_rwindow_to_system))
	{
	  if ((mod_key_state & RIGHT_WIN_PRESSED) == 0)
	    {
346 347 348 349 350
	      if (NUMBERP (Vw32_phantom_key_code))
		faked_key = XUINT (Vw32_phantom_key_code) & 255;
	      else
		faked_key = VK_SPACE;
	      keybd_event (faked_key, (BYTE) MapVirtualKey (faked_key, 0), 0, 0);
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
	    }
	}
      mod_key_state |= RIGHT_WIN_PRESSED;
      if (!NILP (Vw32_rwindow_modifier))
	return 0;
      break;
    case VK_APPS:
      mod_key_state |= APPS_PRESSED;
      if (!NILP (Vw32_apps_modifier))
	return 0;
      break;
    case VK_CAPITAL:
      /* Decide whether to treat as modifier or function key.  */
      if (NILP (Vw32_enable_caps_lock))
	goto disable_lock_key;
      return 0;
    case VK_NUMLOCK:
      /* Decide whether to treat as modifier or function key.  */
      if (NILP (Vw32_enable_num_lock))
	goto disable_lock_key;
      return 0;
    case VK_SCROLL:
      /* Decide whether to treat as modifier or function key.  */
      if (NILP (Vw32_scroll_lock_modifier))
	goto disable_lock_key;
      return 0;
    disable_lock_key:
      /* Ensure the appropriate lock key state is off (and the
	 indicator light as well).  */
      wParam = event->wVirtualKeyCode;
      if (GetAsyncKeyState (wParam) & 0x8000)
	{
	  /* Fake another press of the relevant key.  Apparently, this
	     really is the only way to turn off the indicator.  */
	  faked_key = wParam;
	  keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
		       KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
	  keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
		       KEYEVENTF_EXTENDEDKEY | 0, 0);
	  keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
		       KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
	}
      break;
    case VK_MENU:
    case VK_CONTROL:
    case VK_SHIFT:
      return 0;
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
    case VK_CANCEL:
      /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
	 which is confusing for purposes of key binding; convert
	 VK_CANCEL events into VK_PAUSE events.  */
      event->wVirtualKeyCode = VK_PAUSE;
      break;
    case VK_PAUSE:
      /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
	 for purposes of key binding; convert these back into
	 VK_NUMLOCK events, at least when we want to see NumLock key
	 presses.  (Note that there is never any possibility that
	 VK_PAUSE with Ctrl really is C-Pause as per above.)  */
      if (NILP (Vw32_enable_num_lock)
	  && (event->dwControlKeyState
	      & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0)
	event->wVirtualKeyCode = VK_NUMLOCK;
      break;
Richard M. Stallman's avatar
Richard M. Stallman committed
415
    }
416 417 418 419 420 421 422 423 424 425

  /* Recognize state of Windows and Apps keys.  */
  event->dwControlKeyState |= mod_key_state;

  /* Distinguish numeric keypad keys from extended keys.  */
  event->wVirtualKeyCode =
    map_keypad_keys (event->wVirtualKeyCode,
		     (event->dwControlKeyState & ENHANCED_KEY));

  if (lispy_function_keys[event->wVirtualKeyCode] == 0)
426
    {
Pavel Janík's avatar
Pavel Janík committed
427
      emacs_ev->kind = ASCII_KEYSTROKE_EVENT;
428 429 430 431

      if (!NILP (Vw32_recognize_altgr)
	  && (event->dwControlKeyState & LEFT_CTRL_PRESSED)
	  && (event->dwControlKeyState & RIGHT_ALT_PRESSED))
432
	{
433 434
	  /* Don't try to interpret AltGr key chords; ToAscii seems not
	     to process them correctly.  */
435
	}
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
      /* Handle key chords including any modifiers other than shift
         directly, in order to preserve as much modifier information as
         possible.  */
      else if (event->dwControlKeyState
	       & (  RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED
		  | RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED
		  | (!NILP (Vw32_lwindow_modifier) ? LEFT_WIN_PRESSED : 0)
		  | (!NILP (Vw32_rwindow_modifier) ? RIGHT_WIN_PRESSED : 0)
		  | (!NILP (Vw32_apps_modifier) ? APPS_PRESSED : 0)
		  | (!NILP (Vw32_scroll_lock_modifier) ? SCROLLLOCK_ON : 0)))
	{
	  /* Don't translate modified alphabetic keystrokes, so the user
	     doesn't need to constantly switch layout to type control or
	     meta keystrokes when the normal layout translates
	     alphabetic characters to non-ascii characters.  */
	  if ('A' <= event->wVirtualKeyCode && event->wVirtualKeyCode <= 'Z')
	    {
	      event->uChar.AsciiChar = event->wVirtualKeyCode;
	      if ((event->dwControlKeyState & SHIFT_PRESSED) == 0)
		event->uChar.AsciiChar += ('a' - 'A');
	    }
	  /* Try to handle unrecognized keystrokes by determining the
             base character (ie. translating the base key plus shift
             modifier).  */
	  else if (event->uChar.AsciiChar == 0)
	    w32_kbd_patch_key (event);
	}
      if (event->uChar.AsciiChar == 0)
464
	return 0;
465
      emacs_ev->code = event->uChar.AsciiChar;
466
    }
Richard M. Stallman's avatar
Richard M. Stallman committed
467 468
  else
    {
Pavel Janík's avatar
Pavel Janík committed
469
      emacs_ev->kind = NON_ASCII_KEYSTROKE_EVENT;
470
      emacs_ev->code = event->wVirtualKeyCode;
Richard M. Stallman's avatar
Richard M. Stallman committed
471
    }
472

473
  XSETFRAME (emacs_ev->frame_or_window, get_frame ());
474 475
  emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState,
					       event->wVirtualKeyCode);
Richard M. Stallman's avatar
Richard M. Stallman committed
476 477 478 479
  emacs_ev->timestamp = GetTickCount ();
  return 1;
}

480 481 482 483 484 485 486
int
w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state)
{
  int cur_state = (GetKeyState (vk_code) & 1);

  if (NILP (new_state)
      || (NUMBERP (new_state)
487
	  && ((XUINT (new_state)) & 1) != cur_state))
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
    {
      faked_key = vk_code;

      keybd_event ((BYTE) vk_code,
		   (BYTE) MapVirtualKey (vk_code, 0),
		   KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
      keybd_event ((BYTE) vk_code,
		   (BYTE) MapVirtualKey (vk_code, 0),
		   KEYEVENTF_EXTENDEDKEY | 0, 0);
      keybd_event ((BYTE) vk_code,
		   (BYTE) MapVirtualKey (vk_code, 0),
		   KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
      cur_state = !cur_state;
    }

  return cur_state;
}

Richard M. Stallman's avatar
Richard M. Stallman committed
506
/* Mouse position hook.  */
507
void
508 509 510 511 512 513 514
w32_console_mouse_position (FRAME_PTR *f,
			    int insist,
			    Lisp_Object *bar_window,
			    enum scroll_bar_part *part,
			    Lisp_Object *x,
			    Lisp_Object *y,
			    unsigned long *time)
Richard M. Stallman's avatar
Richard M. Stallman committed
515 516
{
  BLOCK_INPUT;
517

518 519
  insist = insist;

Richard M. Stallman's avatar
Richard M. Stallman committed
520 521 522
  *f = get_frame ();
  *bar_window = Qnil;
  *part = 0;
523
  SELECTED_FRAME ()->mouse_moved = 0;
524

525 526
  XSETINT(*x, movement_pos.X);
  XSETINT(*y, movement_pos.Y);
Richard M. Stallman's avatar
Richard M. Stallman committed
527
  *time = movement_time;
528

Richard M. Stallman's avatar
Richard M. Stallman committed
529 530 531 532
  UNBLOCK_INPUT;
}

/* Remember mouse motion and notify emacs.  */
533
static void
Richard M. Stallman's avatar
Richard M. Stallman committed
534 535 536 537 538
mouse_moved_to (int x, int y)
{
  /* If we're in the same place, ignore it */
  if (x != movement_pos.X || y != movement_pos.Y)
    {
539
      SELECTED_FRAME ()->mouse_moved = 1;
Richard M. Stallman's avatar
Richard M. Stallman committed
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
      movement_pos.X = x;
      movement_pos.Y = y;
      movement_time = GetTickCount ();
    }
}

/* Consoles return button bits in a strange order:
     least significant - Leftmost button
     next - Rightmost button
     next - Leftmost+1
     next - Leftmost+2...

   Assume emacs likes three button mice, so
     Left == 0
     Middle == 1
     Right == 2
   Others increase from there.  */

558 559
#define NUM_TRANSLATED_MOUSE_BUTTONS 3
static int emacs_button_translation[NUM_TRANSLATED_MOUSE_BUTTONS] =
Richard M. Stallman's avatar
Richard M. Stallman committed
560
{
561
  0, 2, 1
Richard M. Stallman's avatar
Richard M. Stallman committed
562 563
};

564
static int
Richard M. Stallman's avatar
Richard M. Stallman committed
565 566 567 568 569 570
do_mouse_event (MOUSE_EVENT_RECORD *event,
		struct input_event *emacs_ev)
{
  static DWORD button_state = 0;
  DWORD but_change, mask;
  int i;
571

Richard M. Stallman's avatar
Richard M. Stallman committed
572 573 574 575 576 577 578
  if (event->dwEventFlags == MOUSE_MOVED)
    {
      /* For movement events we just note that the mouse has moved
	 so that emacs will generate drag events.  */
      mouse_moved_to (event->dwMousePosition.X, event->dwMousePosition.Y);
      return 0;
    }
579

Richard M. Stallman's avatar
Richard M. Stallman committed
580 581 582 583
  /* It looks like the console code sends us a mouse event with
     dwButtonState == 0 when a window is activated.  Ignore this case.  */
  if (event->dwButtonState == button_state)
    return 0;
584

Pavel Janík's avatar
Pavel Janík committed
585
  emacs_ev->kind = MOUSE_CLICK_EVENT;
586

Richard M. Stallman's avatar
Richard M. Stallman committed
587 588 589
  /* Find out what button has changed state since the last button event.  */
  but_change = button_state ^ event->dwButtonState;
  mask = 1;
590
  for (i = 0; mask; i++, mask <<= 1)
Richard M. Stallman's avatar
Richard M. Stallman committed
591 592
    if (but_change & mask)
      {
593
        if (i < NUM_TRANSLATED_MOUSE_BUTTONS)
594
          emacs_ev->code = emacs_button_translation[i];
595
        else
596
          emacs_ev->code = i;
Richard M. Stallman's avatar
Richard M. Stallman committed
597 598 599 600 601
	break;
      }

  button_state = event->dwButtonState;
  emacs_ev->timestamp = GetTickCount ();
602
  emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState, 0) |
Richard M. Stallman's avatar
Richard M. Stallman committed
603
    ((event->dwButtonState & mask) ? down_modifier : up_modifier);
604

605 606
  XSETFASTINT (emacs_ev->x, event->dwMousePosition.X);
  XSETFASTINT (emacs_ev->y, event->dwMousePosition.Y);
607 608 609 610
/* for Mule 2.2 (Based on Emacs 19.28 */
#ifdef MULE
  XSET (emacs_ev->frame_or_window, Lisp_Frame, get_frame ());
#else
611
  XSETFRAME (emacs_ev->frame_or_window, get_frame ());
612
#endif
613

Richard M. Stallman's avatar
Richard M. Stallman committed
614 615 616
  return 1;
}

617
static void
Richard M. Stallman's avatar
Richard M. Stallman committed
618 619 620
resize_event (WINDOW_BUFFER_SIZE_RECORD *event)
{
  FRAME_PTR f = get_frame ();
621

622
  change_frame_size (f, event->dwSize.Y, event->dwSize.X, 0, 1, 0);
Richard M. Stallman's avatar
Richard M. Stallman committed
623 624 625
  SET_FRAME_GARBAGED (f);
}

626 627 628 629 630 631 632 633 634 635 636 637 638
static void
maybe_generate_resize_event ()
{
  CONSOLE_SCREEN_BUFFER_INFO info;
  FRAME_PTR f = get_frame ();

  GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info);

  /* It is okay to call this unconditionally, since it will do nothing
     if the size hasn't actually changed.  */
  change_frame_size (f,
		     1 + info.srWindow.Bottom - info.srWindow.Top,
		     1 + info.srWindow.Right - info.srWindow.Left,
639
		     0, 0, 0);
640 641
}

642
int
643 644 645
w32_console_read_socket (struct terminal *terminal,
                         int expected,
                         struct input_event *hold_quit)
Richard M. Stallman's avatar
Richard M. Stallman committed
646 647 648
{
  BOOL no_events = TRUE;
  int nev, ret = 0, add;
649 650
  int isdead;

Richard M. Stallman's avatar
Richard M. Stallman committed
651 652 653
  if (interrupt_input_blocked)
    {
      interrupt_input_pending = 1;
654
#ifdef SYNC_INPUT
655
      pending_signals = 1;
656
#endif
Richard M. Stallman's avatar
Richard M. Stallman committed
657 658
      return -1;
    }
659

Richard M. Stallman's avatar
Richard M. Stallman committed
660
  interrupt_input_pending = 0;
661
#ifdef SYNC_INPUT
662
  pending_signals = pending_atimers;
663
#endif
Richard M. Stallman's avatar
Richard M. Stallman committed
664
  BLOCK_INPUT;
665

Richard M. Stallman's avatar
Richard M. Stallman committed
666 667
  for (;;)
    {
668
      nev = fill_queue (0);
Richard M. Stallman's avatar
Richard M. Stallman committed
669 670 671 672 673 674 675 676 677
      if (nev <= 0)
        {
	  /* If nev == -1, there was some kind of error
	     If nev == 0 then waitp must be zero and no events were available
	     so return.  */
	  UNBLOCK_INPUT;
	  return nev;
        }

678
      while (nev > 0)
Richard M. Stallman's avatar
Richard M. Stallman committed
679
        {
680 681 682 683 684 685
	  struct input_event inev;

	  EVENT_INIT (inev);
	  inev.kind = NO_EVENT;
	  inev.arg = Qnil;

Richard M. Stallman's avatar
Richard M. Stallman committed
686 687 688
	  switch (queue_ptr->EventType)
            {
            case KEY_EVENT:
689
	      add = key_event (&queue_ptr->Event.KeyEvent, &inev, &isdead);
690
	      if (add == -1) /* 95.7.25 by himi */
691
		{
692 693 694
		  queue_ptr--;
		  add = 1;
		}
695 696
	      if (add)
		kbd_buffer_store_event_hold (&inev, hold_quit);
Richard M. Stallman's avatar
Richard M. Stallman committed
697 698 699
	      break;

            case MOUSE_EVENT:
700 701 702
	      add = do_mouse_event (&queue_ptr->Event.MouseEvent, &inev);
	      if (add)
		kbd_buffer_store_event_hold (&inev, hold_quit);
Richard M. Stallman's avatar
Richard M. Stallman committed
703 704 705
	      break;

            case WINDOW_BUFFER_SIZE_EVENT:
706 707
	      if (w32_use_full_screen_buffer)
		resize_event (&queue_ptr->Event.WindowBufferSizeEvent);
Richard M. Stallman's avatar
Richard M. Stallman committed
708
	      break;
709

Richard M. Stallman's avatar
Richard M. Stallman committed
710 711 712 713 714
            case MENU_EVENT:
            case FOCUS_EVENT:
	      /* Internal event types, ignored. */
	      break;
            }
715

Richard M. Stallman's avatar
Richard M. Stallman committed
716 717 718 719 720 721 722
	  queue_ptr++;
	  nev--;
        }

      if (ret > 0 || expected == 0)
	break;
    }
723 724 725 726

  /* We don't get told about changes in the window size (only the buffer
     size, which we no longer care about), so we have to check it
     periodically.  */
727 728
  if (!w32_use_full_screen_buffer)
    maybe_generate_resize_event ();
729

Richard M. Stallman's avatar
Richard M. Stallman committed
730 731 732
  UNBLOCK_INPUT;
  return ret;
}
Miles Bader's avatar
Miles Bader committed
733 734 735

/* arch-tag: 0bcb39b7-d085-4b85-9070-6750e8c03047
   (do not change this comment) */