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