Release 950122
[wine/multimedia.git] / windows / event.c
blob4f4a2cf0065a28392414a4c6712aa4918889aa96
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 WND * wndPtr = WIN_FindWndPtr( hwnd );
260 if (!wndPtr) return;
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;
268 RedrawWindow( hwnd, &rect, 0,
269 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
270 (event->count ? 0 : RDW_ERASENOW) );
274 /***********************************************************************
275 * EVENT_key
277 * Handle a X key event
279 static void EVENT_key( XKeyEvent *event )
281 char Str[24];
282 XComposeStatus cs;
283 KeySym keysym;
284 WORD xkey, vkey, key_type, key;
285 KEYLP keylp;
286 BOOL extended = FALSE;
288 int count = XLookupString(event, Str, 1, &keysym, &cs);
289 Str[count] = '\0';
290 dprintf_key(stddeb,"WM_KEY??? : keysym=%lX, count=%u / %X / '%s'\n",
291 keysym, count, Str[0], Str);
293 xkey = LOWORD(keysym);
294 key_type = HIBYTE(xkey);
295 key = LOBYTE(xkey);
296 dprintf_key(stddeb," key_type=%X, key=%X\n", key_type, key);
298 if (key_type == 0xFF) /* non-character key */
300 if (key >= 0x08 && key <= 0x1B) /* special key */
301 vkey = special_key[key - 0x08];
302 else if (key >= 0x50 && key <= 0x57) /* cursor key */
303 vkey = cursor_key[key - 0x50];
304 else if (key >= 0x60 && key <= 0x6B) /* miscellaneous key */
305 vkey = misc_key[key - 0x60];
306 else if (key >= 0x7E && key <= 0xB9) /* keypad key */
308 vkey = keypad_key[key - 0x7E];
309 extended = TRUE;
311 else if (key >= 0xBE && key <= 0xCD) /* function key */
313 vkey = function_key[key - 0xBE];
314 extended = TRUE;
316 else if (key >= 0xE1 && key <= 0xEA) /* modifier key */
317 vkey = modifier_key[key - 0xE1];
318 else if (key == 0xFF) /* DEL key */
319 vkey = VK_DELETE;
321 else if (key_type == 0) /* character key */
323 if (key >= 0x61 && key <= 0x7A)
324 vkey = key - 0x20; /* convert lower to uppercase */
325 else
326 vkey = key;
329 if (event->type == KeyPress)
331 if (vkey == VK_MENU) ALTKeyState = TRUE;
332 if (!(KeyStateTable[vkey] & 0x0f))
333 KeyStateTable[vkey] ^= 0x80;
334 KeyStateTable[vkey] |= 0x01;
335 keylp.lp1.count = 1;
336 keylp.lp1.code = LOBYTE(event->keycode);
337 keylp.lp1.extended = (extended ? 1 : 0);
338 keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0);
339 keylp.lp1.previous = (KeyDown ? 0 : 1);
340 keylp.lp1.transition = 0;
341 dprintf_key(stddeb," wParam=%X, lParam=%lX\n",
342 vkey, keylp.lp2 );
343 dprintf_key(stddeb," KeyState=%X\n", KeyStateTable[vkey]);
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;
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.
355 if (count == 1) /* key has an ASCII representation */
357 dprintf_key(stddeb,"WM_CHAR : wParam=%X\n", (WORD)Str[0] );
358 PostMessage( GetFocus(), WM_CHAR, (WORD)Str[0], keylp.lp2 );
361 else
363 if (vkey == VK_MENU) ALTKeyState = FALSE;
364 KeyStateTable[vkey] &= 0xf0;
365 keylp.lp1.count = 1;
366 keylp.lp1.code = LOBYTE(event->keycode);
367 keylp.lp1.extended = (extended ? 1 : 0);
368 keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0);
369 keylp.lp1.previous = 1;
370 keylp.lp1.transition = 1;
371 dprintf_key(stddeb," wParam=%X, lParam=%lX\n",
372 vkey, keylp.lp2 );
373 dprintf_key(stddeb," KeyState=%X\n", KeyStateTable[vkey]);
374 hardware_event( ((ALTKeyState || vkey == VK_MENU) ?
375 WM_SYSKEYUP : WM_KEYUP),
376 vkey, keylp.lp2,
377 event->x_root - desktopX, event->y_root - desktopY,
378 event->time, 0 );
379 KeyDown = FALSE;
384 /***********************************************************************
385 * EVENT_MotionNotify
387 static void EVENT_MotionNotify( XMotionEvent *event )
389 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
390 event->x_root - desktopX, event->y_root - desktopY,
391 event->time, 0 );
395 /***********************************************************************
396 * EVENT_ButtonPress
398 static void EVENT_ButtonPress( XButtonEvent *event )
400 static WORD messages[NB_BUTTONS] =
401 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
402 int buttonNum = event->button - 1;
404 if (buttonNum >= NB_BUTTONS) return;
405 MouseButtonsStates[buttonNum] = TRUE;
406 AsyncMouseButtonsStates[buttonNum] = TRUE;
407 hardware_event( messages[buttonNum],
408 EVENT_XStateToKeyState( event->state ), 0L,
409 event->x_root - desktopX, event->y_root - desktopY,
410 event->time, 0 );
414 /***********************************************************************
415 * EVENT_ButtonRelease
417 static void EVENT_ButtonRelease( XButtonEvent *event )
419 static const WORD messages[NB_BUTTONS] =
420 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
421 int buttonNum = event->button - 1;
423 if (buttonNum >= NB_BUTTONS) return;
424 MouseButtonsStates[buttonNum] = FALSE;
425 hardware_event( messages[buttonNum],
426 EVENT_XStateToKeyState( event->state ), 0L,
427 event->x_root - desktopX, event->y_root - desktopY,
428 event->time, 0 );
432 /**********************************************************************
433 * EVENT_FocusOut
435 * Note: only top-level override-redirect windows get FocusOut events.
437 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
439 if (event->detail == NotifyPointer) return;
440 if (hwnd == GetActiveWindow()) WINPOS_ChangeActiveWindow( 0, FALSE );
441 if ((hwnd == GetFocus()) || IsChild( hwnd, GetFocus())) SetFocus( 0 );
445 /**********************************************************************
446 * EVENT_ConfigureNotify
448 * The ConfigureNotify event is only selected on the desktop window.
450 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
452 desktopX = event->x;
453 desktopY = event->y;
457 /***********************************************************************
458 * EVENT_SelectionRequest
460 static void EVENT_SelectionRequest( HWND hwnd, XSelectionRequestEvent *event )
462 XSelectionEvent result;
463 Atom rprop;
464 Window request=event->requestor;
465 rprop=None;
466 if(event->target == XA_STRING)
468 HANDLE hText;
469 LPSTR text;
470 rprop=event->property;
471 if(rprop == None)rprop=event->target;
472 if(event->selection!=XA_PRIMARY)rprop=None;
473 else if(!IsClipboardFormatAvailable(CF_TEXT))rprop=None;
474 else{
475 /* Don't worry if we can't open */
476 BOOL couldOpen=OpenClipboard(hwnd);
477 hText=GetClipboardData(CF_TEXT);
478 text=GlobalLock(hText);
479 XChangeProperty(display,request,rprop,XA_STRING,
480 8,PropModeReplace,text,strlen(text));
481 GlobalUnlock(hText);
482 /* close only if we opened before */
483 if(couldOpen)CloseClipboard();
486 if(rprop==None) dprintf_event(stddeb,"Request for %s ignored\n",
487 XGetAtomName(display,event->target));
488 result.type=SelectionNotify;
489 result.display=display;
490 result.requestor=request;
491 result.selection=event->selection;
492 result.property=rprop;
493 result.target=event->target;
494 result.time=event->time;
495 XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
499 /***********************************************************************
500 * EVENT_SelectionNotify
502 static void EVENT_SelectionNotify(HWND hwnd, XSelectionEvent *event)
504 if(event->selection!=XA_PRIMARY)return;
505 if(event->target!=XA_STRING)CLIPBOARD_ReadSelection(0,None);
506 CLIPBOARD_ReadSelection(event->requestor,event->property);
510 /***********************************************************************
511 * EVENT_SelectionClear
513 static void EVENT_SelectionClear(HWND hwnd, XSelectionClearEvent *event)
515 if(event->selection!=XA_PRIMARY)return;
516 CLIPBOARD_ReleaseSelection(hwnd);
519 /**********************************************************************
520 * SetCapture (USER.18)
522 HWND SetCapture( HWND hwnd )
524 Window win;
525 HWND old_capture_wnd = captureWnd;
527 if (!(win = WIN_GetXWindow( hwnd ))) return 0;
528 if (XGrabPointer(display, win, False,
529 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
530 GrabModeAsync, GrabModeAsync,
531 None, None, CurrentTime ) == GrabSuccess)
533 captureWnd = hwnd;
534 return old_capture_wnd;
536 else return 0;
540 /**********************************************************************
541 * ReleaseCapture (USER.19)
543 void ReleaseCapture()
545 if (captureWnd == 0) return;
546 XUngrabPointer( display, CurrentTime );
547 captureWnd = 0;
550 /**********************************************************************
551 * GetCapture (USER.236)
553 HWND GetCapture()
555 return captureWnd;
559 /**********************************************************************
560 * EnableHardwareInput [USER.331]
562 BOOL EnableHardwareInput(BOOL bEnable)
564 BOOL bOldState = InputEnabled;
565 dprintf_event(stdnimp,"EMPTY STUB !!! EnableHardwareInput(%d);\n", bEnable);
566 InputEnabled = bEnable;
567 return (bOldState && !bEnable);