Change identifiers of the form win32* to w32*.
[bpt/emacs.git] / src / w32inevt.c
CommitLineData
fbd6baed 1/* Input event support for Emacs under Win32 API.
b02466e8 2 Copyright (C) 1992, 1993, 1995 Free Software Foundation, Inc.
6cdfb6e6 3
3b7ad313
EN
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA.
6cdfb6e6
RS
20
21 Drew Bliss 01-Oct-93
22 Adapted from ntkbd.c by Tim Fleehart
23*/
24
25
26#include "config.h"
27
28#include <stdlib.h>
29#include <stdio.h>
30#include <windows.h>
31
32#include "lisp.h"
33#include "frame.h"
34#include "blockinput.h"
35#include "termhooks.h"
36
37/* stdin, from ntterm */
38extern HANDLE keyboard_handle;
39
6cdfb6e6
RS
40/* Info for last mouse motion */
41static COORD movement_pos;
42static DWORD movement_time;
43
44/* from keyboard.c */
45extern void reinvoke_input_signal (void);
46
47/* from dispnew.c */
48extern int change_frame_size (FRAME_PTR, int, int, int, int);
49
5a6816da 50/* from w32fns.c */
fbd6baed 51extern Lisp_Object Vw32_alt_is_meta;
5a6816da 52
6cdfb6e6
RS
53/* Event queue */
54#define EVENT_QUEUE_SIZE 50
55static INPUT_RECORD event_queue[EVENT_QUEUE_SIZE];
56static INPUT_RECORD *queue_ptr = event_queue, *queue_end = event_queue;
57
58static int
59fill_queue (BOOL block)
60{
61 BOOL rc;
62 DWORD events_waiting;
63
64 if (queue_ptr < queue_end)
65 return queue_end-queue_ptr;
66
67 if (!block)
68 {
69 /* Check to see if there are some events to read before we try
70 because we can't block. */
71 if (!GetNumberOfConsoleInputEvents (keyboard_handle, &events_waiting))
72 return -1;
73 if (events_waiting == 0)
74 return 0;
75 }
76
77 rc = ReadConsoleInput (keyboard_handle, event_queue, EVENT_QUEUE_SIZE,
78 &events_waiting);
79 if (!rc)
80 return -1;
81 queue_ptr = event_queue;
82 queue_end = event_queue + events_waiting;
83 return (int) events_waiting;
84}
85
86/* In a generic, multi-frame world this should take a console handle
87 and return the frame for it
88
89 Right now, there's only one frame so return it. */
90static FRAME_PTR
91get_frame (void)
92{
93 return selected_frame;
94}
95
b02466e8
KH
96/* Translate console modifiers to emacs modifiers.
97 German keyboard support (Kai Morgan Zeise 2/18/95). */
407c1745 98int
fbd6baed 99w32_kbd_mods_to_emacs (DWORD mods)
6cdfb6e6 100{
b02466e8
KH
101 int retval = 0;
102
103 /* If AltGr has been pressed, remove it. */
104 if ((mods & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
105 == (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
106 mods &= ~ (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED);
107
108 if (mods & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
fbd6baed 109 retval = ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier);
b02466e8
KH
110
111 if (mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
112 {
113 retval |= ctrl_modifier;
114 if ((mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
115 == (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
116 retval |= meta_modifier;
117 }
118
119 if (((mods & (SHIFT_PRESSED | CAPSLOCK_ON)) == SHIFT_PRESSED)
120 || ((mods & (SHIFT_PRESSED | CAPSLOCK_ON)) == CAPSLOCK_ON))
121 retval |= shift_modifier;
122
123 return retval;
124}
125
daf38066 126/* The return code indicates key code size. */
c0386d7e 127int
fbd6baed 128w32_kbd_patch_key (KEY_EVENT_RECORD *event)
b02466e8
KH
129{
130 unsigned int key_code = event->wVirtualKeyCode;
131 unsigned int mods = event->dwControlKeyState;
daf38066
GV
132 BYTE keystate[256];
133 static BYTE ansi_code[4];
407c1745 134 static int isdead = 0;
daf38066
GV
135
136 if (isdead == 2)
137 {
138 event->uChar.AsciiChar = ansi_code[2];
139 isdead = 0;
140 return 1;
b02466e8 141 }
daf38066
GV
142 if (event->uChar.AsciiChar != 0)
143 return 1;
c0386d7e 144
daf38066
GV
145 memset (keystate, 0, sizeof (keystate));
146 if (mods & SHIFT_PRESSED)
147 keystate[VK_SHIFT] = 0x80;
148 if (mods & CAPSLOCK_ON)
149 keystate[VK_CAPITAL] = 1;
c0386d7e
GV
150 if ((mods & LEFT_CTRL_PRESSED) && (mods & RIGHT_ALT_PRESSED))
151 {
152 keystate[VK_CONTROL] = 0x80;
153 keystate[VK_LCONTROL] = 0x80;
154 keystate[VK_MENU] = 0x80;
155 keystate[VK_RMENU] = 0x80;
156 }
157
daf38066
GV
158 isdead = ToAscii (event->wVirtualKeyCode, event->wVirtualScanCode,
159 keystate, (LPWORD) ansi_code, 0);
160 if (isdead == 0)
161 return 0;
162 event->uChar.AsciiChar = ansi_code[0];
163 return isdead;
6cdfb6e6 164}
407c1745 165
6cdfb6e6
RS
166/* Map virtual key codes into:
167 -1 - Ignore this key
168 -2 - ASCII char
169 Other - Map non-ASCII keys into X keysyms so that they are looked up
170 correctly in keyboard.c
171
172 Return, escape and tab are mapped to ASCII rather than coming back
173 as non-ASCII to be more compatible with old-style keyboard support. */
174
175static int map_virt_key[256] =
176{
daf38066
GV
177#ifdef MULE
178 -3,
179#else
6cdfb6e6 180 -1,
daf38066 181#endif
6cdfb6e6
RS
182 -1, /* VK_LBUTTON */
183 -1, /* VK_RBUTTON */
184 0x69, /* VK_CANCEL */
185 -1, /* VK_MBUTTON */
186 -1, -1, -1,
187 8, /* VK_BACK */
188 -2, /* VK_TAB */
189 -1, -1,
190 11, /* VK_CLEAR */
191 -2, /* VK_RETURN */
192 -1, -1,
193 -1, /* VK_SHIFT */
194 -1, /* VK_CONTROL */
195 -1, /* VK_MENU */
196 0x13, /* VK_PAUSE */
197 -1, /* VK_CAPITAL */
198 -1, -1, -1, -1, -1, -1,
199 -2, /* VK_ESCAPE */
200 -1, -1, -1, -1,
201 -2, /* VK_SPACE */
202 0x55, /* VK_PRIOR */
203 0x56, /* VK_NEXT */
204 0x57, /* VK_END */
205 0x50, /* VK_HOME */
206 0x51, /* VK_LEFT */
207 0x52, /* VK_UP */
208 0x53, /* VK_RIGHT */
209 0x54, /* VK_DOWN */
210 0x60, /* VK_SELECT */
211 0x61, /* VK_PRINT */
212 0x62, /* VK_EXECUTE */
213 -1, /* VK_SNAPSHOT */
214 0x63, /* VK_INSERT */
215 0xff, /* VK_DELETE */
216 0x6a, /* VK_HELP */
217 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, /* 0 - 9 */
218 -1, -1, -1, -1, -1, -1, -1,
219 -2, -2, -2, -2, -2, -2, -2, -2, /* A - Z */
220 -2, -2, -2, -2, -2, -2, -2, -2,
221 -2, -2, -2, -2, -2, -2, -2, -2,
222 -2, -2,
223 -1, -1, -1, -1, -1,
224 0xb0, /* VK_NUMPAD0 */
225 0xb1, /* VK_NUMPAD1 */
226 0xb2, /* VK_NUMPAD2 */
227 0xb3, /* VK_NUMPAD3 */
228 0xb4, /* VK_NUMPAD4 */
229 0xb5, /* VK_NUMPAD5 */
230 0xb6, /* VK_NUMPAD6 */
231 0xb7, /* VK_NUMPAD7 */
232 0xb8, /* VK_NUMPAD8 */
233 0xb9, /* VK_NUMPAD9 */
234 0xaa, /* VK_MULTIPLY */
235 0xab, /* VK_ADD */
236 0xac, /* VK_SEPARATOR */
237 0xad, /* VK_SUBTRACT */
238 0xae, /* VK_DECIMAL */
239 0xaf, /* VK_DIVIDE */
240 0xbe, /* VK_F1 */
241 0xbf, /* VK_F2 */
242 0xc0, /* VK_F3 */
243 0xc1, /* VK_F4 */
244 0xc2, /* VK_F5 */
245 0xc3, /* VK_F6 */
246 0xc4, /* VK_F7 */
247 0xc5, /* VK_F8 */
248 0xc6, /* VK_F9 */
249 0xc7, /* VK_F10 */
250 0xc8, /* VK_F11 */
251 0xc9, /* VK_F12 */
252 0xca, /* VK_F13 */
253 0xcb, /* VK_F14 */
254 0xcc, /* VK_F15 */
255 0xcd, /* VK_F16 */
256 0xce, /* VK_F17 */
257 0xcf, /* VK_F18 */
258 0xd0, /* VK_F19 */
259 0xd1, /* VK_F20 */
260 0xd2, /* VK_F21 */
261 0xd3, /* VK_F22 */
262 0xd4, /* VK_F23 */
263 0xd5, /* VK_F24 */
264 -1, -1, -1, -1, -1, -1, -1, -1,
265 0x7f, /* VK_NUMLOCK */
4ba58dd4 266 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x9f */
6cdfb6e6
RS
267 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xaf */
268 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb9 */
269 -2, /* ; */
270 -2, /* = */
271 -2, /* , */
272 -2, /* \ */
273 -2, /* . */
274 -2, /* / */
275 -2, /* ` */
4ba58dd4 276 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xcf */
6cdfb6e6 277 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xda */
4ba58dd4
RS
278 -2, -2, -2, -2, -2, /* 0xdf */
279 -2, -2, -2, -2, -2,
280 -1, /* 0xe5 */
281 -2, /* oxe6 */
282 -1, -1, /* 0xe8 */
283 -2, -2, -2, -2, -2, -2, -2, /* 0xef */
284 -2, -2, -2, -2, -2, -2,
285 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xff */
6cdfb6e6
RS
286};
287
daf38066
GV
288/* return code -1 means that event_queue_ptr won't be incremented.
289 In other word, this event makes two key codes. (by himi) */
c0386d7e 290int
6cdfb6e6
RS
291key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev)
292{
293 int map;
daf38066 294 int key_flag = 0;
b02466e8 295 static BOOL map_virt_key_init_done;
6cdfb6e6
RS
296
297 /* Skip key-up events. */
407c1745 298 if (!event->bKeyDown)
6cdfb6e6
RS
299 return 0;
300
301 if (event->wVirtualKeyCode > 0xff)
302 {
303 printf ("Unknown key code %d\n", event->wVirtualKeyCode);
304 return 0;
305 }
b02466e8
KH
306
307 /* Patch needed for German keyboard. Ulrich Leodolter (1/11/95). */
308 if (! map_virt_key_init_done)
309 {
310 short vk;
311
312 if ((vk = VkKeyScan (0x3c)) >= 0 && vk < 256) map_virt_key[vk] = -2; /* less */
313 if ((vk = VkKeyScan (0x3e)) >= 0 && vk < 256) map_virt_key[vk] = -2; /* greater */
314
315 map_virt_key_init_done = TRUE;
316 }
6cdfb6e6
RS
317
318 /* BUGBUG - Ignores the repeat count
319 It's questionable whether we want to obey the repeat count anyway
320 since keys usually aren't repeated unless key events back up in
321 the queue. If they're backing up then we don't generally want
322 to honor them later since that leads to significant slop in
323 cursor motion when the system is under heavy load. */
407c1745 324
6cdfb6e6
RS
325 map = map_virt_key[event->wVirtualKeyCode];
326 if (map == -1)
327 {
328 return 0;
329 }
330 else if (map == -2)
331 {
332 /* ASCII */
333 emacs_ev->kind = ascii_keystroke;
fbd6baed 334 key_flag = w32_kbd_patch_key (event); /* 95.7.25 by himi */
daf38066
GV
335 if (key_flag == 0)
336 return 0;
9e539a3c 337 XSETINT (emacs_ev->code, event->uChar.AsciiChar);
6cdfb6e6 338 }
daf38066
GV
339#ifdef MULE
340 /* for IME */
341 else if (map == -3)
342 {
343 if ((event->dwControlKeyState & NLS_IME_CONVERSION)
344 && !(event->dwControlKeyState & RIGHT_ALT_PRESSED)
345 && !(event->dwControlKeyState & LEFT_ALT_PRESSED)
346 && !(event->dwControlKeyState & RIGHT_CTRL_PRESSED)
347 && !(event->dwControlKeyState & LEFT_CTRL_PRESSED))
348 {
349 emacs_ev->kind = ascii_keystroke;
350 XSETINT (emacs_ev->code, event->uChar.AsciiChar);
351 }
352 else
353 return 0;
354 }
355#endif
6cdfb6e6
RS
356 else
357 {
358 /* non-ASCII */
359 emacs_ev->kind = non_ascii_keystroke;
407c1745
GV
360#ifdef HAVE_NTGUI
361 /* use Windows keysym map */
362 XSETINT (emacs_ev->code, event->wVirtualKeyCode);
363#else
6cdfb6e6
RS
364 /*
365 * make_lispy_event () now requires non-ascii codes to have
366 * the full X keysym values (2nd byte is 0xff). add it on.
367 */
368 map |= 0xff00;
9e539a3c 369 XSETINT (emacs_ev->code, map);
407c1745 370#endif /* HAVE_NTGUI */
6cdfb6e6 371 }
daf38066
GV
372/* for Mule 2.2 (Based on Emacs 19.28) */
373#ifdef MULE
374 XSET (emacs_ev->frame_or_window, Lisp_Frame, get_frame ());
375#else
b02466e8 376 XSETFRAME (emacs_ev->frame_or_window, get_frame ());
daf38066 377#endif
fbd6baed 378 emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState);
6cdfb6e6 379 emacs_ev->timestamp = GetTickCount ();
daf38066 380 if (key_flag == 2) return -1; /* 95.7.25 by himi */
6cdfb6e6
RS
381 return 1;
382}
383
384/* Mouse position hook. */
385void
fbd6baed 386w32_mouse_position (FRAME_PTR *f,
daf38066 387#ifndef MULE
b02466e8 388 int insist,
daf38066 389#endif
6cdfb6e6
RS
390 Lisp_Object *bar_window,
391 enum scroll_bar_part *part,
392 Lisp_Object *x,
393 Lisp_Object *y,
394 unsigned long *time)
395{
396 BLOCK_INPUT;
407c1745
GV
397
398#ifndef MULE
b02466e8 399 insist = insist;
daf38066 400#endif
b02466e8 401
6cdfb6e6
RS
402 *f = get_frame ();
403 *bar_window = Qnil;
404 *part = 0;
0e7078f5 405 selected_frame->mouse_moved = 0;
6cdfb6e6
RS
406
407 *x = movement_pos.X;
408 *y = movement_pos.Y;
409 *time = movement_time;
410
411 UNBLOCK_INPUT;
412}
413
414/* Remember mouse motion and notify emacs. */
415static void
416mouse_moved_to (int x, int y)
417{
418 /* If we're in the same place, ignore it */
419 if (x != movement_pos.X || y != movement_pos.Y)
420 {
0e7078f5 421 selected_frame->mouse_moved = 1;
6cdfb6e6
RS
422 movement_pos.X = x;
423 movement_pos.Y = y;
424 movement_time = GetTickCount ();
425 }
426}
427
428/* Consoles return button bits in a strange order:
429 least significant - Leftmost button
430 next - Rightmost button
431 next - Leftmost+1
432 next - Leftmost+2...
433
434 Assume emacs likes three button mice, so
435 Left == 0
436 Middle == 1
437 Right == 2
438 Others increase from there. */
439
440static int emacs_button_translation[NUM_MOUSE_BUTTONS] =
441{
442 0, 2, 1, 3, 4,
443};
444
445static int
446do_mouse_event (MOUSE_EVENT_RECORD *event,
447 struct input_event *emacs_ev)
448{
449 static DWORD button_state = 0;
450 DWORD but_change, mask;
451 int i;
452
453 if (event->dwEventFlags == MOUSE_MOVED)
454 {
455 /* For movement events we just note that the mouse has moved
456 so that emacs will generate drag events. */
457 mouse_moved_to (event->dwMousePosition.X, event->dwMousePosition.Y);
458 return 0;
459 }
460
461 /* It looks like the console code sends us a mouse event with
462 dwButtonState == 0 when a window is activated. Ignore this case. */
463 if (event->dwButtonState == button_state)
464 return 0;
465
466 emacs_ev->kind = mouse_click;
467
468 /* Find out what button has changed state since the last button event. */
469 but_change = button_state ^ event->dwButtonState;
470 mask = 1;
471 for (i = 0; i < NUM_MOUSE_BUTTONS; i++, mask <<= 1)
472 if (but_change & mask)
473 {
9e539a3c 474 XSETINT (emacs_ev->code, emacs_button_translation[i]);
6cdfb6e6
RS
475 break;
476 }
477
478 /* If the changed button is out of emacs' range (highly unlikely)
479 ignore this event. */
480 if (i == NUM_MOUSE_BUTTONS)
481 return 0;
482
483 button_state = event->dwButtonState;
484 emacs_ev->timestamp = GetTickCount ();
fbd6baed 485 emacs_ev->modifiers = w32_kbd_mods_to_emacs (event->dwControlKeyState) |
6cdfb6e6
RS
486 ((event->dwButtonState & mask) ? down_modifier : up_modifier);
487
9e539a3c
KH
488 XSETFASTINT (emacs_ev->x, event->dwMousePosition.X);
489 XSETFASTINT (emacs_ev->y, event->dwMousePosition.Y);
daf38066
GV
490/* for Mule 2.2 (Based on Emacs 19.28 */
491#ifdef MULE
492 XSET (emacs_ev->frame_or_window, Lisp_Frame, get_frame ());
493#else
b02466e8 494 XSETFRAME (emacs_ev->frame_or_window, get_frame ());
daf38066 495#endif
6cdfb6e6
RS
496
497 return 1;
498}
499
500static void
501resize_event (WINDOW_BUFFER_SIZE_RECORD *event)
502{
503 FRAME_PTR f = get_frame ();
504
505 change_frame_size (f, event->dwSize.Y, event->dwSize.X, 0, 1);
506 SET_FRAME_GARBAGED (f);
507}
508
509int
fbd6baed
GV
510w32_console_read_socket (int sd, struct input_event *bufp, int numchars,
511 int waitp, int expected)
6cdfb6e6
RS
512{
513 BOOL no_events = TRUE;
514 int nev, ret = 0, add;
515
516 if (interrupt_input_blocked)
517 {
518 interrupt_input_pending = 1;
519 return -1;
520 }
521
522 interrupt_input_pending = 0;
523 BLOCK_INPUT;
524
525 for (;;)
526 {
06c2c73d 527 nev = fill_queue (0);
6cdfb6e6
RS
528 if (nev <= 0)
529 {
530 /* If nev == -1, there was some kind of error
531 If nev == 0 then waitp must be zero and no events were available
532 so return. */
533 UNBLOCK_INPUT;
534 return nev;
535 }
536
537 while (nev > 0 && numchars > 0)
538 {
539 switch (queue_ptr->EventType)
540 {
541 case KEY_EVENT:
542 add = key_event (&queue_ptr->Event.KeyEvent, bufp);
daf38066
GV
543 if (add == -1) /* 95.7.25 by himi */
544 {
545 queue_ptr--;
546 add = 1;
547 }
6cdfb6e6
RS
548 bufp += add;
549 ret += add;
550 numchars -= add;
551 break;
552
553 case MOUSE_EVENT:
554 add = do_mouse_event (&queue_ptr->Event.MouseEvent, bufp);
555 bufp += add;
556 ret += add;
557 numchars -= add;
558 break;
559
560 case WINDOW_BUFFER_SIZE_EVENT:
561 resize_event (&queue_ptr->Event.WindowBufferSizeEvent);
562 break;
563
564 case MENU_EVENT:
565 case FOCUS_EVENT:
566 /* Internal event types, ignored. */
567 break;
568 }
569
570 queue_ptr++;
571 nev--;
572 }
573
574 if (ret > 0 || expected == 0)
575 break;
576 }
577
578 UNBLOCK_INPUT;
579 return ret;
580}