w32inevt.c 20.4 KB
Newer Older
1
/* Input event support for Emacs on the Microsoft W32 API.
2
   Copyright (C) 1992-1993, 1995, 2001-2011  Free Software Foundation, Inc.
Richard M. Stallman's avatar
Richard M. Stallman committed
3

4 5
This file is part of GNU Emacs.

6
GNU Emacs is free software: you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8 9
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
10 11 12 13 14 15 16

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
17
along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
Richard M. Stallman's avatar
Richard M. Stallman committed
18

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


Pavel Janík's avatar
Pavel Janík committed
25
#include <config.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
26 27
#include <stdio.h>
#include <windows.h>
28
#include <setjmp.h>
Richard M. Stallman's avatar
Richard M. Stallman committed
29

30 31 32 33
#ifndef MOUSE_MOVED
#define MOUSE_MOVED   1
#endif

Richard M. Stallman's avatar
Richard M. Stallman committed
34
#include "lisp.h"
35
#include "keyboard.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
36
#include "frame.h"
37
#include "dispextern.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
38 39
#include "blockinput.h"
#include "termhooks.h"
40 41
#include "w32heap.h"
#include "w32term.h"
Richard M. Stallman's avatar
Richard M. Stallman committed
42

43
/* stdin, from w32console.c */
Richard M. Stallman's avatar
Richard M. Stallman committed
44 45 46 47 48 49
extern HANDLE keyboard_handle;

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

50
/* from w32fns.c */
51 52
extern unsigned int map_keypad_keys (unsigned int, unsigned int);
extern unsigned int w32_key_to_modifier (int key);
53

Richard M. Stallman's avatar
Richard M. Stallman committed
54 55 56 57 58
/* 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;

59 60 61
/* Temporarily store lead byte of DBCS input sequences.  */
static char dbcs_lead = 0;

62
static int
Richard M. Stallman's avatar
Richard M. Stallman committed
63 64 65 66
fill_queue (BOOL block)
{
  BOOL rc;
  DWORD events_waiting;
67

Richard M. Stallman's avatar
Richard M. Stallman committed
68 69
  if (queue_ptr < queue_end)
    return queue_end-queue_ptr;
70

Richard M. Stallman's avatar
Richard M. Stallman committed
71 72 73 74 75 76 77 78 79
  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;
    }
80

Richard M. Stallman's avatar
Richard M. Stallman committed
81 82 83 84 85 86 87 88 89 90 91 92 93
  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.  */
94
static FRAME_PTR
Richard M. Stallman's avatar
Richard M. Stallman committed
95 96
get_frame (void)
{
97
  return SELECTED_FRAME ();
Richard M. Stallman's avatar
Richard M. Stallman committed
98 99
}

100
/* Translate console modifiers to emacs modifiers.
101
   German keyboard support (Kai Morgan Zeise 2/18/95).  */
