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