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