Mercurial > hg > xemacs-beta
comparison src/event-msw.c @ 249:83b3d10dcba9 r20-5b23
Import from CVS: tag r20-5b23
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:19:09 +0200 |
parents | 51092a27c943 |
children | 677f6a0ee643 |
comparison
equal
deleted
inserted
replaced
248:ad40ac2754d8 | 249:83b3d10dcba9 |
---|---|
31 */ | 31 */ |
32 | 32 |
33 #include <config.h> | 33 #include <config.h> |
34 #include "lisp.h" | 34 #include "lisp.h" |
35 | 35 |
36 #include "console-msw.h" | |
37 | |
38 #ifdef HAVE_SCROLLBARS | |
39 # include "scrollbar-msw.h" | |
40 #endif | |
41 | |
42 #ifdef HAVE_MENUBARS | |
43 # include "menubar-msw.h" | |
44 #endif | |
45 | |
36 #include "device.h" | 46 #include "device.h" |
37 #include "console-msw.h" | |
38 #include "emacsfns.h" | 47 #include "emacsfns.h" |
39 #include "events.h" | 48 #include "events.h" |
40 #include "frame.h" | 49 #include "frame.h" |
41 #include "process.h" | 50 #include "process.h" |
42 #include "redisplay.h" | 51 #include "redisplay.h" |
43 #include "sysproc.h" | 52 #include "sysproc.h" |
44 #include "syswait.h" | 53 #include "syswait.h" |
45 #include "systime.h" | 54 #include "systime.h" |
46 | 55 |
47 #include "event-msw.h" | 56 #include "events-mod.h" |
57 | |
58 #ifdef HAVE_MENUBARS | |
59 #define ADJR_MENUFLAG TRUE | |
60 #else | |
61 #define ADJR_MENUFLAG FALSE | |
62 #endif | |
63 | |
64 /* Fake key modifier which is attached to a quit char event. | |
65 Removed upon dequeueing an event */ | |
66 #define FAKE_MOD_QUIT 0x80 | |
67 | |
68 /* Timer ID used for button2 emulation */ | |
69 #define BUTTON_2_TIMER_ID 1 | |
70 | |
71 /* Drag and drop event data types (subset of types in offix-types.h) */ | |
72 #define DndFile 2 | |
73 #define DndFiles 3 | |
74 #define DndText 4 | |
75 | |
76 | |
77 static Lisp_Object mswindows_find_frame (HWND hwnd); | |
78 static Lisp_Object mswindows_find_console (HWND hwnd); | |
79 static Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods); | |
80 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr); | |
81 static void mswindows_set_chord_timer (HWND hwnd); | |
82 static int mswindows_button2_near_enough (POINTS p1, POINTS p2); | |
83 static int mswindows_current_layout_has_AltGr (void); | |
84 | |
48 | 85 |
49 static struct event_stream *mswindows_event_stream; | 86 static struct event_stream *mswindows_event_stream; |
50 | 87 |
51 /* | 88 /* |
52 * Two separate queues, for efficiency, one (_u_) for user events, and | 89 * Two separate queues, for efficiency, one (_u_) for user events, and |
55 * one. | 92 * one. |
56 */ | 93 */ |
57 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail; | 94 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail; |
58 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail; | 95 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail; |
59 | 96 |
60 /* | 97 /* The number of things we can wait on */ |
61 * List of mswindows waitable handles. | 98 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1) |
62 * Apart from the dispatch queue semaphore, all of these handles may be waited | 99 |
63 * on multiple times in emacs_mswindows_next_event before being processed and so | 100 /* List of mswindows waitable handles. */ |
64 * must be manual-reset events. | |
65 */ | |
66 static HANDLE mswindows_waitable[MAX_WAITABLE]; | 101 static HANDLE mswindows_waitable[MAX_WAITABLE]; |
67 | 102 |
68 /* random emacs info associated with each of the wait handles */ | |
69 static mswindows_waitable_info_type mswindows_waitable_info[MAX_WAITABLE]; | |
70 | |
71 /* Count of quit chars currently in the queue */ | 103 /* Count of quit chars currently in the queue */ |
72 /* Incremented in WM_CHAR handler in msw-proc.c | 104 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc() |
73 Decremented in mswindows_dequeue_dispatch_event() */ | 105 Decremented in mswindows_dequeue_dispatch_event() */ |
74 int mswindows_quit_chars_count = 0; | 106 int mswindows_quit_chars_count = 0; |
75 | 107 |
76 /* These are Lisp integers; see DEFVARS in this file for description. */ | 108 /* These are Lisp integers; see DEFVARS in this file for description. */ |
77 int mswindows_dynamic_frame_resize; | 109 int mswindows_dynamic_frame_resize; |
94 static int | 126 static int |
95 mswindows_user_event_p (struct Lisp_Event* sevt) | 127 mswindows_user_event_p (struct Lisp_Event* sevt) |
96 { | 128 { |
97 return (sevt->event_type == key_press_event | 129 return (sevt->event_type == key_press_event |
98 || sevt->event_type == button_press_event | 130 || sevt->event_type == button_press_event |
99 || sevt->event_type == button_release_event); | 131 || sevt->event_type == button_release_event |
100 } | 132 || sevt->event_type == dnd_drop_event); |
101 | 133 } |
102 /* | 134 |
135 /************************************************************************/ | |
136 /* Dispatch queue management */ | |
137 /************************************************************************/ | |
138 | |
139 /* | |
103 * Add an emacs event to the proper dispatch queue | 140 * Add an emacs event to the proper dispatch queue |
104 */ | 141 */ |
105 void | 142 void |
106 mswindows_enqueue_dispatch_event (Lisp_Object event) | 143 mswindows_enqueue_dispatch_event (Lisp_Object event) |
107 { | 144 { |
113 &mswindows_s_dispatch_event_queue_tail); | 150 &mswindows_s_dispatch_event_queue_tail); |
114 | 151 |
115 /* This one does not go to window procedure, hence does not | 152 /* This one does not go to window procedure, hence does not |
116 generate XM_BUMPQUEUE magic event! */ | 153 generate XM_BUMPQUEUE magic event! */ |
117 PostMessage (NULL, XM_BUMPQUEUE, 0, 0); | 154 PostMessage (NULL, XM_BUMPQUEUE, 0, 0); |
155 } | |
156 | |
157 void | |
158 mswindows_enqueue_magic_event (HWND hwnd, UINT message) | |
159 { | |
160 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
161 struct Lisp_Event* event = XEVENT (emacs_event); | |
162 | |
163 event->channel = mswindows_find_frame (hwnd); | |
164 event->timestamp = GetMessageTime(); | |
165 event->event_type = magic_event; | |
166 EVENT_MSWINDOWS_MAGIC_TYPE (event) = message; | |
167 | |
168 mswindows_enqueue_dispatch_event (emacs_event); | |
169 } | |
170 | |
171 static void | |
172 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWORD when) | |
173 { | |
174 | |
175 /* We always use last message time, because mouse button | |
176 events may get delayed, and XEmacs double click | |
177 recognition will fail */ | |
178 | |
179 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
180 struct Lisp_Event* event = XEVENT(emacs_event); | |
181 | |
182 event->channel = mswindows_find_frame(hwnd); | |
183 event->timestamp = when; | |
184 event->event.button.button = | |
185 (message==WM_LBUTTONDOWN || message==WM_LBUTTONUP) ? 1 : | |
186 ((message==WM_RBUTTONDOWN || message==WM_RBUTTONUP) ? 3 : 2); | |
187 event->event.button.x = where.x; | |
188 event->event.button.y = where.y; | |
189 event->event.button.modifiers = mswindows_modifier_state (NULL, 0); | |
190 | |
191 if (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN || | |
192 message==WM_RBUTTONDOWN) | |
193 { | |
194 event->event_type = button_press_event; | |
195 SetCapture (hwnd); | |
196 } | |
197 else | |
198 { | |
199 event->event_type = button_release_event; | |
200 ReleaseCapture (); | |
201 } | |
202 | |
203 mswindows_enqueue_dispatch_event (emacs_event); | |
204 } | |
205 | |
206 static void | |
207 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods) | |
208 { | |
209 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
210 struct Lisp_Event* event = XEVENT(emacs_event); | |
211 | |
212 event->channel = mswindows_find_console(hwnd); | |
213 event->timestamp = GetMessageTime(); | |
214 event->event_type = key_press_event; | |
215 event->event.key.keysym = keysym; | |
216 event->event.key.modifiers = mods; | |
217 mswindows_enqueue_dispatch_event (emacs_event); | |
118 } | 218 } |
119 | 219 |
120 /* | 220 /* |
121 * Remove and return the first emacs event on the dispatch queue. | 221 * Remove and return the first emacs event on the dispatch queue. |
122 * Give a preference to user events over non-user ones. | 222 * Give a preference to user events over non-user ones. |
201 } | 301 } |
202 previous_event = event; | 302 previous_event = event; |
203 } | 303 } |
204 return Qnil; | 304 return Qnil; |
205 } | 305 } |
306 | |
307 | |
308 /************************************************************************/ | |
309 /* Event pump */ | |
310 /************************************************************************/ | |
206 | 311 |
207 static Lisp_Object | 312 static Lisp_Object |
208 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data, | 313 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data, |
209 Lisp_Object u_n_u_s_e_d) | 314 Lisp_Object u_n_u_s_e_d) |
210 { | 315 { |
310 mswindows_pump_outstanding_events (void) | 415 mswindows_pump_outstanding_events (void) |
311 { | 416 { |
312 /* This function can call lisp */ | 417 /* This function can call lisp */ |
313 | 418 |
314 Lisp_Object result = Qt; | 419 Lisp_Object result = Qt; |
315 | 420 struct gcpro gcpro1; |
421 GCPRO1 (result); | |
422 | |
316 if (NILP(mswindows_error_caught_in_modal_loop)) | 423 if (NILP(mswindows_error_caught_in_modal_loop)) |
317 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil); | 424 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil); |
425 UNGCPRO; | |
318 return result; | 426 return result; |
319 } | 427 } |
320 | 428 |
321 /* | 429 |
322 * Find a free waitable slot | |
323 */ | |
324 #if 0 /* NOTUSED */ | |
325 static int | |
326 mswindows_find_free_waitable(void) | |
327 { | |
328 int i; | |
329 for (i=0; i<mswindows_waitable_count; i++) | |
330 if (mswindows_waitable_info[i].type == mswindows_waitable_type_none) | |
331 return i; | |
332 assert (mswindows_waitable_count < MAX_WAITABLE); | |
333 return mswindows_waitable_count++; | |
334 } | |
335 #endif | |
336 | |
337 /* | |
338 * Create a new waitable using the type and data passed in by the info structure | |
339 * Returns a pointer to the info associated with the assigned waitable object | |
340 */ | |
341 mswindows_waitable_info_type * | |
342 mswindows_add_waitable(mswindows_waitable_info_type *info) | |
343 { | |
344 int waitable; | |
345 | |
346 switch (info->type) | |
347 { | |
348 case mswindows_waitable_type_dispatch: | |
349 assert (0); /* kkm - should not get here */ | |
350 /* Can only have one waitable for the dispatch queue, and it's the first one */ | |
351 assert (mswindows_waitable_count++ == 0); | |
352 waitable=0; | |
353 #if 0 | |
354 InitializeCriticalSection(&mswindows_dispatch_crit); | |
355 #endif | |
356 assert (mswindows_waitable[0] = CreateSemaphore (NULL, 0, 0x7fffffff, NULL)); | |
357 return mswindows_waitable_info+0; | |
358 | |
359 default: | |
360 assert(0); | |
361 } | |
362 mswindows_waitable_info[waitable].type = info->type; | |
363 return mswindows_waitable_info+waitable; | |
364 } | |
365 | |
366 /* | |
367 * Remove a waitable using the type and data passed in by the info structure. | |
368 */ | |
369 void | |
370 mswindows_remove_waitable(mswindows_waitable_info_type *info) | |
371 { | |
372 int waitable; | |
373 | |
374 switch (info->type) | |
375 { | |
376 | |
377 default: | |
378 assert(0); | |
379 } | |
380 | |
381 CloseHandle(mswindows_waitable[waitable]); | |
382 mswindows_waitable[waitable] = 0; | |
383 mswindows_waitable_info[waitable].type = mswindows_waitable_type_none; | |
384 if (waitable == mswindows_waitable_count-1) | |
385 --mswindows_waitable_count; | |
386 } | |
387 | |
388 /* | |
389 * Callback procedure for synchronous timer messages | |
390 */ | |
391 static void CALLBACK | |
392 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime) | |
393 { | |
394 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
395 struct Lisp_Event *event = XEVENT (emacs_event); | |
396 | |
397 if (KillTimer (NULL, id_timer)) | |
398 --mswindows_pending_timers_count; | |
399 | |
400 event->channel = Qnil; | |
401 event->timestamp = dwtime; | |
402 event->event_type = timeout_event; | |
403 event->event.timeout.interval_id = id_timer; | |
404 | |
405 mswindows_enqueue_dispatch_event (emacs_event); | |
406 } | |
407 | 430 |
408 static void | 431 static void |
409 mswindows_drain_windows_queue () | 432 mswindows_drain_windows_queue () |
410 { | 433 { |
411 MSG msg; | 434 MSG msg; |
521 } | 544 } |
522 else | 545 else |
523 { | 546 { |
524 /* XXX FIXME: We should do some kind of round-robin scheme to ensure fairness */ | 547 /* XXX FIXME: We should do some kind of round-robin scheme to ensure fairness */ |
525 int waitable = active - WAIT_OBJECT_0; | 548 int waitable = active - WAIT_OBJECT_0; |
526 mswindows_waitable_info_type *info = mswindows_waitable_info + waitable; | 549 assert(0); /* #### */ |
527 | 550 } |
528 switch (info->type) | 551 } /* while */ |
552 | |
553 return; | |
554 } | |
555 | |
556 /************************************************************************/ | |
557 /* Event generators */ | |
558 /************************************************************************/ | |
559 | |
560 /* | |
561 * Callback procedure for synchronous timer messages | |
562 */ | |
563 static void CALLBACK | |
564 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime) | |
565 { | |
566 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
567 struct Lisp_Event *event = XEVENT (emacs_event); | |
568 | |
569 if (KillTimer (NULL, id_timer)) | |
570 --mswindows_pending_timers_count; | |
571 | |
572 event->channel = Qnil; | |
573 event->timestamp = dwtime; | |
574 event->event_type = timeout_event; | |
575 event->event.timeout.interval_id = id_timer; | |
576 | |
577 mswindows_enqueue_dispatch_event (emacs_event); | |
578 } | |
579 | |
580 /* | |
581 * Callback procedure for dde messages | |
582 */ | |
583 HDDEDATA CALLBACK | |
584 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv, | |
585 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata, | |
586 DWORD dwData1, DWORD dwData2) | |
587 { | |
588 switch (uType) | |
589 { | |
590 case XTYP_CONNECT: | |
591 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)) | |
592 return (HDDEDATA)TRUE; | |
593 return (HDDEDATA)FALSE; | |
594 | |
595 case XTYP_WILDCONNECT: | |
596 { | |
597 /* We only support one {service,topic} pair */ | |
598 HSZPAIR pairs[2] = { | |
599 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } }; | |
600 | |
601 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) && | |
602 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))); | |
603 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs, | |
604 sizeof (pairs), 0L, 0, uFmt, 0)); | |
605 } | |
606 return (HDDEDATA)NULL; | |
607 | |
608 case XTYP_EXECUTE: | |
609 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)) | |
610 { | |
611 DWORD len = DdeGetData (hdata, NULL, 0, 0); | |
612 char *cmd = alloca (len+1); | |
613 char *end; | |
614 Lisp_Object l_dndlist; | |
615 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
616 struct Lisp_Event *event = XEVENT (emacs_event); | |
617 | |
618 DdeGetData (hdata, cmd, len, 0); | |
619 cmd[len] = '\0'; | |
620 DdeFreeDataHandle (hdata); | |
621 | |
622 /* Check syntax & that it's an [Open("foo")] command */ | |
623 /* #### Ought to be generalised and accept some other commands */ | |
624 if (*cmd == '[') | |
625 cmd++; | |
626 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN, | |
627 strlen (MSWINDOWS_DDE_ITEM_OPEN))) | |
628 return DDE_FNOTPROCESSED; | |
629 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN); | |
630 while (*cmd==' ') | |
631 cmd++; | |
632 if (*cmd!='(' || *(cmd+1)!='\"') | |
633 return DDE_FNOTPROCESSED; | |
634 end = (cmd+=2); | |
635 while (*end && *end!='\"') | |
636 end++; | |
637 if (!*end) | |
638 return DDE_FNOTPROCESSED; | |
639 *end = '\0'; | |
640 if (*(++end)!=')') | |
641 return DDE_FNOTPROCESSED; | |
642 if (*(++end)==']') | |
643 end++; | |
644 if (*end) | |
645 return DDE_FNOTPROCESSED; | |
646 | |
647 l_dndlist = make_ext_string (cmd, strlen(cmd), FORMAT_FILENAME); | |
648 | |
649 event->channel = Qnil; | |
650 event->timestamp = GetTickCount(); | |
651 event->event_type = dnd_drop_event; | |
652 event->event.dnd_drop.button = 0; | |
653 event->event.dnd_drop.modifiers = 0; | |
654 event->event.dnd_drop.x = -1; | |
655 event->event.dnd_drop.y = -1; | |
656 event->event.dnd_drop.data = Fcons (make_int (DndFile), | |
657 Fcons (l_dndlist, Qnil)); | |
658 mswindows_enqueue_dispatch_event (emacs_event); | |
659 | |
660 return (HDDEDATA) DDE_FACK; | |
661 } | |
662 DdeFreeDataHandle (hdata); | |
663 return (HDDEDATA) DDE_FNOTPROCESSED; | |
664 | |
665 default: | |
666 return (HDDEDATA) NULL; | |
667 } | |
668 | |
669 } | |
670 | |
671 /* | |
672 * The windows procedure for the window class XEMACS_CLASS | |
673 */ | |
674 LRESULT WINAPI | |
675 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | |
676 { | |
677 /* Note: Remember to initialise emacs_event and event before use. | |
678 This code calls code that can GC. You must GCPRO before calling such code. */ | |
679 Lisp_Object emacs_event = Qnil; | |
680 Lisp_Object fobj = Qnil; | |
681 | |
682 struct Lisp_Event *event; | |
683 struct frame *frame; | |
684 struct mswindows_frame* msframe; | |
685 | |
686 switch (message) | |
687 { | |
688 case WM_ERASEBKGND: | |
689 /* Erase background only during non-dynamic sizing */ | |
690 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
691 if (msframe->sizing && !mswindows_dynamic_frame_resize) | |
692 goto defproc; | |
693 return 1; | |
694 | |
695 case WM_CLOSE: | |
696 fobj = mswindows_find_frame (hwnd); | |
697 enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt)); | |
698 mswindows_enqueue_magic_event (hwnd, XM_BUMPQUEUE); | |
699 break; | |
700 | |
701 case WM_KEYDOWN: | |
702 case WM_SYSKEYDOWN: | |
703 { | |
704 BYTE keymap[256]; | |
705 int has_AltGr = mswindows_current_layout_has_AltGr (); | |
706 int mods; | |
707 Lisp_Object keysym; | |
708 | |
709 GetKeyboardState (keymap); | |
710 mods = mswindows_modifier_state (keymap, has_AltGr); | |
711 | |
712 /* Handle those keys that TranslateMessage won't generate a WM_CHAR for */ | |
713 if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods))) | |
714 mswindows_enqueue_keypress_event (hwnd, keysym, mods); | |
715 else | |
716 { | |
717 int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd))); | |
718 BYTE keymap_orig[256]; | |
719 MSG msg = { hwnd, message, wParam, lParam, GetMessageTime(), (GetMessagePos()) }; | |
720 memcpy (keymap_orig, keymap, 256); | |
721 | |
722 /* Clear control and alt modifiers out of the keymap */ | |
723 keymap [VK_RCONTROL] = 0; | |
724 keymap [VK_LMENU] = 0; | |
725 if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) || !(keymap [VK_RMENU] & 0x80)) | |
726 { | |
727 keymap [VK_LCONTROL] = 0; | |
728 keymap [VK_CONTROL] = 0; | |
729 keymap [VK_RMENU] = 0; | |
730 keymap [VK_MENU] = 0; | |
731 } | |
732 SetKeyboardState (keymap); | |
733 | |
734 /* Have some WM_[SYS]CHARS in the queue */ | |
735 TranslateMessage (&msg); | |
736 | |
737 while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE) | |
738 ||PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE)) | |
739 { | |
740 int ch = msg.wParam; | |
741 /* CH is a character code for the key: | |
742 'C' for Shift+C and Ctrl+Shift+C | |
743 'c' for c and Ctrl+c */ | |
744 | |
745 /* #### If locale is not C, US or other latin-1, | |
746 isalpha() maybe not what do we mean */ | |
747 | |
748 /* XEmacs doesn't seem to like Shift on non-alpha keys */ | |
749 if (!isalpha(ch)) | |
750 mods &= ~MOD_SHIFT; | |
751 | |
752 /* Un-capitalise alpha control keys */ | |
753 if ((mods & MOD_CONTROL) && isalpha(ch)) | |
754 ch |= ('A' ^ 'a'); | |
755 | |
756 /* If a quit char with no modifiers other than control and | |
757 shift, then mark it with a fake modifier, which is removed | |
758 upon dequeueing the event */ | |
759 /* #### This might also not withstand localization, if | |
760 quit character is not a latin-1 symbol */ | |
761 if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch) | |
762 || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch)) | |
763 && ((mods & ~(MOD_CONTROL | MOD_SHIFT)) == 0)) | |
764 { | |
765 mods |= FAKE_MOD_QUIT; | |
766 ++mswindows_quit_chars_count; | |
767 } | |
768 | |
769 mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods); | |
770 } /* while */ | |
771 SetKeyboardState (keymap_orig); | |
772 } /* else */ | |
773 } | |
774 goto defproc; | |
775 | |
776 case WM_MBUTTONDOWN: | |
777 case WM_MBUTTONUP: | |
778 /* Real middle mouse button has nothing to do with emulated one: | |
779 if one wants to exercise fingers playing chords on the mouse, | |
780 he is allowed to do that! */ | |
781 mswindows_enqueue_mouse_button_event (hwnd, message, | |
782 MAKEPOINTS (lParam), GetMessageTime()); | |
783 break; | |
784 | |
785 case WM_LBUTTONUP: | |
786 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
787 msframe->last_click_time = GetMessageTime(); | |
788 | |
789 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
790 msframe->button2_need_lbutton = 0; | |
791 if (msframe->ignore_next_lbutton_up) | |
792 { | |
793 msframe->ignore_next_lbutton_up = 0; | |
794 } | |
795 else if (msframe->button2_is_down) | |
796 { | |
797 msframe->button2_is_down = 0; | |
798 msframe->ignore_next_rbutton_up = 1; | |
799 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, | |
800 MAKEPOINTS (lParam), GetMessageTime()); | |
801 } | |
802 else | |
803 { | |
804 if (msframe->button2_need_rbutton) | |
529 { | 805 { |
530 /* XXX FIXME: Should enque subprocess event here so that it is not lost */ | 806 msframe->button2_need_rbutton = 0; |
531 default: | 807 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, |
532 assert(0); | 808 MAKEPOINTS (lParam), GetMessageTime()); |
809 } | |
810 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP, | |
811 MAKEPOINTS (lParam), GetMessageTime()); | |
812 } | |
813 break; | |
814 | |
815 case WM_RBUTTONUP: | |
816 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
817 msframe->last_click_time = GetMessageTime(); | |
818 | |
819 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
820 msframe->button2_need_rbutton = 0; | |
821 if (msframe->ignore_next_rbutton_up) | |
822 { | |
823 msframe->ignore_next_rbutton_up = 0; | |
824 } | |
825 else if (msframe->button2_is_down) | |
826 { | |
827 msframe->button2_is_down = 0; | |
828 msframe->ignore_next_lbutton_up = 1; | |
829 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, | |
830 MAKEPOINTS (lParam), GetMessageTime()); | |
831 } | |
832 else | |
833 { | |
834 if (msframe->button2_need_lbutton) | |
835 { | |
836 msframe->button2_need_lbutton = 0; | |
837 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
838 MAKEPOINTS (lParam), GetMessageTime()); | |
839 } | |
840 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP, | |
841 MAKEPOINTS (lParam), GetMessageTime()); | |
842 } | |
843 break; | |
844 | |
845 case WM_LBUTTONDOWN: | |
846 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
847 | |
848 if (msframe->button2_need_lbutton) | |
849 { | |
850 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
851 msframe->button2_need_lbutton = 0; | |
852 msframe->button2_need_rbutton = 0; | |
853 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam))) | |
854 { | |
855 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, | |
856 MAKEPOINTS (lParam), GetMessageTime()); | |
857 msframe->button2_is_down = 1; | |
858 } | |
859 else | |
860 { | |
861 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
862 msframe->last_click_point, msframe->last_click_time); | |
863 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
864 MAKEPOINTS (lParam), GetMessageTime()); | |
533 } | 865 } |
534 } | 866 } |
535 } /* while */ | 867 else |
536 | 868 { |
537 return; | 869 mswindows_set_chord_timer (hwnd); |
538 } | 870 msframe->button2_need_rbutton = 1; |
871 msframe->last_click_point = MAKEPOINTS (lParam); | |
872 } | |
873 msframe->last_click_time = GetMessageTime(); | |
874 break; | |
875 | |
876 case WM_RBUTTONDOWN: | |
877 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
878 | |
879 if (msframe->button2_need_rbutton) | |
880 { | |
881 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
882 msframe->button2_need_lbutton = 0; | |
883 msframe->button2_need_rbutton = 0; | |
884 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam))) | |
885 { | |
886 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, | |
887 MAKEPOINTS (lParam), GetMessageTime()); | |
888 msframe->button2_is_down = 1; | |
889 } | |
890 else | |
891 { | |
892 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
893 msframe->last_click_point, msframe->last_click_time); | |
894 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
895 MAKEPOINTS (lParam), GetMessageTime()); | |
896 } | |
897 } | |
898 else | |
899 { | |
900 mswindows_set_chord_timer (hwnd); | |
901 msframe->button2_need_lbutton = 1; | |
902 msframe->last_click_point = MAKEPOINTS (lParam); | |
903 } | |
904 msframe->last_click_time = GetMessageTime(); | |
905 break; | |
906 | |
907 case WM_TIMER: | |
908 if (wParam == BUTTON_2_TIMER_ID) | |
909 { | |
910 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
911 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
912 | |
913 if (msframe->button2_need_lbutton) | |
914 { | |
915 msframe->button2_need_lbutton = 0; | |
916 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
917 msframe->last_click_point, msframe->last_click_time); | |
918 } | |
919 else if (msframe->button2_need_rbutton) | |
920 { | |
921 msframe->button2_need_rbutton = 0; | |
922 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
923 msframe->last_click_point, msframe->last_click_time); | |
924 } | |
925 } | |
926 else | |
927 assert ("Spurious timer fired" == 0); | |
928 break; | |
929 | |
930 case WM_MOUSEMOVE: | |
931 /* Optimization: don't report mouse movement while size is changind */ | |
932 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
933 if (!msframe->sizing) | |
934 { | |
935 /* When waiting for the second mouse button to finish | |
936 button2 emulation, and have moved too far, just pretend | |
937 as if timer has expired. This impoves drag-select feedback */ | |
938 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton) | |
939 && !mswindows_button2_near_enough (msframe->last_click_point, | |
940 MAKEPOINTS (lParam))) | |
941 { | |
942 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
943 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0); | |
944 } | |
945 | |
946 emacs_event = Fmake_event (Qnil, Qnil); | |
947 event = XEVENT(emacs_event); | |
948 | |
949 event->channel = mswindows_find_frame(hwnd); | |
950 event->timestamp = GetMessageTime(); | |
951 event->event_type = pointer_motion_event; | |
952 event->event.motion.x = MAKEPOINTS(lParam).x; | |
953 event->event.motion.y = MAKEPOINTS(lParam).y; | |
954 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0); | |
955 | |
956 mswindows_enqueue_dispatch_event (emacs_event); | |
957 } | |
958 break; | |
959 | |
960 case WM_PAINT: | |
961 { | |
962 PAINTSTRUCT paintStruct; | |
963 | |
964 frame = XFRAME (mswindows_find_frame (hwnd)); | |
965 | |
966 BeginPaint (hwnd, &paintStruct); | |
967 mswindows_redraw_exposed_area (frame, | |
968 paintStruct.rcPaint.left, paintStruct.rcPaint.top, | |
969 paintStruct.rcPaint.right, paintStruct.rcPaint.bottom); | |
970 EndPaint (hwnd, &paintStruct); | |
971 } | |
972 break; | |
973 | |
974 case WM_SIZE: | |
975 /* We only care about this message if our size has really changed */ | |
976 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED) | |
977 { | |
978 RECT rect; | |
979 int columns, rows; | |
980 | |
981 fobj = mswindows_find_frame (hwnd); | |
982 frame = XFRAME (fobj); | |
983 msframe = FRAME_MSWINDOWS_DATA (frame); | |
984 | |
985 /* We cannot handle frame map and unmap hooks right in | |
986 this routine, because these may throw. We queue | |
987 magic events to run these hooks instead - kkm */ | |
988 | |
989 if (wParam==SIZE_MINIMIZED) | |
990 { | |
991 /* Iconified */ | |
992 FRAME_VISIBLE_P (frame) = 0; | |
993 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME); | |
994 Fframe_iconified_p (fobj); | |
995 } | |
996 else | |
997 { | |
998 int was_visible = FRAME_VISIBLE_P (frame); | |
999 if (!msframe->sizing && !was_visible) | |
1000 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME); | |
1001 | |
1002 GetClientRect(hwnd, &rect); | |
1003 FRAME_VISIBLE_P(frame) = 1; | |
1004 FRAME_PIXWIDTH(frame) = rect.right; | |
1005 FRAME_PIXHEIGHT(frame) = rect.bottom; | |
1006 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows); | |
1007 change_frame_size (frame, rows, columns, 1); | |
1008 | |
1009 if (msframe->sizing && mswindows_dynamic_frame_resize) | |
1010 redisplay (); | |
1011 } | |
1012 } | |
1013 break; | |
1014 | |
1015 /* Misc magic events which only require that the frame be identified */ | |
1016 case WM_SETFOCUS: | |
1017 case WM_KILLFOCUS: | |
1018 mswindows_enqueue_magic_event (hwnd, message); | |
1019 break; | |
1020 | |
1021 case WM_WINDOWPOSCHANGING: | |
1022 { | |
1023 WINDOWPOS *wp = (LPWINDOWPOS) lParam; | |
1024 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) }; | |
1025 GetWindowPlacement(hwnd, &wpl); | |
1026 | |
1027 /* Only interested if size is changing and we're not being iconified */ | |
1028 if ((wpl.showCmd != SW_SHOWMINIMIZED) && !(wp->flags & SWP_NOSIZE)) | |
1029 { | |
1030 RECT ncsize = { 0, 0, 0, 0 }; | |
1031 int pixwidth, pixheight; | |
1032 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE), | |
1033 GetMenu(hwnd) != NULL, | |
1034 GetWindowLong (hwnd, GWL_EXSTYLE)); | |
1035 | |
1036 round_size_to_char (XFRAME (mswindows_find_frame (hwnd)), | |
1037 wp->cx - (ncsize.right - ncsize.left), | |
1038 wp->cy - (ncsize.bottom - ncsize.top), | |
1039 &pixwidth, &pixheight); | |
1040 | |
1041 /* Convert client sizes to window sizes */ | |
1042 pixwidth += (ncsize.right - ncsize.left); | |
1043 pixheight += (ncsize.bottom - ncsize.top); | |
1044 | |
1045 if (wpl.showCmd != SW_SHOWMAXIMIZED) | |
1046 { | |
1047 /* Adjust so that the bottom or right doesn't move if it's | |
1048 * the top or left that's being changed */ | |
1049 RECT rect; | |
1050 GetWindowRect (hwnd, &rect); | |
1051 | |
1052 if (rect.left != wp->x) | |
1053 wp->x += wp->cx - pixwidth; | |
1054 if (rect.top != wp->y) | |
1055 wp->y += wp->cy - pixheight; | |
1056 } | |
1057 | |
1058 wp->cx = pixwidth; | |
1059 wp->cy = pixheight; | |
1060 } | |
1061 } | |
1062 break; | |
1063 | |
1064 case WM_ENTERSIZEMOVE: | |
1065 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
1066 msframe->sizing = 1; | |
1067 return 0; | |
1068 | |
1069 case WM_EXITSIZEMOVE: | |
1070 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
1071 msframe->sizing = 0; | |
1072 /* Queue noop event */ | |
1073 mswindows_enqueue_magic_event (hwnd, XM_BUMPQUEUE); | |
1074 return 0; | |
1075 | |
1076 #ifdef HAVE_SCROLLBARS | |
1077 case WM_VSCROLL: | |
1078 case WM_HSCROLL: | |
1079 { | |
1080 /* Direction of scroll is determined by scrollbar instance. */ | |
1081 int code = (int) LOWORD(wParam); | |
1082 int pos = (short int) HIWORD(wParam); | |
1083 HWND hwndScrollBar = (HWND) lParam; | |
1084 struct gcpro gcpro1, gcpro2; | |
1085 | |
1086 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos); | |
1087 GCPRO2 (emacs_event, fobj); | |
1088 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */ | |
1089 { | |
1090 /* Error during event pumping - cancel scroll */ | |
1091 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0); | |
1092 } | |
1093 UNGCPRO; | |
1094 break; | |
1095 } | |
1096 #endif | |
1097 | |
1098 #ifdef HAVE_MENUBARS | |
1099 case WM_INITMENU: | |
1100 if (UNBOUNDP (mswindows_handle_wm_initmenu ( | |
1101 (HMENU) wParam, | |
1102 XFRAME (mswindows_find_frame (hwnd))))) | |
1103 SendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
1104 break; | |
1105 | |
1106 case WM_INITMENUPOPUP: | |
1107 if (!HIWORD(lParam)) | |
1108 { | |
1109 if (UNBOUNDP (mswindows_handle_wm_initmenupopup ( | |
1110 (HMENU) wParam, | |
1111 XFRAME (mswindows_find_frame (hwnd))))) | |
1112 SendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
1113 } | |
1114 break; | |
1115 | |
1116 case WM_EXITMENULOOP: | |
1117 if (UNBOUNDP (mswindows_handle_wm_exitmenuloop ( | |
1118 XFRAME (mswindows_find_frame (hwnd))))) | |
1119 SendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
1120 break; | |
1121 | |
1122 #endif /* HAVE_MENUBARS */ | |
1123 | |
1124 case WM_COMMAND: | |
1125 { | |
1126 WORD id = LOWORD (wParam); | |
1127 frame = XFRAME (mswindows_find_frame (hwnd)); | |
1128 | |
1129 #ifdef HAVE_MENUBARS | |
1130 if (!NILP (mswindows_handle_wm_command (frame, id))) | |
1131 break; | |
1132 #endif | |
1133 | |
1134 #ifdef HAVE_TOOLBARS | |
1135 O Toolbar Implementor, this place may have something for you!; | |
1136 #endif | |
1137 | |
1138 /* Bite me - a spurious command. No abort(), for safety */ | |
1139 /* #### Perhaps, this message should be changed */ | |
1140 error ("Cannot decode command. Tell kkm he's a parallelogramm, if you know" | |
1141 " what does that mean!"); | |
1142 } | |
1143 break; | |
1144 | |
1145 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */ | |
1146 { | |
1147 UINT filecount, i, len; | |
1148 POINT point; | |
1149 char filename[MAX_PATH]; | |
1150 Lisp_Object l_type, l_dndlist = Qnil, l_item; | |
1151 | |
1152 emacs_event = Fmake_event (Qnil, Qnil); | |
1153 event = XEVENT(emacs_event); | |
1154 | |
1155 if (!DragQueryPoint ((HANDLE) wParam, &point)) | |
1156 point.x = point.y = -1; /* outside client area */ | |
1157 | |
1158 filecount = DragQueryFile ((HANDLE) wParam, -1, NULL, 0); | |
1159 if (filecount == 1) | |
1160 { | |
1161 l_type = make_int (DndFile); | |
1162 len = DragQueryFile ((HANDLE) wParam, 0, filename, MAX_PATH); | |
1163 l_dndlist = make_ext_string (filename, len, FORMAT_FILENAME); | |
1164 } | |
1165 else | |
1166 { | |
1167 l_type = make_int (DndFiles); | |
1168 for (i=0; i<filecount; i++) | |
1169 { | |
1170 len = DragQueryFile ((HANDLE) wParam, i, filename, MAX_PATH); | |
1171 l_item = make_ext_string (filename, len, FORMAT_FILENAME); | |
1172 l_dndlist = Fcons (l_item, l_dndlist); /* reverse order */ | |
1173 } | |
1174 } | |
1175 DragFinish ((HANDLE) wParam); | |
1176 | |
1177 event->channel = mswindows_find_frame(hwnd); | |
1178 event->timestamp = GetMessageTime(); | |
1179 event->event_type = dnd_drop_event; | |
1180 event->event.dnd_drop.button = 1; /* #### Should try harder */ | |
1181 event->event.dnd_drop.modifiers = mswindows_modifier_state (NULL, 0); | |
1182 event->event.dnd_drop.x = point.x; | |
1183 event->event.dnd_drop.y = point.y; | |
1184 event->event.dnd_drop.data = Fcons (l_type, Fcons (l_dndlist, Qnil)); | |
1185 | |
1186 mswindows_enqueue_dispatch_event (emacs_event); | |
1187 } | |
1188 break; | |
1189 | |
1190 defproc: | |
1191 default: | |
1192 return DefWindowProc (hwnd, message, wParam, lParam); | |
1193 } | |
1194 return (0); | |
1195 } | |
1196 | |
1197 | |
1198 /************************************************************************/ | |
1199 /* keyboard, mouse & other helpers for the windows procedure */ | |
1200 /************************************************************************/ | |
1201 static void | |
1202 mswindows_set_chord_timer (HWND hwnd) | |
1203 { | |
1204 int interval; | |
1205 | |
1206 /* We get half system threshold as it seems to | |
1207 long before drag-selection is shown */ | |
1208 if (mswindows_button2_chord_time <= 0) | |
1209 interval = GetDoubleClickTime () / 2; | |
1210 else | |
1211 interval = mswindows_button2_chord_time; | |
1212 | |
1213 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0); | |
1214 } | |
1215 | |
1216 static int | |
1217 mswindows_button2_near_enough (POINTS p1, POINTS p2) | |
1218 { | |
1219 int dx, dy; | |
1220 if (mswindows_button2_max_skew_x <= 0) | |
1221 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2; | |
1222 else | |
1223 dx = mswindows_button2_max_skew_x; | |
1224 | |
1225 if (mswindows_button2_max_skew_y <= 0) | |
1226 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2; | |
1227 else | |
1228 dy = mswindows_button2_max_skew_y; | |
1229 | |
1230 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy; | |
1231 } | |
1232 | |
1233 static int | |
1234 mswindows_current_layout_has_AltGr (void) | |
1235 { | |
1236 /* This simple caching mechanism saves 10% of CPU | |
1237 time when a key typed at autorepeat rate of 30 cps! */ | |
1238 static HKL last_hkl = 0; | |
1239 static int last_hkl_has_AltGr; | |
1240 | |
1241 HKL current_hkl = GetKeyboardLayout (0); | |
1242 if (current_hkl != last_hkl) | |
1243 { | |
1244 TCHAR c; | |
1245 last_hkl_has_AltGr = 0; | |
1246 /* In this loop, we query whether a character requires | |
1247 AltGr to be down to generate it. If at least such one | |
1248 found, this means that the layout does regard AltGr */ | |
1249 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c) | |
1250 if (HIBYTE (VkKeyScan (c)) == 6) | |
1251 last_hkl_has_AltGr = 1; | |
1252 last_hkl = current_hkl; | |
1253 } | |
1254 return last_hkl_has_AltGr; | |
1255 } | |
1256 | |
1257 | |
1258 /* Returns the state of the modifier keys in the format expected by the | |
1259 * Lisp_Event key_data, button_data and motion_data modifiers member */ | |
1260 int mswindows_modifier_state (BYTE* keymap, int has_AltGr) | |
1261 { | |
1262 int mods = 0; | |
1263 | |
1264 if (keymap == NULL) | |
1265 { | |
1266 keymap = (BYTE*) alloca(256); | |
1267 GetKeyboardState (keymap); | |
1268 has_AltGr = mswindows_current_layout_has_AltGr (); | |
1269 } | |
1270 | |
1271 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80)) | |
1272 { | |
1273 mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0; | |
1274 mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0; | |
1275 } | |
1276 else | |
1277 { | |
1278 mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0; | |
1279 mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0; | |
1280 } | |
1281 | |
1282 mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0; | |
1283 | |
1284 return mods; | |
1285 } | |
1286 | |
1287 /* | |
1288 * Translate a mswindows virtual key to a keysym. | |
1289 * Only returns non-Qnil for keys that don't generate WM_CHAR messages | |
1290 * or whose ASCII codes (like space) xemacs doesn't like. | |
1291 * Virtual key values are defined in winresrc.h | |
1292 * XXX I'm not sure that KEYSYM("name") is the best thing to use here. | |
1293 */ | |
1294 Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods) | |
1295 { | |
1296 switch (mswindows_key) | |
1297 { | |
1298 /* First the predefined ones */ | |
1299 case VK_BACK: return QKbackspace; | |
1300 case VK_TAB: return QKtab; | |
1301 case '\n': return QKlinefeed; /* No VK_LINEFEED in winresrc.h */ | |
1302 case VK_RETURN: return QKreturn; | |
1303 case VK_ESCAPE: return QKescape; | |
1304 case VK_SPACE: return QKspace; | |
1305 case VK_DELETE: return QKdelete; | |
1306 | |
1307 /* The rest */ | |
1308 case VK_CLEAR: return KEYSYM ("clear"); /* Should do ^L ? */ | |
1309 case VK_PRIOR: return KEYSYM ("prior"); | |
1310 case VK_NEXT: return KEYSYM ("next"); | |
1311 case VK_END: return KEYSYM ("end"); | |
1312 case VK_HOME: return KEYSYM ("home"); | |
1313 case VK_LEFT: return KEYSYM ("left"); | |
1314 case VK_UP: return KEYSYM ("up"); | |
1315 case VK_RIGHT: return KEYSYM ("right"); | |
1316 case VK_DOWN: return KEYSYM ("down"); | |
1317 case VK_SELECT: return KEYSYM ("select"); | |
1318 case VK_PRINT: return KEYSYM ("print"); | |
1319 case VK_EXECUTE: return KEYSYM ("execute"); | |
1320 case VK_SNAPSHOT: return KEYSYM ("print"); | |
1321 case VK_INSERT: return KEYSYM ("insert"); | |
1322 case VK_HELP: return KEYSYM ("help"); | |
1323 #if 0 /* XXX What are these supposed to do? */ | |
1324 case VK_LWIN return KEYSYM (""); | |
1325 case VK_RWIN return KEYSYM (""); | |
1326 #endif | |
1327 case VK_APPS: return KEYSYM ("menu"); | |
1328 case VK_F1: return KEYSYM ("f1"); | |
1329 case VK_F2: return KEYSYM ("f2"); | |
1330 case VK_F3: return KEYSYM ("f3"); | |
1331 case VK_F4: return KEYSYM ("f4"); | |
1332 case VK_F5: return KEYSYM ("f5"); | |
1333 case VK_F6: return KEYSYM ("f6"); | |
1334 case VK_F7: return KEYSYM ("f7"); | |
1335 case VK_F8: return KEYSYM ("f8"); | |
1336 case VK_F9: return KEYSYM ("f9"); | |
1337 case VK_F10: return KEYSYM ("f10"); | |
1338 case VK_F11: return KEYSYM ("f11"); | |
1339 case VK_F12: return KEYSYM ("f12"); | |
1340 case VK_F13: return KEYSYM ("f13"); | |
1341 case VK_F14: return KEYSYM ("f14"); | |
1342 case VK_F15: return KEYSYM ("f15"); | |
1343 case VK_F16: return KEYSYM ("f16"); | |
1344 case VK_F17: return KEYSYM ("f17"); | |
1345 case VK_F18: return KEYSYM ("f18"); | |
1346 case VK_F19: return KEYSYM ("f19"); | |
1347 case VK_F20: return KEYSYM ("f20"); | |
1348 case VK_F21: return KEYSYM ("f21"); | |
1349 case VK_F22: return KEYSYM ("f22"); | |
1350 case VK_F23: return KEYSYM ("f23"); | |
1351 case VK_F24: return KEYSYM ("f24"); | |
1352 } | |
1353 return Qnil; | |
1354 } | |
1355 | |
1356 /* | |
1357 * Find the console that matches the supplied mswindows window handle | |
1358 */ | |
1359 Lisp_Object | |
1360 mswindows_find_console (HWND hwnd) | |
1361 { | |
1362 Lisp_Object concons; | |
1363 | |
1364 CONSOLE_LOOP (concons) | |
1365 { | |
1366 Lisp_Object console = XCAR (concons); | |
1367 /* We only support one console so this must be it */ | |
1368 return console; | |
1369 } | |
1370 | |
1371 return Qnil; | |
1372 } | |
1373 | |
1374 /* | |
1375 * Find the frame that matches the supplied mswindows window handle | |
1376 */ | |
1377 static Lisp_Object | |
1378 mswindows_find_frame (HWND hwnd) | |
1379 { | |
1380 return (Lisp_Object) GetWindowLong (hwnd, XWL_FRAMEOBJ); | |
1381 } | |
1382 | |
539 | 1383 |
540 | 1384 |
541 /************************************************************************/ | 1385 /************************************************************************/ |
542 /* methods */ | 1386 /* methods */ |
543 /************************************************************************/ | 1387 /************************************************************************/ |
552 milliseconds = EMACS_SECS (thyme) * 1000 + | 1396 milliseconds = EMACS_SECS (thyme) * 1000 + |
553 (EMACS_USECS (thyme) + 500) / 1000; | 1397 (EMACS_USECS (thyme) + 500) / 1000; |
554 if (milliseconds < 1) | 1398 if (milliseconds < 1) |
555 milliseconds = 1; | 1399 milliseconds = 1; |
556 ++mswindows_pending_timers_count; | 1400 ++mswindows_pending_timers_count; |
557 return SetTimer (NULL, 0, milliseconds, mswindows_wm_timer_callback); | 1401 return SetTimer (NULL, 0, milliseconds, |
1402 (TIMERPROC) mswindows_wm_timer_callback); | |
558 } | 1403 } |
559 | 1404 |
560 static void | 1405 static void |
561 emacs_mswindows_remove_timeout (int id) | 1406 emacs_mswindows_remove_timeout (int id) |
562 { | 1407 { |
615 * Handle a magic event off the dispatch queue. | 1460 * Handle a magic event off the dispatch queue. |
616 */ | 1461 */ |
617 static void | 1462 static void |
618 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event) | 1463 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event) |
619 { | 1464 { |
620 #if 0 | |
621 stderr_out("magic %x, (%d,%d), (%d,%d)\n", | |
622 EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event), | |
623 rect->left, rect->top, rect->right, rect->bottom); | |
624 #endif | |
625 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)) | 1465 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)) |
626 { | 1466 { |
627 case WM_SETFOCUS: | 1467 case WM_SETFOCUS: |
628 case WM_KILLFOCUS: | 1468 case WM_KILLFOCUS: |
629 { | 1469 { |
660 Qmap_frame_hook : Qunmap_frame_hook, | 1500 Qmap_frame_hook : Qunmap_frame_hook, |
661 1, frame); | 1501 1, frame); |
662 } | 1502 } |
663 break; | 1503 break; |
664 | 1504 |
665 /* XXX What about Enter & Leave */ | 1505 /* #### What about Enter & Leave */ |
666 #if 0 | 1506 #if 0 |
667 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook : | 1507 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook : |
668 Qmouse_leave_frame_hook, 1, frame); | 1508 Qmouse_leave_frame_hook, 1, frame); |
669 #endif | 1509 #endif |
670 | 1510 |