102
int
103
w32_kbd_mods_to_emacs (DWORD mods, WORD key)
Richard M. Stallman's avatar
Richard M. Stallman committed
104
{
105 106
  int retval = 0;

107
  /* If we recognize right-alt and left-ctrl as AltGr, and it has been
108
     pressed, first remove those modifiers.  */
109 110
  if (!NILP (Vw32_recognize_altgr)
      && (mods & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
111 112 113 114
      == (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
    mods &= ~ (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED);

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

117 118 119
  if (mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
    {
      retval |= ctrl_modifier;
120
      if ((mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
121 122 123 124
	  == (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
	retval |= meta_modifier;
    }

125 126 127 128 129 130 131 132 133
  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
134
  /* Just in case someone wanted the original behavior, make it
135
     optional by setting w32-capslock-is-shiftlock to t.  */
136 137 138 139 140 141 142 143 144 145 146
  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))
	 ))
147
    {
148 149
      /* Only consider shift state.  */
      if ((mods & SHIFT_PRESSED) != 0)
150 151 152 153
	retval |= shift_modifier;
    }
  else
    {
154 155 156 157 158
      /* 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;
159
    }
160 161 162 163

  return retval;
}

164 165 166 167 168 169 170 171 172 173 174 175
#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

176
/* The return code indicates key code size. */
177
int
178
w32_kbd_patch_key (KEY_EVENT_RECORD *event)
179 180 181
{
  unsigned int key_code = event->wVirtualKeyCode;
  unsigned int mods = event->dwControlKeyState;
182 183
  BYTE keystate[256];
  static BYTE ansi_code[4];
184
  static int isdead = 0;
185 186 187 188 189 190

  if (isdead == 2)
    {
      event->uChar.AsciiChar = ansi_code[2];
      isdead = 0;
      return 1;
191
    }
192
  if (event->uChar.AsciiChar != 0)
193
    return 1;
194

195
  memset (keystate, 0, sizeof (keystate));
196
  keystate[key_code] = 0x80;
197
  if (mods & SHIFT_PRESSED)
198
    keystate[VK_SHIFT] = 0x80;
199
  if (mods & CAPSLOCK_ON)
200
    keystate[VK_CAPITAL] = 1;
201 202 203 204
  /* 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))
205 206 207 208 209 210 211
    {
      keystate[VK_CONTROL] = 0x80;
      keystate[VK_LCONTROL] = 0x80;
      keystate[VK_MENU] = 0x80;
      keystate[VK_RMENU] = 0x80;
    }

212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
#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)
	{
234 235
	  char cp[20];
	  int cpId;
236

237 238 239
	  event->uChar.UnicodeChar = buf[isdead - 1];

	  GetLocaleInfo (GetThreadLocale (),
240
			 LOCALE_IDEFAULTANSICODEPAGE, cp, 20);
241 242
	  cpId = atoi (cp);
	  isdead = WideCharToMultiByte (cpId, 0, buf, isdead,
243 244 245 246 247 248 249 250 251 252 253
					ansi_code, 4, NULL, NULL);
	}
      else
	isdead = 0;
    }
  else
    {
      isdead = ToAscii (event->wVirtualKeyCode, event->wVirtualScanCode,
                        keystate, (LPWORD) ansi_code, 0);
    }

254
  if (isdead == 0)
255 256 257
    return 0;
  event->uChar.AsciiChar = ansi_code[0];
  return isdead;
Richard M. Stallman's avatar
Richard M. Stallman committed
258
}
259

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

261 262
static int faked_key = 0;

263
/* return code -1 means that event_queue_ptr won't be incremented.
264
   In other word, this event makes two key codes.   (by himi)       */
265
static int
266
key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
Richard M. Stallman's avatar
Richard M. Stallman committed
267
{
268 269
  static int mod_key_state = 0;
  int wParam;
270 271

  *isdead = 0;
272

Richard M. Stallman's avatar
Richard M. Stallman committed
273
  /* Skip key-up events.  */
274
  if (!event->bKeyDown)
Richard M. Stallman's avatar
Richard M. Stallman committed
275
    {
276 277 278 279 280 281 282 283 284 285 286 287
      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
288 289
      return 0;
    }
290

291 292
  /* Ignore keystrokes we fake ourself; see below.  */
  if (faked_key == event->wVirtualKeyCode)
Richard M. Stallman's avatar
Richard M. Stallman committed
293
    {
294
      faked_key = 0;
Richard M. Stallman's avatar
Richard M. Stallman committed
295 296
      return 0;
    }
297 298 299

  /* To make it easier to debug this code, ignore modifier keys!  */
  switch (event->wVirtualKeyCode)
Richard M. Stallman's avatar
Richard M. Stallman committed
300
    {
301 302 303 304 305 306 307 308
    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)
	    {
309 310 311 312 313
	      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);
314 315 316 317
	    }
	}
      mod_key_state |= LEFT_WIN_PRESSED;
      if (!NILP (Vw32_lwindow_modifier))
318
	return 0;
319 320 321 322 323 324
      break;
    case VK_RWIN:
      if (NILP (Vw32_pass_rwindow_to_system))
	{
	  if ((mod_key_state & RIGHT_WIN_PRESSED) == 0)
	    {
325 326 327 328 329
	      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);
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 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
	    }
	}
      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;
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
    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
394
    }
395 396 397 398 399 400 401 402 403 404

  /* 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)
405
    {
406 407 408
      if (!NILP (Vw32_recognize_altgr)
	  && (event->dwControlKeyState & LEFT_CTRL_PRESSED)
	  && (event->dwControlKeyState & RIGHT_ALT_PRESSED))
409
	{
410 411
	  /* Don't try to interpret AltGr key chords; ToAscii seems not
	     to process them correctly.  */
412
	}
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
      /* 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);
	}
440

441
      if (event->uChar.AsciiChar == 0)
442 443 444 445
	{
	  emacs_ev->kind = NO_EVENT;
	  return 0;
	}
446
      else if (event->uChar.AsciiChar > 0)
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
	{
	  emacs_ev->kind = ASCII_KEYSTROKE_EVENT;
	  emacs_ev->code = event->uChar.AsciiChar;
	}
      else if (event->uChar.UnicodeChar > 0)
	{
	  emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
	  emacs_ev->code = event->uChar.UnicodeChar;
	}
      else
	{
	  /* Fallback for non-Unicode versions of Windows.  */
	  wchar_t code;
	  char dbcs[2];
          char cp[20];
          int cpId;

	  /* Get the codepage to interpret this key with.  */
          GetLocaleInfo (GetThreadLocale (),
			 LOCALE_IDEFAULTANSICODEPAGE, cp, 20);
          cpId = atoi (cp);

	  dbcs[0] = dbcs_lead;
	  dbcs[1] = event->uChar.AsciiChar;
	  if (dbcs_lead)
	    {
	      dbcs_lead = 0;
	      if (!MultiByteToWideChar (cpId, 0, dbcs, 2, &code, 1))
		{
		  /* Garbage  */
		  DebPrint (("Invalid DBCS sequence: %d %d\n",
			     dbcs[0], dbcs[1]));
479
		  emacs_ev->kind = NO_EVENT;
480 481 482 483 484
		}
	    }
	  else if (IsDBCSLeadByteEx (cpId, dbcs[1]))
	    {
	      dbcs_lead = dbcs[1];
485
	      emacs_ev->kind = NO_EVENT;
486 487 488 489 490 491 492
	    }
	  else
	    {
	      if (!MultiByteToWideChar (cpId, 0, &dbcs[1], 1, &code, 1))
		{
		  /* Garbage  */
		  DebPrint (("Invalid character: %d\n", dbcs[1]));
493
		  emacs_ev->kind = NO_EVENT;
494 495 496 497 498
		}
	    }
	  emacs_ev->kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
	  emacs_ev->code = code;
	}
499
    }
