213
|
1 /* mswindows specific event-handling.
|
|
2 Copyright (C) 1997 Jonathan Harris.
|
|
3
|
|
4 This file is part of XEmacs.
|
|
5
|
|
6 XEmacs 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
|
|
9 later version.
|
|
10
|
|
11 XEmacs 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
|
|
14 for more details.
|
|
15
|
|
16 You should have received a copy of the GNU General Public License
|
|
17 along with XEmacs; see the file COPYING. If not, write to
|
|
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
19 Boston, MA 02111-1307, USA. */
|
|
20
|
|
21 /* Synched up with: Not in FSF. */
|
|
22
|
|
23 /* Authorship:
|
|
24
|
|
25 Jonathan Harris, November 1997 for 20.4.
|
|
26 */
|
|
27
|
|
28 /*
|
|
29 * Comment:
|
|
30 *
|
|
31 * Windows user-input type events are stored in a per-thread message queue
|
|
32 * and retrieved using GetMessage(). It is not possible to wait on this
|
|
33 * queue and on other events (eg process input) simultaneously. Also, the
|
|
34 * main event-handling code in windows (the "windows procedure") is called
|
|
35 * asynchronously when windows has certain other types of events ("nonqueued
|
|
36 * messages") to deliver. The documentation doesn't appear to specify the
|
|
37 * context in which the windows procedure is called, but I assume that the
|
|
38 * thread that created the window is temporarily highjacked for this purpose.
|
|
39 *
|
|
40 * We spawn off a single thread to deal with both kinds of messages. The
|
|
41 * thread turns the windows events into emacs_events and stuffs them in a
|
|
42 * queue which XEmacs reads at its leisure. This file contains the code for
|
|
43 * the thread. This scheme also helps to prevent weird synchronisation and
|
|
44 * deadlock problems that might occur if the windows procedure was called
|
|
45 * when XEmacs was already in the middle of processing an event.
|
|
46 *
|
|
47 * Unfortunately, only the thread that created a window can retrieve messages
|
|
48 * destined for that window ("GetMessage does not retrieve messages for
|
|
49 * windows that belong to other threads..."). This means that our message-
|
|
50 * processing thread also has to do all window creation. We handle this
|
|
51 * bogosity by getting the main XEmacs thread to send special user-defined
|
|
52 * messages to the message-processing thread to instruct it to create windows.
|
|
53 */
|
|
54
|
|
55
|
|
56 #include <config.h>
|
|
57 #include "lisp.h"
|
|
58
|
|
59 #include "console-msw.h"
|
|
60 #include "device.h"
|
|
61 #include "frame.h"
|
|
62 #include "events.h"
|
|
63 #include "event-msw.h"
|
|
64
|
|
65 #define MSWINDOWS_FRAME_STYLE WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_TILEDWINDOW
|
|
66 #define MSWINDOWS_POPUP_STYLE WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_CAPTION|WS_POPUP
|
|
67
|
|
68 static LRESULT WINAPI mswindows_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
69 static Lisp_Object mswindows_find_console (HWND hwnd);
|
|
70 static Lisp_Object mswindows_find_frame (HWND hwnd);
|
|
71 static Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key);
|
|
72
|
|
73 /*
|
|
74 * Entry point for the "windows" message-processing thread
|
|
75 */
|
|
76 DWORD mswindows_win_thread()
|
|
77 {
|
|
78 WNDCLASS wc;
|
|
79 MSG msg;
|
|
80 mswindows_waitable_info_type info;
|
|
81
|
|
82 /* Register the main window class */
|
|
83 wc.style = CS_OWNDC; /* One DC per window */
|
|
84 wc.lpfnWndProc = (WNDPROC) mswindows_wnd_proc;
|
|
85 wc.cbClsExtra = 0;
|
|
86 wc.cbWndExtra = 0; /* ? */
|
|
87 wc.hInstance = NULL; /* ? */
|
|
88 wc.hIcon = LoadIcon (NULL, XEMACS_CLASS);
|
|
89 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
|
|
90 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
|
|
91 wc.lpszMenuName = NULL; /* XXX FIXME? Add a menu? */
|
|
92 wc.lpszClassName = XEMACS_CLASS;
|
|
93 RegisterClass(&wc); /* XXX FIXME: Should use RegisterClassEx */
|
|
94
|
|
95 info.type = mswindows_waitable_type_dispatch;
|
|
96 mswindows_add_waitable(&info);
|
|
97
|
|
98 /* Ensure our message queue is created XXX FIXME: Is this necessary? */
|
|
99 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
|
|
100
|
|
101 /* Notify the main thread that we're ready */
|
|
102 assert(PostThreadMessage (mswindows_main_thread_id, WM_XEMACS_ACK, 0, 0));
|
|
103
|
|
104 /* Main windows loop */
|
|
105 while (1)
|
|
106 {
|
|
107 GetMessage (&msg, NULL, 0, 0);
|
|
108
|
|
109 /*
|
|
110 * Process things that don't have an associated window, so wouldn't
|
|
111 * get sent to mswindows_wnd_proc
|
|
112 */
|
|
113
|
|
114 /* Request from main thread */
|
|
115 if (msg.message>=WM_XEMACS_BASE && msg.message<=WM_XEMACS_END)
|
|
116 mswindows_handle_request(&msg);
|
|
117
|
|
118 /* Timeout */
|
|
119 else if (msg.message == WM_TIMER)
|
|
120 {
|
|
121 Lisp_Object emacs_event;
|
|
122 struct Lisp_Event *event;
|
|
123
|
|
124 KillTimer(NULL, msg.wParam);
|
|
125 EnterCriticalSection (&mswindows_dispatch_crit);
|
|
126 emacs_event = Fmake_event (Qnil, Qnil);
|
|
127 event = XEVENT(emacs_event);
|
|
128
|
|
129 event->channel = Qnil;
|
|
130 event->timestamp = msg.time;
|
|
131 event->event_type = timeout_event;
|
|
132 event->event.timeout.interval_id = msg.wParam;
|
|
133 mswindows_enqueue_dispatch_event (emacs_event);
|
|
134 LeaveCriticalSection (&mswindows_dispatch_crit);
|
|
135 }
|
|
136 else
|
|
137 /* Pass on to mswindows_wnd_proc */
|
|
138 DispatchMessage (&msg);
|
|
139 }
|
|
140 }
|
|
141
|
|
142 /*
|
|
143 * The windows procedure for the window class XEMACS_CLASS
|
|
144 * Stuffs messages in the mswindows event queue
|
|
145 */
|
|
146 static LRESULT WINAPI mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam,
|
|
147 LPARAM lParam)
|
|
148 {
|
|
149 /* Note: Remember to initialise these before use */
|
|
150 Lisp_Object emacs_event;
|
|
151 struct Lisp_Event *event;
|
|
152
|
|
153 static int mods = 0;
|
|
154 MSG msg = { hwnd, message, wParam, lParam, 0, {0,0} };
|
|
155 msg.time = GetMessageTime();
|
|
156
|
|
157 #if 0 /* XXX */
|
|
158 stderr_out("Message %04x, wParam=%04x, lParam=%08lx\n", message, wParam, lParam);
|
|
159 #endif
|
|
160 switch (message)
|
|
161 {
|
|
162 case WM_KEYDOWN:
|
|
163 case WM_SYSKEYDOWN:
|
|
164 switch(wParam)
|
|
165 {
|
|
166 case VK_SHIFT:
|
|
167 mods |= MOD_SHIFT;
|
|
168 break;
|
|
169 case VK_CONTROL:
|
|
170 mods |= MOD_CONTROL;
|
|
171 break;
|
|
172 case VK_MENU:
|
|
173 mods |= MOD_META;
|
|
174 break;
|
|
175 default:
|
|
176 /* Handle those keys that TranslateMessage won't generate a WM_CHAR for */
|
|
177 {
|
|
178 Lisp_Object keysym;
|
|
179 if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam)))
|
|
180 {
|
|
181 EnterCriticalSection (&mswindows_dispatch_crit);
|
|
182 emacs_event = Fmake_event (Qnil, Qnil);
|
|
183 event = XEVENT(emacs_event);
|
|
184
|
|
185 event->channel = mswindows_find_console(hwnd);
|
|
186 event->timestamp = msg.time;
|
|
187 event->event_type = key_press_event;
|
|
188 event->event.key.keysym = keysym;
|
|
189 event->event.key.modifiers = mods;
|
|
190 mswindows_enqueue_dispatch_event (emacs_event);
|
|
191 LeaveCriticalSection (&mswindows_dispatch_crit);
|
|
192 return (0);
|
|
193 }
|
|
194 }
|
|
195 }
|
|
196 TranslateMessage (&msg); /* Maybe generates WM_[SYS]CHAR in message queue */
|
|
197 goto defproc;
|
|
198
|
|
199 case WM_KEYUP:
|
|
200 case WM_SYSKEYUP:
|
|
201 switch(wParam)
|
|
202 {
|
|
203 case VK_SHIFT:
|
|
204 mods &= ~MOD_SHIFT;
|
|
205 break;
|
|
206 case VK_CONTROL:
|
|
207 mods &= ~MOD_CONTROL;
|
|
208 break;
|
|
209 case VK_MENU:
|
|
210 mods &= ~MOD_META;
|
|
211 break;
|
|
212 }
|
|
213 TranslateMessage (&msg);
|
|
214 goto defproc;
|
|
215
|
|
216 case WM_CHAR:
|
|
217 case WM_SYSCHAR:
|
|
218 {
|
|
219 EnterCriticalSection (&mswindows_dispatch_crit);
|
|
220 emacs_event = Fmake_event (Qnil, Qnil);
|
|
221 event = XEVENT(emacs_event);
|
|
222
|
|
223 event->channel = mswindows_find_console(hwnd);
|
|
224 event->timestamp = msg.time;
|
|
225 event->event_type = key_press_event;
|
|
226 event->event.key.modifiers = mods;
|
|
227 event->event.key.modifiers = lParam & 0x20000000 ? MOD_META : 0; /* redundant? */
|
|
228 if (wParam<' ') /* Control char not handled under WM_KEYDOWN */
|
|
229 {
|
|
230 event->event.key.keysym = make_char(wParam+'a'-1);
|
|
231 event->event.key.modifiers |= MOD_CONTROL; /* redundant? */
|
|
232 }
|
|
233 else
|
|
234 {
|
|
235 /* Assumes that emacs keysym == ASCII code */
|
|
236 event->event.key.keysym = make_char(wParam);
|
|
237 }
|
|
238 mswindows_enqueue_dispatch_event (emacs_event);
|
|
239 LeaveCriticalSection (&mswindows_dispatch_crit);
|
|
240 }
|
|
241 break;
|
|
242
|
|
243 case WM_LBUTTONDOWN:
|
|
244 case WM_MBUTTONDOWN:
|
|
245 case WM_RBUTTONDOWN:
|
|
246 case WM_LBUTTONUP:
|
|
247 case WM_MBUTTONUP:
|
|
248 case WM_RBUTTONUP:
|
|
249 {
|
|
250 /* XXX FIXME: Do middle button emulation */
|
|
251 EnterCriticalSection (&mswindows_dispatch_crit);
|
|
252 emacs_event = Fmake_event (Qnil, Qnil);
|
|
253 event = XEVENT(emacs_event);
|
|
254
|
|
255 event->channel = mswindows_find_frame(hwnd);
|
|
256 event->timestamp = msg.time;
|
|
257 event->event_type =
|
|
258 (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN ||
|
|
259 message==WM_RBUTTONDOWN) ?
|
|
260 button_press_event : button_release_event;
|
|
261 #if 0
|
|
262 ((wParam & MK_CONTROL) ? MOD_CONTROL : 0) |
|
|
263 ((wParam & MK_SHIFT) ? MOD_SHIFT : 0);
|
|
264 #endif
|
|
265 event->event.button.button =
|
|
266 (message==WM_LBUTTONDOWN || message==WM_LBUTTONUP) ? 1 :
|
|
267 ((message==WM_RBUTTONDOWN || message==WM_RBUTTONUP) ? 3 : 2);
|
|
268 event->event.button.x = LOWORD(lParam);
|
|
269 event->event.button.y = HIWORD(lParam);
|
|
270 event->event.button.modifiers = mods;
|
|
271
|
|
272 mswindows_enqueue_dispatch_event (emacs_event);
|
|
273 LeaveCriticalSection (&mswindows_dispatch_crit);
|
|
274 }
|
|
275 break;
|
|
276
|
|
277 case WM_MOUSEMOVE:
|
|
278 {
|
|
279 EnterCriticalSection (&mswindows_dispatch_crit);
|
|
280 emacs_event = Fmake_event (Qnil, Qnil);
|
|
281 event = XEVENT(emacs_event);
|
|
282
|
|
283 event->channel = mswindows_find_frame(hwnd);
|
|
284 event->timestamp = msg.time;
|
|
285 event->event_type = pointer_motion_event;
|
|
286 event->event.motion.x = LOWORD(lParam);
|
|
287 event->event.motion.y = HIWORD(lParam);
|
|
288 event->event.motion.modifiers = mods;
|
|
289
|
|
290 mswindows_enqueue_dispatch_event (emacs_event);
|
|
291 LeaveCriticalSection (&mswindows_dispatch_crit);
|
|
292 }
|
|
293 break;
|
|
294
|
|
295 case WM_PAINT:
|
|
296 if (GetUpdateRect(hwnd, NULL, FALSE))
|
|
297 {
|
|
298 PAINTSTRUCT paintStruct;
|
|
299
|
|
300 EnterCriticalSection (&mswindows_dispatch_crit);
|
|
301 emacs_event = Fmake_event (Qnil, Qnil);
|
|
302 event = XEVENT(emacs_event);
|
|
303
|
|
304 event->channel = mswindows_find_frame(hwnd);
|
|
305 event->timestamp = msg.time;
|
|
306 event->event_type = magic_event;
|
|
307 BeginPaint (hwnd, &paintStruct);
|
|
308 EVENT_MSWINDOWS_MAGIC_TYPE(event) = message;
|
|
309 EVENT_MSWINDOWS_MAGIC_DATA(event) = paintStruct.rcPaint;
|
|
310 EndPaint (hwnd, &paintStruct);
|
|
311
|
|
312 mswindows_enqueue_dispatch_event (emacs_event);
|
|
313 LeaveCriticalSection (&mswindows_dispatch_crit);
|
|
314 }
|
|
315 break;
|
|
316
|
|
317 case WM_SIZE:
|
|
318 /* We only care about this message if our size has really changed */
|
|
319 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
|
|
320 {
|
|
321 RECT rect;
|
|
322 EnterCriticalSection (&mswindows_dispatch_crit);
|
|
323 emacs_event = Fmake_event (Qnil, Qnil);
|
|
324 event = XEVENT(emacs_event);
|
|
325
|
|
326 event->channel = mswindows_find_frame(hwnd);
|
|
327 event->timestamp = msg.time;
|
|
328 event->event_type = magic_event;
|
|
329 if (wParam==SIZE_MINIMIZED)
|
|
330 rect.left = rect.top = rect.right = rect.bottom = -1;
|
|
331 else
|
|
332 GetClientRect(hwnd, &rect);
|
|
333 EVENT_MSWINDOWS_MAGIC_TYPE(event) = message;
|
|
334 EVENT_MSWINDOWS_MAGIC_DATA(event) = rect;
|
|
335
|
|
336 mswindows_enqueue_dispatch_event (emacs_event);
|
|
337 LeaveCriticalSection (&mswindows_dispatch_crit);
|
|
338 }
|
|
339 break;
|
|
340
|
|
341 case WM_SETFOCUS:
|
|
342 case WM_KILLFOCUS:
|
|
343 {
|
|
344 EnterCriticalSection (&mswindows_dispatch_crit);
|
|
345 emacs_event = Fmake_event (Qnil, Qnil);
|
|
346 event = XEVENT(emacs_event);
|
|
347
|
|
348 event->channel = mswindows_find_frame(hwnd);
|
|
349 event->timestamp = msg.time;
|
|
350 event->event_type = magic_event;
|
|
351 EVENT_MSWINDOWS_MAGIC_TYPE(event) = message;
|
|
352
|
|
353 mswindows_enqueue_dispatch_event (emacs_event);
|
|
354 LeaveCriticalSection (&mswindows_dispatch_crit);
|
|
355 }
|
|
356 break;
|
|
357
|
|
358 case WM_QUIT:
|
|
359 /* XXX FIXME: Should do something here! */
|
|
360 defproc:
|
|
361 default:
|
|
362 return DefWindowProc (hwnd, message, wParam, lParam);
|
|
363 }
|
|
364 return (0);
|
|
365 }
|
|
366
|
|
367
|
|
368 /*
|
|
369 * Make a request to the message-processing thread to do things that
|
|
370 * can't be done in the main thread.
|
|
371 */
|
|
372 LPARAM
|
|
373 mswindows_make_request(UINT message, WPARAM wParam, mswindows_request_type *request)
|
|
374 {
|
|
375 MSG msg;
|
|
376 assert(PostThreadMessage (mswindows_win_thread_id, message, wParam,
|
|
377 (LPARAM) request));
|
|
378 GetMessage (&msg, NULL, WM_XEMACS_ACK, WM_XEMACS_ACK);
|
|
379 return (msg.lParam);
|
|
380 }
|
|
381
|
|
382
|
|
383 /*
|
|
384 * Handle a request from the main thread to do things that have to be
|
|
385 * done in the message-processing thread.
|
|
386 */
|
|
387 static void
|
|
388 mswindows_handle_request (MSG *msg)
|
|
389 {
|
|
390 mswindows_request_type *request = (mswindows_request_type *) msg->lParam;
|
|
391
|
|
392 switch (msg->message)
|
|
393 {
|
|
394 case WM_XEMACS_CREATEWINDOW:
|
|
395 {
|
|
396 struct frame *f = request->thing1;
|
|
397 Lisp_Object *props = request->thing2;
|
|
398 Lisp_Object name, height, width, popup, top, left;
|
|
399 RECT rect;
|
|
400 DWORD style;
|
|
401 HWND hwnd;
|
|
402
|
|
403 name = Fplist_get (*props, Qname, Qnil);
|
|
404 height = Fplist_get (*props, Qheight, Qnil);
|
|
405 width = Fplist_get (*props, Qwidth, Qnil);
|
|
406 popup = Fplist_get (*props, Qpopup, Qnil);
|
|
407 top = Fplist_get (*props, Qtop, Qnil);
|
|
408 left = Fplist_get (*props, Qleft, Qnil);
|
|
409
|
|
410 style = (NILP(popup)) ? MSWINDOWS_FRAME_STYLE : MSWINDOWS_POPUP_STYLE;
|
|
411
|
|
412 rect.left = rect.top = 0;
|
|
413 rect.right = INTP(width) ? XINT(width) : 640;
|
|
414 rect.bottom = INTP(height) ? XINT(height) : 480;
|
|
415 #ifdef HAVE_MENUBARS
|
|
416 AdjustWindowRect(&rect, style, TRUE);
|
|
417 #else
|
|
418 AdjustWindowRect(&rect, style, FALSE);
|
|
419 #endif
|
|
420
|
|
421 hwnd = CreateWindow (XEMACS_CLASS,
|
|
422 STRINGP(f->name) ? XSTRING_DATA(f->name) :
|
|
423 (STRINGP(name) ? XSTRING_DATA(name) : XEMACS_CLASS),
|
|
424 style,
|
|
425 INTP(left) ? XINT(left) : CW_USEDEFAULT,
|
|
426 INTP(top) ? XINT(top) : CW_USEDEFAULT,
|
|
427 rect.right-rect.left, rect.bottom-rect.top,
|
|
428 NULL, NULL, NULL, NULL);
|
|
429 assert(PostThreadMessage (mswindows_main_thread_id, WM_XEMACS_ACK, 0, (LPARAM) hwnd));
|
|
430 }
|
|
431 return;
|
|
432
|
|
433 case WM_XEMACS_SETTIMER:
|
|
434 {
|
|
435 UINT id;
|
|
436 id=SetTimer (NULL, 0, (UINT) request->thing1, NULL);
|
|
437 assert(PostThreadMessage (mswindows_main_thread_id, WM_XEMACS_ACK, 0, id));
|
|
438 }
|
|
439 break;
|
|
440
|
|
441 case WM_XEMACS_KILLTIMER:
|
|
442 {
|
|
443 KillTimer (NULL, (UINT) request->thing1);
|
|
444 assert(PostThreadMessage (mswindows_main_thread_id, WM_XEMACS_ACK, 0, 0));
|
|
445 }
|
|
446 break;
|
|
447
|
|
448 default:
|
|
449 assert(0);
|
|
450 }
|
|
451 }
|
|
452
|
|
453
|
|
454 /*
|
|
455 * Translate a mswindows virtual key to a keysym.
|
|
456 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
|
|
457 * or whose ASCII codes (like space) xemacs doesn't like.
|
|
458 * Virtual key values are defined in winresrc.h
|
|
459 * XXX I'm not sure that KEYSYM("name") is the best thing to use here.
|
|
460 */
|
|
461 Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key)
|
|
462 {
|
|
463 switch (mswindows_key)
|
|
464 {
|
|
465 /* First the predefined ones */
|
|
466 case VK_BACK: return QKbackspace;
|
|
467 case VK_TAB: return QKtab;
|
|
468 case '\n': return QKlinefeed; /* No VK_LINEFEED in winresrc.h */
|
|
469 case VK_RETURN: return QKreturn;
|
|
470 case VK_ESCAPE: return QKescape;
|
|
471 case VK_SPACE: return QKspace;
|
|
472 case VK_DELETE: return QKdelete;
|
|
473
|
|
474 /* The rest */
|
|
475 case VK_PRIOR: return KEYSYM ("prior");
|
|
476 case VK_NEXT: return KEYSYM ("next");
|
|
477 case VK_END: return KEYSYM ("end");
|
|
478 case VK_HOME: return KEYSYM ("home");
|
|
479 case VK_LEFT: return KEYSYM ("left");
|
|
480 case VK_UP: return KEYSYM ("up");
|
|
481 case VK_RIGHT: return KEYSYM ("right");
|
|
482 case VK_DOWN: return KEYSYM ("down");
|
|
483 case VK_INSERT: return KEYSYM ("insert");
|
|
484 case VK_HELP: return KEYSYM ("help");
|
|
485 case VK_F1: return KEYSYM ("F1");
|
|
486 case VK_F2: return KEYSYM ("F2");
|
|
487 case VK_F3: return KEYSYM ("F3");
|
|
488 case VK_F4: return KEYSYM ("F4");
|
|
489 case VK_F5: return KEYSYM ("F5");
|
|
490 case VK_F6: return KEYSYM ("F6");
|
|
491 case VK_F7: return KEYSYM ("F7");
|
|
492 case VK_F8: return KEYSYM ("F8");
|
|
493 case VK_F9: return KEYSYM ("F9");
|
|
494 case VK_F10: return KEYSYM ("F10");
|
|
495 case VK_F11: return KEYSYM ("F11");
|
|
496 case VK_F12: return KEYSYM ("F12");
|
|
497 case VK_F13: return KEYSYM ("F13");
|
|
498 case VK_F14: return KEYSYM ("F14");
|
|
499 case VK_F15: return KEYSYM ("F15");
|
|
500 case VK_F16: return KEYSYM ("F16");
|
|
501 case VK_F17: return KEYSYM ("F17");
|
|
502 case VK_F18: return KEYSYM ("F18");
|
|
503 case VK_F19: return KEYSYM ("F19");
|
|
504 case VK_F20: return KEYSYM ("F20");
|
|
505 case VK_F21: return KEYSYM ("F21");
|
|
506 case VK_F22: return KEYSYM ("F22");
|
|
507 case VK_F23: return KEYSYM ("F23");
|
|
508 case VK_F24: return KEYSYM ("F24");
|
|
509 }
|
|
510 return Qnil;
|
|
511 }
|
|
512
|
|
513
|
|
514 /*
|
|
515 * Find the console that matches the supplied mswindows window handle
|
|
516 */
|
|
517 static Lisp_Object
|
|
518 mswindows_find_console (HWND hwnd)
|
|
519 {
|
|
520 Lisp_Object concons;
|
|
521
|
|
522 CONSOLE_LOOP (concons)
|
|
523 {
|
|
524 Lisp_Object console = XCAR (concons);
|
|
525 /* We only support one console so this must be it */
|
|
526 return console;
|
|
527 }
|
|
528
|
|
529 return Qnil;
|
|
530 }
|
|
531
|
|
532 /*
|
|
533 * Find the frame that matches the supplied mswindows window handle
|
|
534 */
|
|
535 static Lisp_Object
|
|
536 mswindows_find_frame (HWND hwnd)
|
|
537 {
|
|
538 Lisp_Object frmcons, devcons, concons;
|
|
539
|
|
540 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
|
|
541 {
|
|
542 struct frame *f;
|
|
543 Lisp_Object frame = XCAR (frmcons);
|
|
544 f = XFRAME (frame);
|
|
545 if (FRAME_TYPE_P(f, mswindows)) /* Might be a stream-type frame */
|
|
546 if (FRAME_MSWINDOWS_HANDLE(f)==hwnd)
|
|
547 return frame;
|
|
548 }
|
|
549 assert(0); /* XXX Can't happen! we only get messages for our windows */
|
|
550 return Qnil;
|
|
551 }
|
|
552
|
|
553 /*
|
|
554 * Random helper functions for debugging.
|
|
555 * Intended for use in the MSVC "Watch" window which doesn't like
|
|
556 * the aborts that the error_check_foo() functions can make.
|
|
557 */
|
|
558 struct lrecord_header *DHEADER(Lisp_Object obj)
|
|
559 {
|
|
560 return LRECORDP(obj) ? XRECORD_LHEADER(obj) : NULL;
|
|
561 /* (lrecord_header*)(obj & 0xfffffff) */
|
|
562 }
|
|
563
|
|
564 struct Lisp_Event *DEVENT(Lisp_Object obj)
|
|
565 {
|
|
566 return (EVENTP (obj)) ? XEVENT(obj) : NULL;
|
|
567 }
|
|
568
|
|
569 struct Lisp_Cons *DCONS(Lisp_Object obj)
|
|
570 {
|
|
571 return (CONSP (obj)) ? XCONS(obj) : NULL;
|
|
572 }
|
|
573
|
|
574 Lisp_Object DCAR(Lisp_Object obj)
|
|
575 {
|
|
576 return (CONSP (obj)) ? XCAR(obj) : 0;
|
|
577 }
|
|
578
|
|
579 Lisp_Object DCDR(Lisp_Object obj)
|
|
580 {
|
|
581 return (CONSP (obj)) ? XCDR(obj) : 0;
|
|
582 }
|
|
583
|
|
584 char *DSTRING(Lisp_Object obj)
|
|
585 {
|
|
586 return (STRINGP (obj)) ? XSTRING_DATA(obj) : NULL;
|
|
587 }
|
|
588
|
|
589 struct Lisp_Vector *DVECTOR(Lisp_Object obj)
|
|
590 {
|
|
591 return (VECTORP (obj)) ? XVECTOR(obj) : NULL;
|
|
592 }
|
|
593
|
|
594 struct Lisp_Symbol *DSYMBOL(Lisp_Object obj)
|
|
595 {
|
|
596 return (SYMBOLP (obj)) ? XSYMBOL(obj) : NULL;
|
|
597 }
|
|
598
|
|
599 char *DSYMNAME(Lisp_Object obj)
|
|
600 {
|
|
601 return (SYMBOLP (obj)) ? XSYMBOL(obj)->name->_data : NULL;
|
|
602 }
|