Release 950216
[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 WHO_NEEDS_DIRTY_HACKS
35 #ifdef sparc
36 /* Dirty hack to compile with Sun's OpenWindows */
37 typedef char *XPointer;
38 #endif
39 #endif
40
41 #define NB_BUTTONS      3     /* Windows can handle 3 buttons */
42
43   /* X context to associate a hwnd to an X window */
44 static XContext winContext = 0;
45
46   /* State variables */
47 BOOL MouseButtonsStates[NB_BUTTONS] = { FALSE, FALSE, FALSE };
48 BOOL AsyncMouseButtonsStates[NB_BUTTONS] = { FALSE, FALSE, FALSE };
49 BYTE KeyStateTable[256];
50 BYTE AsyncKeyStateTable[256];
51 static WORD ALTKeyState;
52 static HWND captureWnd = 0;
53 static BOOL     InputEnabled = TRUE;
54
55 /* Keyboard translation tables */
56 static int special_key[] =
57 {
58     VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0,           /* FF08 */
59     0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0,                      /* FF10 */
60     0, 0, 0, VK_ESCAPE                                          /* FF18 */
61 };
62
63 static cursor_key[] =
64 {
65     VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR, 
66                                        VK_NEXT, VK_END          /* FF50 */
67 };
68
69 static misc_key[] =
70 {
71     VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0,  /* FF60 */
72     VK_CANCEL, VK_HELP, VK_CANCEL, VK_MENU                      /* FF68 */
73 };
74
75 static keypad_key[] =
76 {
77     VK_MENU, VK_NUMLOCK,                                        /* FF7E */
78     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF80 */
79     0, 0, 0, 0, 0, VK_RETURN, 0, 0,                             /* FF88 */
80     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF90 */
81     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FF98 */
82     0, 0, 0, 0, 0, 0, 0, 0,                                     /* FFA0 */
83     0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT, 
84                                VK_DECIMAL, VK_DIVIDE,           /* FFA8 */
85     VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
86                             VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
87     VK_NUMPAD8, VK_NUMPAD9                                      /* FFB8 */
88 };
89     
90 static function_key[] =
91 {
92     VK_F1, VK_F2,                                               /* FFBE */
93     VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10,    /* FFC0 */
94     VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16              /* FFC8 */
95 };
96
97 static modifier_key[] =
98 {
99     VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL,
100                                                 0, 0,           /* FFE1 */
101     0, VK_MENU, VK_MENU                                         /* FFE8 */
102 };
103
104 typedef union
105 {
106     struct
107     {
108         unsigned long count : 16;
109         unsigned long code : 8;
110         unsigned long extended : 1;
111         unsigned long : 4;
112         unsigned long context : 1;
113         unsigned long previous : 1;
114         unsigned long transition : 1;
115     } lp1;
116     unsigned long lp2;
117 } KEYLP;
118
119 static BOOL KeyDown = FALSE;
120
121
122 static char *event_names[] =
123 {
124     "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
125     "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
126     "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
127     "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
128     "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
129     "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
130     "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
131     "ClientMessage", "MappingNotify"
132 };
133
134   /* Event handlers */
135 static void EVENT_key( XKeyEvent *event );
136 static void EVENT_ButtonPress( XButtonEvent *event );
137 static void EVENT_ButtonRelease( XButtonEvent *event );
138 static void EVENT_MotionNotify( XMotionEvent *event );
139 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event );
140 static void EVENT_Expose( HWND hwnd, XExposeEvent *event );
141 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
142 static void EVENT_SelectionRequest( HWND hwnd, XSelectionRequestEvent *event);
143 static void EVENT_SelectionNotify( HWND hwnd, XSelectionEvent *event);
144 static void EVENT_SelectionClear( HWND hwnd, XSelectionClearEvent *event);
145
146
147 /***********************************************************************
148  *           EVENT_ProcessEvent
149  *
150  * Process an X event.
151  */
152 void EVENT_ProcessEvent( XEvent *event )
153 {
154     HWND hwnd;
155     XPointer ptr;
156     
157     XFindContext( display, ((XAnyEvent *)event)->window, winContext, &ptr );
158     hwnd = (HWND) (int)ptr;
159
160     dprintf_event(stddeb, "Got event %s for hwnd %d\n", 
161                   event_names[event->type], hwnd );
162
163     switch(event->type)
164     {
165     case KeyPress:
166     case KeyRelease:
167         EVENT_key( (XKeyEvent*)event );
168         break;
169         
170     case ButtonPress:
171         EVENT_ButtonPress( (XButtonEvent*)event );
172         break;
173
174     case ButtonRelease:
175         EVENT_ButtonRelease( (XButtonEvent*)event );
176         break;
177
178     case MotionNotify:
179         /* Wine between two fast machines across the overloaded campus
180            ethernet gets very boged down in MotionEvents. The following
181            simply finds the last motion event in the queue and drops
182            the rest. On a good link events are servered before they build
183            up so this doesn't take place. On a slow link this may cause
184            problems if the event order is important. I'm not yet seen
185            of any problems. Jon 7/6/96.
186          */
187         while (XCheckTypedWindowEvent(display, ((XAnyEvent *)event)->window,
188                           MotionNotify, event));    
189         EVENT_MotionNotify( (XMotionEvent*)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     case SelectionRequest:
205         EVENT_SelectionRequest( hwnd, (XSelectionRequestEvent*)event );
206         break;
207
208     case SelectionNotify:
209         EVENT_SelectionNotify( hwnd, (XSelectionEvent*)event );
210         break;
211
212     case SelectionClear:
213         EVENT_SelectionClear( hwnd, (XSelectionClearEvent*) event );
214         break;
215
216     default:    
217         dprintf_event(stddeb, "Unprocessed event %s for hwnd %d\n",
218                 event_names[event->type], hwnd );
219         break;
220     }
221 }
222
223
224 /***********************************************************************
225  *           EVENT_RegisterWindow
226  *
227  * Associate an X window to a HWND.
228  */
229 void EVENT_RegisterWindow( Window w, HWND hwnd )
230 {
231     if (!winContext) winContext = XUniqueContext();
232     XSaveContext( display, w, winContext, (XPointer)(int)hwnd );
233 }
234
235
236 /***********************************************************************
237  *           EVENT_XStateToKeyState
238  *
239  * Translate a X event state (Button1Mask, ShiftMask, etc...) to
240  * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
241  */
242 static WORD EVENT_XStateToKeyState( int state )
243 {
244     int kstate = 0;
245     
246     if (state & Button1Mask) kstate |= MK_LBUTTON;
247     if (state & Button2Mask) kstate |= MK_MBUTTON;
248     if (state & Button3Mask) kstate |= MK_RBUTTON;
249     if (state & ShiftMask)   kstate |= MK_SHIFT;
250     if (state & ControlMask) kstate |= MK_CONTROL;
251     return kstate;
252 }
253
254
255 /***********************************************************************
256  *           EVENT_Expose
257  */
258 static void EVENT_Expose( HWND hwnd, XExposeEvent *event )
259 {
260     RECT rect;
261     WND * wndPtr = WIN_FindWndPtr( hwnd );
262     if (!wndPtr) return;
263
264       /* Make position relative to client area instead of window */
265     rect.left = event->x - (wndPtr->rectClient.left - wndPtr->rectWindow.left);
266     rect.top  = event->y - (wndPtr->rectClient.top - wndPtr->rectWindow.top);
267     rect.right  = rect.left + event->width;
268     rect.bottom = rect.top + event->height;
269
270     RedrawWindow( hwnd, &rect, 0,
271                   RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
272                   (event->count ? 0 : RDW_ERASENOW) );
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