Richard M. Stallman's avatar
Richard M. Stallman committed
500 501
  else
    {
Pavel Janík's avatar
Pavel Janík committed
502
      emacs_ev->kind = NON_ASCII_KEYSTROKE_EVENT;
503
      emacs_ev->code = event->wVirtualKeyCode;
Richard M. Stallman's avatar
Richard M. Stallman committed
504
    }
505

506
  XSETFRAME (emacs_ev->frame_or_window, get_frame ());
507 508
  emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState,
					       event->wVirtualKeyCode);
Richard M. Stallman's avatar
Richard M. Stallman committed
509 510 511 512
  emacs_ev->timestamp = GetTickCount ();
  return 1;
}

513 514 515 516 517 518 519
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)
520
	  && ((XUINT (new_state)) & 1) != cur_state))
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
    {
      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
539
/* Mouse position hook.  */
540
void
541 542 543 544 545 546 547
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
548 549
{
  BLOCK_INPUT;
550

551 552
  insist = insist;

Richard M. Stallman's avatar
Richard M. Stallman committed
553 554 555
  *f = get_frame ();
  *bar_window = Qnil;
  *part = 0;
556
  SELECTED_FRAME ()->mouse_moved = 0;
557

558 559
  XSETINT (*x, movement_pos.X);
  XSETINT (*y, movement_pos.Y);
Richard M. Stallman's avatar
Richard M. Stallman committed
560
  *time = movement_time;
561

Richard M. Stallman's avatar
Richard M. Stallman committed
562 563 564 565
  UNBLOCK_INPUT;
}

/* Remember mouse motion and notify emacs.  */
566
static void
Richard M. Stallman's avatar
Richard M. Stallman committed
567 568 569 570 571
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)
    {
572
      SELECTED_FRAME ()->mouse_moved = 1;
Richard M. Stallman's avatar
Richard M. Stallman committed
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
      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.  */

591 592
#define NUM_TRANSLATED_MOUSE_BUTTONS 3
static int emacs_button_translation[NUM_TRANSLATED_MOUSE_BUTTONS] =
Richard M. Stallman's avatar
Richard M. Stallman committed
593
{
594
  0, 2, 1
Richard M. Stallman's avatar
Richard M. Stallman committed
595 596
};

597
static int
Richard M. Stallman's avatar
Richard M. Stallman committed
598 599 600 601 602 603
do_mouse_event (MOUSE_EVENT_RECORD *event,
		struct input_event *emacs_ev)
{
  static DWORD button_state = 0;
  DWORD but_change, mask;
  int i;
604

Richard M. Stallman's avatar
Richard M. Stallman committed
605 606 607 608 609 610 611
  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;
    }
612

Richard M. Stallman's avatar
Richard M. Stallman committed
613 614 615 616
  /* 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;
617

Pavel Janík's avatar
Pavel Janík committed
618
  emacs_ev->kind = MOUSE_CLICK_EVENT;
619

Richard M. Stallman's avatar
Richard M. Stallman committed
620 621 622
  /* Find out what button has changed state since the last button event.  */
  but_change = button_state ^ event->dwButtonState;
  mask = 1;
623
  for (i = 0; mask; i++, mask <<= 1)
Richard M. Stallman's avatar
Richard M. Stallman committed
624 625
    if (but_change & mask)
      {
626
        if (i < NUM_TRANSLATED_MOUSE_BUTTONS)
627
          emacs_ev->code = emacs_button_translation[i];
628
        else
629
          emacs_ev->code = i;
Richard M. Stallman's avatar
Richard M. Stallman committed
630 631 632 633 634
	break;
      }

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

638 639
  XSETFASTINT (emacs_ev->x, event->dwMousePosition.X);
  XSETFASTINT (emacs_ev->y, event->dwMousePosition.Y);
640 641 642 643
/* for Mule 2.2 (Based on Emacs 19.28 */
#ifdef MULE
  XSET (emacs_ev->frame_or_window, Lisp_Frame, get_frame ());
#else
644
  XSETFRAME (emacs_ev->frame_or_window, get_frame ());
645
#endif
646

Richard M. Stallman's avatar
Richard M. Stallman committed
647 648 649
  return 1;
}

