Release 941227
[wine/multimedia.git] / windows / event.c
blob71469b7808b8823de6853cebfcea5bd1ceb80f36
1 /*
2 * X events handling functions
4 * Copyright 1993 Alexandre Julliard
6 static char Copyright[] = "Copyright Alexandre Julliard, 1993";
7 */
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"
28 #ifdef ndef
29 #ifndef FamilyAmoeba
30 typedef char *XPointer;
31 #endif
32 #endif
34 #ifdef sparc
35 /* Dirty hack to compile with Sun's OpenWindows */
36 typedef char *XPointer;
37 #endif
39 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
41 /* X context to associate a hwnd to an X window */
42 static XContext winContext = 0;
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;
53 /* Keyboard translation tables */
54 static int special_key[] =
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 */
61 static cursor_key[] =
63 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR,
64 VK_NEXT, VK_END /* FF50 */
67 static misc_key[] =
69 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
70 VK_CANCEL, VK_HELP, VK_CANCEL, VK_MENU /* FF68 */
73 static keypad_key[] =
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 */
88 static function_key[] =
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 */
95 static modifier_key[] =
97 VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL,
98 0, 0, /* FFE1 */
99 0, VK_MENU, VK_MENU /* FFE8 */
102 typedef union
104 struct
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;
117 static BOOL KeyDown = FALSE;
120 static char *event_names[] =
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"
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);
145 /***********************************************************************
146 * EVENT_ProcessEvent
148 * Process an X event.
150 void EVENT_ProcessEvent( XEvent *event )
152 HWND hwnd;
153 XPointer ptr;
155 XFindContext( display, ((XAnyEvent *)event)->window, winContext, &ptr );
156 hwnd = (HWND) (int)ptr;
158 dprintf_event(stddeb, "Got event %s for hwnd %d\n",
159 event_names[event->type], hwnd );
161 switch(event->type)
163 case KeyPress:
164 case KeyRelease:
165 EVENT_key( (XKeyEvent*)event );
166 break;
168 case ButtonPress:
169 EVENT_ButtonPress( (XButtonEvent*)event );
170 break;
172 case ButtonRelease:
173 EVENT_ButtonRelease( (XButtonEvent*)event );
174 break;
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.
185 while (XCheckTypedWindowEvent(display, ((XAnyEvent *)event)->window,
186 MotionNotify, event));
187 EVENT_MotionNotify( (XMotionEvent*)event );
188 break;
190 case FocusOut:
191 EVENT_FocusOut( hwnd, (XFocusChangeEvent*)event );
192 break;
194 case Expose:
195 EVENT_Expose( hwnd, (XExposeEvent*)event );
196 break;
198 case ConfigureNotify:
199 EVENT_ConfigureNotify( hwnd, (XConfigureEvent*)event );
200 break;
202 case SelectionRequest:
203 EVENT_SelectionRequest( hwnd, (XSelectionRequestEvent*)event );
204 break;
206 case SelectionNotify:
207 EVENT_SelectionNotify( hwnd, (XSelectionEvent*)event );
208 break;
210 case SelectionClear:
211 EVENT_SelectionClear( hwnd, (XSelectionClearEvent*) event );
212 break;
214 default:
215 dprintf_event(stddeb, "Unprocessed event %s for hwnd %d\n",
216 event_names[event->type], hwnd );
217 break;
222 /***********************************************************************
223 * EVENT_RegisterWindow
225 * Associate an X window to a HWND.
227 void EVENT_RegisterWindow( Window w, HWND hwnd )
229 if (!winContext) winContext = XUniqueContext();
230 XSaveContext( display, w, winContext, (XPointer)(int)hwnd );
234 /***********************************************************************
235 * EVENT_XStateToKeyState
237 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
238 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
240 static WORD EVENT_XStateToKeyState( int state )
242 int kstate = 0;
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;
253 /***********************************************************************
254 * EVENT_Expose
256 static void EVENT_Expose( HWND hwnd, XExposeEvent *event )
258 RECT rect;
259 UINT flags;
260 WND * wndPtr = WIN_FindWndPtr( hwnd );
261 if (!wndPtr) return;
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;
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 );
276 /***********************************************************************
277 * EVENT_key
279 * Handle a X key event
281 static void EVENT_key( XKeyEvent *event )
283 char Str[24];
284 XComposeStatus cs;
285 KeySym keysym;
286 WORD xkey, vkey, key_type, key;
287 KEYLP keylp;
288 BOOL extended = FALSE;
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);
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);
300 if (key_type == 0xFF) /* non-character key */
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 */
310 vkey = keypad_key[key - 0x7E];
311 extended = TRUE;
313 else if (key >= 0xBE && key <= 0xCD) /* function key */
315 vkey = function_key[key - 0xBE];
316 extended = TRUE;
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;
323 else if (key_type == 0) /* character key */
325 if (key >= 0x61 && key <= 0x7A)
326 vkey = key - 0x20; /* convert lower to uppercase */
327 else
328 vkey = key;
331 if (event->type == KeyPress)
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;
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.
357 if (count == 1) /* key has an ASCII representation */
359 dprintf_key(stddeb,"WM_CHAR : wParam=%X\n", (WORD)Str[0] );
360 PostMessage( GetFocus(), WM_CHAR, (WORD)Str[0], keylp.lp2 );
363 else
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;
386 /***********************************************************************
387 * EVENT_MotionNotify
389 static void EVENT_MotionNotify( XMotionEvent *event )
391 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
392 event->x_root - desktopX, event->y_root - desktopY,
393 event->time, 0 );
397 /***********************************************************************
398 * EVENT_ButtonPress
400 static void EVENT_ButtonPress( XButtonEvent *event )
402 static WORD messages[NB_BUTTONS] =
403 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
404 int buttonNum = event->button - 1;
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 );
416 /***********************************************************************
417 * EVENT_ButtonRelease
419 static void EVENT_ButtonRelease( XButtonEvent *event )
421 static const WORD messages[NB_BUTTONS] =
422 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
423 int buttonNum = event->button - 1;
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 );
434 /**********************************************************************
435 * EVENT_FocusOut
437 * Note: only top-level override-redirect windows get FocusOut events.
439 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
441 if (event->detail == NotifyPointer) return;
442 if (hwnd == GetActiveWindow()) WINPOS_ChangeActiveWindow( 0, FALSE );
443 if ((hwnd == GetFocus()) || IsChild( hwnd, GetFocus())) SetFocus( 0 );
447 /**********************************************************************
448 * EVENT_ConfigureNotify
450 * The ConfigureNotify event is only selected on the desktop window.
452 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
454 desktopX = event->x;
455 desktopY = event->y;
459 /***********************************************************************
460 * EVENT_SelectionRequest
462 static void EVENT_SelectionRequest( HWND hwnd, XSelectionRequestEvent *event )
464 XSelectionEvent result;
465 Atom rprop;
466 Window request=event->requestor;
467 rprop=None;
468 if(event->target == XA_STRING)
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();
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);
501 /***********************************************************************
502 * EVENT_SelectionNotify
504 static void EVENT_SelectionNotify(HWND hwnd, XSelectionEvent *event)
506 if(event->selection!=XA_PRIMARY)return;
507 if(event->target!=XA_STRING)CLIPBOARD_ReadSelection(0,None);
508 CLIPBOARD_ReadSelection(event->requestor,event->property);
512 /***********************************************************************
513 * EVENT_SelectionClear
515 static void EVENT_SelectionClear(HWND hwnd, XSelectionClearEvent *event)
517 if(event->selection!=XA_PRIMARY)return;
518 CLIPBOARD_ReleaseSelection(hwnd);
521 /**********************************************************************
522 * SetCapture (USER.18)
524 HWND SetCapture( HWND hwnd )
526 Window win;
527 HWND old_capture_wnd = captureWnd;
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)
535 captureWnd = hwnd;
536 return old_capture_wnd;
538 else return 0;
542 /**********************************************************************
543 * ReleaseCapture (USER.19)
545 void ReleaseCapture()
547 if (captureWnd == 0) return;
548 XUngrabPointer( display, CurrentTime );
549 captureWnd = 0;
552 /**********************************************************************
553 * GetCapture (USER.236)
555 HWND GetCapture()
557 return captureWnd;
561 /**********************************************************************
562 * EnableHardwareInput [USER.331]
564 BOOL EnableHardwareInput(BOOL bEnable)
566 BOOL bOldState = InputEnabled;
567 dprintf_event(stdnimp,"EMPTY STUB !!! EnableHardwareInput(%d);\n", bEnable);
568 InputEnabled = bEnable;
569 return (bOldState && !bEnable);