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