Release 940420
[wine] / windows / event.c
1 /*
2  * X events handling functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
8
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <X11/Xlib.h>
12 #include <X11/Xresource.h>
13 #include <X11/Xutil.h>
14
15 #include "windows.h"
16 #include "win.h"
17 #include "class.h"
18 #include "message.h"
19
20 #ifndef FamilyAmoeba
21 typedef char *XPointer;
22 #endif
23
24 #define NB_BUTTONS      3     /* Windows can handle 3 buttons */
25
26 extern int desktopX, desktopY;   /* misc/main.c */
27
28 extern void WINPOS_ChangeActiveWindow( HWND hwnd, BOOL mouseMsg ); /*winpos.c*/
29
30   /* X context to associate a hwnd to an X window */
31 static XContext winContext = 0;
32
33   /* State variables */
34 BOOL MouseButtonsStates[NB_BUTTONS] = { FALSE, FALSE, FALSE };
35 static WORD ALTKeyState;
36 static HWND captureWnd = 0;
37 Window winHasCursor = 0;
38
39 /* Keyboard translation tables */
40 static int special_key[] =
41 {
42     VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0,           /* FF08 */
43     0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0,                      /* FF10 */
44     0, 0, 0, VK_ESCAPE                                          /* FF18 */
45 };
46
47 static cursor_key[] =
48 {
49     VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR, 
50                                        VK_NEXT, VK_END          /* FF50 */
51 };
52
53 static misc_key[] =
54 {
55     VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0,  /* FF60 */
56     VK_CANCEL, VK_HELP, VK_CANCEL, VK_MENU                      /* FF68 */
57 };
58
59 static keypad_key[] =
60 {
61     VK_MENU, VK_NUMLOCK,                                        /* FF7E */
62     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF80 */
63     0, 0, 0, 0, 0, VK_RETURN, 0, 0,                             /* FF88 */
64     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF90 */
65     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF98 */
66     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FFA0 */
67     0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT, 
68                                VK_DECIMAL, VK_DIVIDE,           /* FFA8 */
69     VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
70                             VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
71     VK_NUMPAD8, VK_NUMPAD9                                      /* FFB8 */
72 };
73     
74 static function_key[] =
75 {
76     VK_F1, VK_F2,                                               /* FFBE */
77     VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10,    /* FFC0 */
78     VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16              /* FFC8 */
79 };
80
81 static modifier_key[] =
82 {
83     VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL,
84                                                 0, 0,           /* FFE1 */
85     0, VK_MENU, VK_MENU                                         /* FFE8 */
86 };
87
88 typedef union
89 {
90     struct
91     {
92         unsigned long count : 16;
93         unsigned long code : 8;
94         unsigned long extended : 1;
95         unsigned long : 4;
96         unsigned long context : 1;
97         unsigned long previous : 1;
98         unsigned long transition : 1;
99     } lp1;
100     unsigned long lp2;
101 } KEYLP;
102
103 static BOOL KeyDown = FALSE;
104
105
106 #ifdef DEBUG_EVENT
107 static char *event_names[] =
108 {
109     "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
110     "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
111     "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
112     "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
113     "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
114     "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
115     "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
116     "ClientMessage", "MappingNotify"
117 };
118 #endif
119
120   /* Event handlers */
121 static void EVENT_key( HWND hwnd, XKeyEvent *event );
122 static void EVENT_ButtonPress( XButtonEvent *event );
123 static void EVENT_ButtonRelease( XButtonEvent *event );
124 static void EVENT_MotionNotify( XMotionEvent *event );
125 static void EVENT_EnterNotify( XCrossingEvent *event );
126 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event );
127 static void EVENT_Expose( HWND hwnd, XExposeEvent *event );
128 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
129
130
131 /***********************************************************************
132  *           EVENT_ProcessEvent
133  *
134  * Process an X event.
135  */
136 void EVENT_ProcessEvent( XEvent *event )
137 {
138     HWND hwnd;
139     XPointer ptr;
140     
141     XFindContext( display, ((XAnyEvent *)event)->window, winContext, &ptr );
142     hwnd = (HWND) (int)ptr;
143
144 #ifdef DEBUG_EVENT
145     printf( "Got event %s for hwnd %d\n", event_names[event->type], hwnd );
146 #endif
147
148     switch(event->type)
149     {
150     case KeyPress:
151     case KeyRelease:
152         EVENT_key( hwnd, (XKeyEvent*)event );
153         break;
154         
155     case ButtonPress:
156         EVENT_ButtonPress( (XButtonEvent*)event );
157         break;
158
159     case ButtonRelease:
160         EVENT_ButtonRelease( (XButtonEvent*)event );
161         break;
162
163     case MotionNotify:
164         EVENT_MotionNotify( (XMotionEvent*)event );
165         break;
166
167     case EnterNotify:
168         EVENT_EnterNotify( (XCrossingEvent*)event );
169         break;
170
171     case FocusOut:
172         EVENT_FocusOut( hwnd, (XFocusChangeEvent*)event );
173         break;
174
175     case Expose:
176         EVENT_Expose( hwnd, (XExposeEvent*)event );
177         break;
178
179     case ConfigureNotify:
180         EVENT_ConfigureNotify( hwnd, (XConfigureEvent*)event );
181         break;
182
183 #ifdef DEBUG_EVENT
184     default:    
185         printf( "Unprocessed event %s for hwnd %d\n",
186                 event_names[event->type], hwnd );
187         break;
188 #endif  
189     }
190 }
191
192
193 /***********************************************************************
194  *           EVENT_RegisterWindow
195  *
196  * Associate an X window to a HWND.
197  */
198 void EVENT_RegisterWindow( Window w, HWND hwnd )
199 {
200     if (!winContext) winContext = XUniqueContext();
201     XSaveContext( display, w, winContext, (XPointer)(int)hwnd );
202 }
203
204
205 /***********************************************************************
206  *           EVENT_XStateToKeyState
207  *
208  * Translate a X event state (Button1Mask, ShiftMask, etc...) to
209  * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
210  */
211 static WORD EVENT_XStateToKeyState( int state )
212 {
213     int kstate = 0;
214     
215     if (state & Button1Mask) kstate |= MK_LBUTTON;
216     if (state & Button2Mask) kstate |= MK_MBUTTON;
217     if (state & Button3Mask) kstate |= MK_RBUTTON;
218     if (state & ShiftMask)   kstate |= MK_SHIFT;
219     if (state & ControlMask) kstate |= MK_CONTROL;
220     return kstate;
221 }
222
223
224 /***********************************************************************
225  *           EVENT_Expose
226  */
227 static void EVENT_Expose( HWND hwnd, XExposeEvent *event )
228 {
229     RECT rect;
230     UINT flags;
231     WND * wndPtr = WIN_FindWndPtr( hwnd );
232     if (!wndPtr) return;
233
234       /* Make position relative to client area instead of window */
235     rect.left = event->x - (wndPtr->rectClient.left - wndPtr->rectWindow.left);
236     rect.top  = event->y - (wndPtr->rectClient.top - wndPtr->rectWindow.top);
237     rect.right  = rect.left + event->width;
238     rect.bottom = rect.top + event->height;
239     winHasCursor = event->window;
240
241     flags = RDW_INVALIDATE | RDW_ERASE | RDW_FRAME;
242       /* Erase desktop background synchronously */
243     if (event->window == rootWindow) flags |= RDW_ERASENOW | RDW_NOCHILDREN;
244     RedrawWindow( hwnd, &rect, 0, flags );
245 }
246
247
248 /***********************************************************************
249  *           EVENT_key
250  *
251  * Handle a X key event
252  */
253 static void EVENT_key( HWND hwnd, XKeyEvent *event )
254 {
255     char Str[24]; 
256     XComposeStatus cs; 
257     KeySym keysym;
258     WORD xkey, vkey, key_type, key;
259     KEYLP keylp;
260     BOOL extended = FALSE;
261
262     int count = XLookupString(event, Str, 1, &keysym, &cs);
263     Str[count] = '\0';
264 #ifdef DEBUG_KEY
265     printf("WM_KEY??? : keysym=%lX, count=%u / %X / '%s'\n", 
266            keysym, count, Str[0], Str);
267 #endif
268
269     xkey = LOWORD(keysym);
270     key_type = HIBYTE(xkey);
271     key = LOBYTE(xkey);
272 #ifdef DEBUG_KEY
273     printf("            key_type=%X, key=%X\n", key_type, key);
274 #endif
275
276     if (key_type == 0xFF)                          /* non-character key */
277     {
278         if (key >= 0x08 && key <= 0x1B)            /* special key */
279             vkey = special_key[key - 0x08];
280         else if (key >= 0x50 && key <= 0x57)       /* cursor key */
281             vkey = cursor_key[key - 0x50];
282         else if (key >= 0x60 && key <= 0x6B)       /* miscellaneous key */
283             vkey = misc_key[key - 0x60];
284         else if (key >= 0x7E && key <= 0xB9)       /* keypad key */
285         {
286             vkey = keypad_key[key - 0x7E];
287             extended = TRUE;
288         }
289         else if (key >= 0xBE && key <= 0xCD)       /* function key */
290         {
291             vkey = function_key[key - 0xBE];
292             extended = TRUE;
293         }
294         else if (key >= 0xE1 && key <= 0xEA)       /* modifier key */
295             vkey = modifier_key[key - 0xE1];
296         else if (key == 0xFF)                      /* DEL key */
297             vkey = VK_DELETE;
298     }
299     else if (key_type == 0)                        /* character key */
300     {
301         if (key >= 0x61 && key <= 0x7A)
302             vkey = key - 0x20;                 /* convert lower to uppercase */
303         else
304             vkey = key;
305     }
306
307     if (event->type == KeyPress)
308     {
309         if (vkey == VK_MENU) ALTKeyState = TRUE;
310         keylp.lp1.count = 1;
311         keylp.lp1.code = LOBYTE(event->keycode);
312         keylp.lp1.extended = (extended ? 1 : 0);
313         keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0);
314         keylp.lp1.previous = (KeyDown ? 0 : 1);
315         keylp.lp1.transition = 0;
316 #ifdef DEBUG_KEY
317         printf("            wParam=%X, lParam=%lX\n", vkey, keylp.lp2 );
318 #endif
319         hardware_event( ALTKeyState ? WM_SYSKEYDOWN : WM_KEYDOWN, 
320                         vkey, keylp.lp2,
321                         event->x_root - desktopX, event->y_root - desktopY,
322                         event->time, 0 );
323         KeyDown = TRUE;
324
325         /* The key translation ought to take place in TranslateMessage().
326          * However, there is no way of passing the required information 
327          * in a Windows message, so TranslateMessage does not currently
328          * do anything and the translation is done here.
329          */
330         if (count == 1)                /* key has an ASCII representation */
331         {
332 #ifdef DEBUG_KEY
333             printf("WM_CHAR :   wParam=%X\n", (WORD)Str[0] );
334 #endif
335             PostMessage( GetFocus(), WM_CHAR, (WORD)Str[0], keylp.lp2 );
336         }
337     }
338     else
339     {
340         if (vkey == VK_MENU) ALTKeyState = FALSE;
341         keylp.lp1.count = 1;
342         keylp.lp1.code = LOBYTE(event->keycode);
343         keylp.lp1.extended = (extended ? 1 : 0);
344         keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0);
345         keylp.lp1.previous = 1;
346         keylp.lp1.transition = 1;
347 #ifdef DEBUG_KEY
348         printf("            wParam=%X, lParam=%lX\n", vkey, keylp.lp2 );
349 #endif
350         hardware_event( ((ALTKeyState || vkey == VK_MENU) ? 
351                          WM_SYSKEYUP : WM_KEYUP), 
352                         vkey, keylp.lp2,
353                         event->x_root - desktopX, event->y_root - desktopY,
354                         event->time, 0 );
355         KeyDown = FALSE;
356     }
357 }
358
359
360 /***********************************************************************
361  *           EVENT_MotionNotify
362  */
363 static void EVENT_MotionNotify( XMotionEvent *event )
364 {
365     hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
366                     event->x_root - desktopX, event->y_root - desktopY,
367                     event->time, 0 );
368 }
369
370
371 /***********************************************************************
372  *           EVENT_ButtonPress
373  */
374 static void EVENT_ButtonPress( XButtonEvent *event )
375 {
376     static WORD messages[NB_BUTTONS] = 
377         { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
378     int buttonNum = event->button - 1;
379
380     if (buttonNum >= NB_BUTTONS) return;
381     MouseButtonsStates[buttonNum] = TRUE;
382     winHasCursor = event->window;
383     hardware_event( messages[buttonNum],
384                     EVENT_XStateToKeyState( event->state ), 0L,
385                     event->x_root - desktopX, event->y_root - desktopY,
386                     event->time, 0 );
387 }
388
389
390 /***********************************************************************
391  *           EVENT_ButtonRelease
392  */
393 static void EVENT_ButtonRelease( XButtonEvent *event )
394 {
395     static const WORD messages[NB_BUTTONS] = 
396         { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
397     int buttonNum = event->button - 1;
398
399     if (buttonNum >= NB_BUTTONS) return;    
400     MouseButtonsStates[buttonNum] = FALSE;
401     winHasCursor = event->window;
402     hardware_event( messages[buttonNum],
403                     EVENT_XStateToKeyState( event->state ), 0L,
404                     event->x_root - desktopX, event->y_root - desktopY,
405                     event->time, 0 );
406 }
407
408
409 /**********************************************************************
410  *              EVENT_FocusOut
411  *
412  * Note: only top-level override-redirect windows get FocusOut events.
413  */
414 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
415 {
416     if (event->detail == NotifyPointer) return;
417     if (hwnd == GetActiveWindow()) WINPOS_ChangeActiveWindow( 0, FALSE );
418     if ((hwnd == GetFocus()) || IsChild( hwnd, GetFocus())) SetFocus( 0 );
419 }
420
421
422 /**********************************************************************
423  *              EVENT_EnterNotify
424  */
425 static void EVENT_EnterNotify( XCrossingEvent *event )
426 {
427     if (captureWnd != 0) return;
428     winHasCursor = event->window;
429 }
430
431
432 /**********************************************************************
433  *              EVENT_ConfigureNotify
434  *
435  * The ConfigureNotify event is only selected on the desktop window.
436  */
437 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
438 {
439     desktopX = event->x;
440     desktopY = event->y;
441 }
442
443
444 /**********************************************************************
445  *              SetCapture      (USER.18)
446  */
447 HWND SetCapture(HWND wnd)
448 {
449     int rv;
450     HWND old_capture_wnd = captureWnd;
451     WND *wnd_p = WIN_FindWndPtr(wnd);
452     if (wnd_p == NULL)
453         return 0;
454     
455     rv = XGrabPointer(display, wnd_p->window, False, 
456                       ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
457                       GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
458
459     if (rv == GrabSuccess)
460     {
461         captureWnd = wnd;
462         return old_capture_wnd;
463     }
464     else
465         return 0;
466 }
467
468 /**********************************************************************
469  *              ReleaseCapture  (USER.19)
470  */
471 void ReleaseCapture()
472 {
473     if (captureWnd == 0) return;
474     XUngrabPointer( display, CurrentTime );
475     captureWnd = 0;
476 }
477
478 /**********************************************************************
479  *              GetCapture      (USER.236)
480  */
481 HWND GetCapture()
482 {
483     return captureWnd;
484 }