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