Release 940912
[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       /* Make position relative to client area instead of window */
256     rect.left = event->x - (wndPtr->rectClient.left - wndPtr->rectWindow.left);
257     rect.top  = event->y - (wndPtr->rectClient.top - wndPtr->rectWindow.top);
258     rect.right  = rect.left + event->width;
259     rect.bottom = rect.top + event->height;
260     winHasCursor = event->window;
261
262     flags = RDW_INVALIDATE | RDW_ERASE | RDW_FRAME;
263       /* Erase desktop background synchronously */
264     if (event->window == rootWindow) flags |= RDW_ERASENOW | RDW_NOCHILDREN;
265     RedrawWindow( hwnd, &rect, 0, flags );
266 }
267
268
269 /***********************************************************************
270  *           EVENT_key
271  *
272  * Handle a X key event
273  */
274 static void EVENT_key( HWND hwnd, XKeyEvent *event )
275 {
276     char Str[24]; 
277     XComposeStatus cs; 
278     KeySym keysym;
279     WORD xkey, vkey, key_type, key;
280     KEYLP keylp;
281     BOOL extended = FALSE;
282
283     int count = XLookupString(event, Str, 1, &keysym, &cs);
284     Str[count] = '\0';
285 #ifdef DEBUG_KEY
286     printf("WM_KEY??? : keysym=%lX, count=%u / %X / '%s'\n", 
287            keysym, count, Str[0], Str);
288 #endif
289
290     xkey = LOWORD(keysym);
291     key_type = HIBYTE(xkey);
292     key = LOBYTE(xkey);
293 #ifdef DEBUG_KEY
294     printf("            key_type=%X, key=%X\n", key_type, key);
295 #endif
296
297     if (key_type == 0xFF)                          /* non-character key */
298     {
299         if (key >= 0x08 && key <= 0x1B)            /* special key */
300             vkey = special_key[key - 0x08];
301         else if (key >= 0x50 && key <= 0x57)       /* cursor key */
302             vkey = cursor_key[key - 0x50];
303         else if (key >= 0x60 && key <= 0x6B)       /* miscellaneous key */
304             vkey = misc_key[key - 0x60];
305         else if (key >= 0x7E && key <= 0xB9)       /* keypad key */
306         {
307             vkey = keypad_key[key - 0x7E];
308             extended = TRUE;
309         }
310         else if (key >= 0xBE && key <= 0xCD)       /* function key */
311         {
312             vkey = function_key[key - 0xBE];
313             extended = TRUE;
314         }
315         else if (key >= 0xE1 && key <= 0xEA)       /* modifier key */
316             vkey = modifier_key[key - 0xE1];
317         else if (key == 0xFF)                      /* DEL key */
318             vkey = VK_DELETE;
319     }
320     else if (key_type == 0)                        /* character key */
321     {
322         if (key >= 0x61 && key <= 0x7A)
323             vkey = key - 0x20;                 /* convert lower to uppercase */
324         else
325             vkey = key;
326     }
327
328     if (event->type == KeyPress)
329     {
330         if (vkey == VK_MENU) ALTKeyState = TRUE;
331         if (!(KeyStateTable[vkey] & 0x0f))
332             KeyStateTable[vkey] ^= 0x80;
333         KeyStateTable[vkey] |= 0x01;
334         keylp.lp1.count = 1;
335         keylp.lp1.code = LOBYTE(event->keycode);
336         keylp.lp1.extended = (extended ? 1 : 0);
337         keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0);
338         keylp.lp1.previous = (KeyDown ? 0 : 1);
339         keylp.lp1.transition = 0;
340 #ifdef DEBUG_KEY
341         printf("            wParam=%X, lParam=%lX\n", vkey, keylp.lp2 );
342         printf("            KeyState=%X\n", KeyStateTable[vkey]);
343 #endif
344         hardware_event( ALTKeyState ? WM_SYSKEYDOWN : WM_KEYDOWN, 
345                         vkey, keylp.lp2,
346                         event->x_root - desktopX, event->y_root - desktopY,
347                         event->time, 0 );
348         KeyDown = TRUE;
349
350         /* The key translation ought to take place in TranslateMessage().
351          * However, there is no way of passing the required information 
352          * in a Windows message, so TranslateMessage does not currently
353          * do anything and the translation is done here.
354          */
355         if (count == 1)                /* key has an ASCII representation */
356         {
357 #ifdef DEBUG_KEY
358             printf("WM_CHAR :   wParam=%X\n", (WORD)Str[0] );
359 #endif
360             PostMessage( GetFocus(), WM_CHAR, (WORD)Str[0], keylp.lp2 );
361         }
362     }
363     else
364     {
365         if (vkey == VK_MENU) ALTKeyState = FALSE;
366         KeyStateTable[vkey] &= 0xf0;
367         keylp.lp1.count = 1;
368         keylp.lp1.code = LOBYTE(event->keycode);
369         keylp.lp1.extended = (extended ? 1 : 0);
370         keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0);
371         keylp.lp1.previous = 1;
372         keylp.lp1.transition = 1;
373 #ifdef DEBUG_KEY
374         printf("            wParam=%X, lParam=%lX\n", vkey, keylp.lp2 );
375         printf("            KeyState=%X\n", KeyStateTable[vkey]);
376 #endif
377         hardware_event( ((ALTKeyState || vkey == VK_MENU) ? 
378                          WM_SYSKEYUP : WM_KEYUP), 
379                         vkey, keylp.lp2,
380                         event->x_root - desktopX, event->y_root - desktopY,
381                         event->time, 0 );
382         KeyDown = FALSE;
383     }
384 }
385
386
387 /***********************************************************************
388  *           EVENT_MotionNotify
389  */
390 static void EVENT_MotionNotify( XMotionEvent *event )
391 {
392     hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
393                     event->x_root - desktopX, event->y_root - desktopY,
394                     event->time, 0 );
395 }
396
397
398 /***********************************************************************
399  *           EVENT_ButtonPress
400  */
401 static void EVENT_ButtonPress( XButtonEvent *event )
402 {
403     static WORD messages[NB_BUTTONS] = 
404         { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
405     int buttonNum = event->button - 1;
406
407     if (buttonNum >= NB_BUTTONS) return;
408     MouseButtonsStates[buttonNum] = TRUE;
409     AsyncMouseButtonsStates[buttonNum] = TRUE;
410     winHasCursor = event->window;
411     hardware_event( messages[buttonNum],
412                     EVENT_XStateToKeyState( event->state ), 0L,
413                     event->x_root - desktopX, event->y_root - desktopY,
414                     event->time, 0 );
415 }
416
417
418 /***********************************************************************
419  *           EVENT_ButtonRelease
420  */
421 static void EVENT_ButtonRelease( XButtonEvent *event )
422 {
423     static const WORD messages[NB_BUTTONS] = 
424         { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
425     int buttonNum = event->button - 1;
426
427     if (buttonNum >= NB_BUTTONS) return;    
428     MouseButtonsStates[buttonNum] = FALSE;
429     winHasCursor = event->window;
430     hardware_event( messages[buttonNum],
431                     EVENT_XStateToKeyState( event->state ), 0L,
432                     event->x_root - desktopX, event->y_root - desktopY,
433                     event->time, 0 );
434 }
435
436
437 /**********************************************************************
438  *              EVENT_FocusOut
439  *
440  * Note: only top-level override-redirect windows get FocusOut events.
441  */
442 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
443 {
444     if (event->detail == NotifyPointer) return;
445     if (hwnd == GetActiveWindow()) WINPOS_ChangeActiveWindow( 0, FALSE );
446     if ((hwnd == GetFocus()) || IsChild( hwnd, GetFocus())) SetFocus( 0 );
447 }
448
449
450 /**********************************************************************
451  *              EVENT_EnterNotify
452  */
453 static void EVENT_EnterNotify( XCrossingEvent *event )
454 {
455     if (captureWnd != 0) return;
456     winHasCursor = event->window;
457 }
458
459
460 /**********************************************************************
461  *              EVENT_ConfigureNotify
462  *
463  * The ConfigureNotify event is only selected on the desktop window.
464  */
465 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
466 {
467     desktopX = event->x;
468     desktopY = event->y;
469 }
470
471
472 /**********************************************************************
473  *              SetCapture      (USER.18)
474  */
475 HWND SetCapture(HWND wnd)
476 {
477     int rv;
478     HWND old_capture_wnd = captureWnd;
479     WND *wnd_p = WIN_FindWndPtr(wnd);
480     if (wnd_p == NULL)
481         return 0;
482     
483     rv = XGrabPointer(display, wnd_p->window, False, 
484                       ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
485                       GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
486
487     if (rv == GrabSuccess)
488     {
489         winHasCursor = wnd_p->window;
490         captureWnd = wnd;
491         return old_capture_wnd;
492     }
493     else
494         return 0;
495 }
496
497 /**********************************************************************
498  *              ReleaseCapture  (USER.19)
499  */
500 void ReleaseCapture()
501 {
502     if (captureWnd == 0) return;
503     XUngrabPointer( display, CurrentTime );
504     captureWnd = 0;
505 }
506
507 /**********************************************************************
508  *              GetCapture      (USER.236)
509  */
510 HWND GetCapture()
511 {
512     return captureWnd;
513 }
514
515
516 /**********************************************************************
517  *                      EnableHardwareInput             [USER.331]
518  */
519 BOOL EnableHardwareInput(BOOL bEnable)
520 {
521         BOOL bOldState = InputEnabled;
522         printf("EMPTY STUB !!! EnableHardwareInput(%d);\n", bEnable);
523         InputEnabled = bEnable;
524     return (bOldState && !bEnable);
525 }
526