650
static void
Richard M. Stallman's avatar
Richard M. Stallman committed
651 652 653
resize_event (WINDOW_BUFFER_SIZE_RECORD *event)
{
  FRAME_PTR f = get_frame ();
654

655
  change_frame_size (f, event->dwSize.Y, event->dwSize.X, 0, 1, 0);
Richard M. Stallman's avatar
Richard M. Stallman committed
656 657 658
  SET_FRAME_GARBAGED (f);
}

659
static void
660
maybe_generate_resize_event (void)
661 662 663 664 665 666 667 668 669 670 671
{
  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,
672
		     0, 0, 0);
673 674
}

675
int
676 677 678
w32_console_read_socket (struct terminal *terminal,
                         int expected,
                         struct input_event *hold_quit)
Richard M. Stallman's avatar
Richard M. Stallman committed
679 680 681
{
  BOOL no_events = TRUE;
  int nev, ret = 0, add;
682 683
  int isdead;

Richard M. Stallman's avatar
Richard M. Stallman committed
684 685 686 687 688
  if (interrupt_input_blocked)
    {
      interrupt_input_pending = 1;
      return -1;
    }
689

Richard M. Stallman's avatar
Richard M. Stallman committed
690 691
  interrupt_input_pending = 0;
  BLOCK_INPUT;
692

Richard M. Stallman's avatar
Richard M. Stallman committed
693 694
  for (;;)
    {
695
      nev = fill_queue (0);
Richard M. Stallman's avatar
Richard M. Stallman committed
696 697 698 699 700 701 702 703 704
      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;
        }

705
      while (nev > 0)
Richard M. Stallman's avatar
Richard M. Stallman committed
706
        {
707 708 709 710 711 712
	  struct input_event inev;

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

Richard M. Stallman's avatar
Richard M. Stallman committed
713 714 715
	  switch (queue_ptr->EventType)
            {
            case KEY_EVENT:
716
	      add = key_event (&queue_ptr->Event.KeyEvent, &inev, &isdead);
717
	      if (add == -1) /* 95.7.25 by himi */
718
		{
719 720 721
		  queue_ptr--;
		  add = 1;
		}
722 723
	      if (add)
		kbd_buffer_store_event_hold (&inev, hold_quit);
Richard M. Stallman's avatar
Richard M. Stallman committed
724 725 726
	      break;

            case MOUSE_EVENT:
727 728 729
	      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
730 731 732
	      break;

            case WINDOW_BUFFER_SIZE_EVENT:
733 734
	      if (w32_use_full_screen_buffer)
		resize_event (&queue_ptr->Event.WindowBufferSizeEvent);
Richard M. Stallman's avatar
Richard M. Stallman committed
735
	      break;
736

Richard M. Stallman's avatar
Richard M. Stallman committed
737 738 739 740 741
            case MENU_EVENT:
            case FOCUS_EVENT:
	      /* Internal event types, ignored. */
	      break;
            }
742

Richard M. Stallman's avatar
Richard M. Stallman committed
743 744 745 746 747 748 749
	  queue_ptr++;
	  nev--;
        }

      if (ret > 0 || expected == 0)
	break;
    }
750 751 752 753

  /* 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.  */
754 755
  if (!w32_use_full_screen_buffer)
    maybe_generate_resize_event ();
756

Richard M. Stallman's avatar
Richard M. Stallman committed
757 758 759
  UNBLOCK_INPUT;
  return ret;
}
Miles Bader's avatar
Miles Bader committed
760