Release 951105
[wine/multimedia.git] / windows / event.c
blob28f21e1f43c14367e8b22867c949c2c629a5251d
1 /*
2 * X events handling functions
3 *
4 * Copyright 1993 Alexandre Julliard
5 *
6 */
8 #include <ctype.h>
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 "registers.h"
23 #include "stackframe.h"
24 #include "stddebug.h"
25 /* #define DEBUG_EVENT */
26 /* #define DEBUG_KEY */
27 #include "debug.h"
30 #ifdef ndef
31 #ifndef FamilyAmoeba
32 typedef char *XPointer;
33 #endif
34 #endif
36 #ifdef WHO_NEEDS_DIRTY_HACKS
37 #ifdef sparc
38 /* Dirty hack to compile with Sun's OpenWindows */
39 typedef char *XPointer;
40 #endif
41 #endif
43 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
45 /* X context to associate a hwnd to an X window */
46 static XContext winContext = 0;
48 /* State variables */
49 BOOL MouseButtonsStates[NB_BUTTONS] = { FALSE, FALSE, FALSE };
50 BOOL AsyncMouseButtonsStates[NB_BUTTONS] = { FALSE, FALSE, FALSE };
51 BYTE KeyStateTable[256];
52 BYTE AsyncKeyStateTable[256];
53 static WORD ALTKeyState;
54 static HWND captureWnd = 0;
55 static BOOL InputEnabled = TRUE;
57 /* Keyboard translation tables */
58 static int special_key[] =
60 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
61 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
62 0, 0, 0, VK_ESCAPE /* FF18 */
65 static cursor_key[] =
67 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR,
68 VK_NEXT, VK_END /* FF50 */
71 static misc_key[] =
73 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
74 VK_CANCEL, VK_HELP, VK_CANCEL, VK_MENU /* FF68 */
77 static keypad_key[] =
79 VK_MENU, VK_NUMLOCK, /* FF7E */
80 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
81 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
82 0, 0, 0, 0, 0, 0, 0, 0, /* FF90 */
83 0, 0, 0, 0, 0, 0, 0, 0, /* FF98 */
84 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
85 0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT,
86 VK_DECIMAL, VK_DIVIDE, /* FFA8 */
87 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
88 VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
89 VK_NUMPAD8, VK_NUMPAD9 /* FFB8 */
92 static function_key[] =
94 VK_F1, VK_F2, /* FFBE */
95 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
96 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16 /* FFC8 */
99 static modifier_key[] =
101 VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL,
102 0, 0, /* FFE1 */
103 0, VK_MENU, VK_MENU /* FFE8 */
106 typedef union
108 struct
110 unsigned long count : 16;
111 unsigned long code : 8;
112 unsigned long extended : 1;
113 unsigned long : 4;
114 unsigned long context : 1;
115 unsigned long previous : 1;
116 unsigned long transition : 1;
117 } lp1;
118 unsigned long lp2;
119 } KEYLP;
121 static BOOL KeyDown = FALSE;
123 static const char *event_names[] =
125 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
126 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
127 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
128 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
129 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
130 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
131 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
132 "ClientMessage", "MappingNotify"
135 /* Event handlers */
136 static void EVENT_key( XKeyEvent *event );
137 static void EVENT_ButtonPress( XButtonEvent *event );
138 static void EVENT_ButtonRelease( XButtonEvent *event );
139 static void EVENT_MotionNotify( XMotionEvent *event );
140 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event );
141 static void EVENT_Expose( HWND hwnd, XExposeEvent *event );
142 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
143 static void EVENT_SelectionRequest( HWND hwnd, XSelectionRequestEvent *event);
144 static void EVENT_SelectionNotify( HWND hwnd, XSelectionEvent *event);
145 static void EVENT_SelectionClear( HWND hwnd, XSelectionClearEvent *event);
148 /***********************************************************************
149 * EVENT_ProcessEvent
151 * Process an X event.
153 void EVENT_ProcessEvent( XEvent *event )
155 HWND hwnd;
156 XPointer ptr;
158 XFindContext( display, ((XAnyEvent *)event)->window, winContext, &ptr );
159 hwnd = (HWND) (int)ptr;
161 dprintf_event(stddeb, "Got event %s for hwnd "NPFMT"\n",
162 event_names[event->type], hwnd );
164 switch(event->type)
166 case KeyPress:
167 case KeyRelease:
168 EVENT_key( (XKeyEvent*)event );
169 break;
171 case ButtonPress:
172 EVENT_ButtonPress( (XButtonEvent*)event );
173 break;
175 case ButtonRelease:
176 EVENT_ButtonRelease( (XButtonEvent*)event );
177 break;
179 case MotionNotify:
180 /* Wine between two fast machines across the overloaded campus
181 ethernet gets very boged down in MotionEvents. The following
182 simply finds the last motion event in the queue and drops
183 the rest. On a good link events are servered before they build
184 up so this doesn't take place. On a slow link this may cause
185 problems if the event order is important. I'm not yet seen
186 of any problems. Jon 7/6/96.
188 while (XCheckTypedWindowEvent(display, ((XAnyEvent *)event)->window,
189 MotionNotify, event));
190 EVENT_MotionNotify( (XMotionEvent*)event );
191 break;
193 case FocusOut:
194 EVENT_FocusOut( hwnd, (XFocusChangeEvent*)event );
195 break;
197 case Expose:
198 EVENT_Expose( hwnd, (XExposeEvent*)event );
199 break;
201 case ConfigureNotify:
202 EVENT_ConfigureNotify( hwnd, (XConfigureEvent*)event );
203 break;
205 case SelectionRequest:
206 EVENT_SelectionRequest( hwnd, (XSelectionRequestEvent*)event );
207 break;
209 case SelectionNotify:
210 EVENT_SelectionNotify( hwnd, (XSelectionEvent*)event );
211 break;
213 case SelectionClear:
214 EVENT_SelectionClear( hwnd, (XSelectionClearEvent*) event );
215 break;
217 default:
218 dprintf_event(stddeb, "Unprocessed event %s for hwnd "NPFMT"\n",
219 event_names[event->type], hwnd );
220 break;
225 /***********************************************************************
226 * EVENT_RegisterWindow
228 * Associate an X window to a HWND.
230 void EVENT_RegisterWindow( Window w, HWND hwnd )
232 if (!winContext) winContext = XUniqueContext();
233 XSaveContext( display, w, winContext, (XPointer)(int)hwnd );
237 /***********************************************************************
238 * EVENT_XStateToKeyState
240 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
241 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
243 static WORD EVENT_XStateToKeyState( int state )
245 int kstate = 0;
247 if (state & Button1Mask) kstate |= MK_LBUTTON;
248 if (state & Button2Mask) kstate |= MK_MBUTTON;
249 if (state & Button3Mask) kstate |= MK_RBUTTON;
250 if (state & ShiftMask) kstate |= MK_SHIFT;
251 if (state & ControlMask) kstate |= MK_CONTROL;
252 return kstate;
256 /***********************************************************************
257 * EVENT_Expose
259 static void EVENT_Expose( HWND hwnd, XExposeEvent *event )
261 RECT rect;
262 WND * wndPtr = WIN_FindWndPtr( hwnd );
263 if (!wndPtr) return;
265 /* Make position relative to client area instead of window */
266 rect.left = event->x - (wndPtr->rectClient.left - wndPtr->rectWindow.left);
267 rect.top = event->y - (wndPtr->rectClient.top - wndPtr->rectWindow.top);
268 rect.right = rect.left + event->width;
269 rect.bottom = rect.top + event->height;
271 RedrawWindow( hwnd, &rect, 0,
272 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
273 (event->count ? 0 : RDW_ERASENOW) );
277 /***********************************************************************
278 * EVENT_key
280 * Handle a X key event
282 static void EVENT_key( XKeyEvent *event )
284 char Str[24];
285 XComposeStatus cs;
286 KeySym keysym;
287 WORD vkey = 0;
288 WORD xkey, key_type, key;
289 KEYLP keylp;
290 BOOL extended = FALSE;
292 int count = XLookupString(event, Str, 1, &keysym, &cs);
293 Str[count] = '\0';
294 dprintf_key(stddeb,"WM_KEY??? : keysym=%lX, count=%u / %X / '%s'\n",
295 keysym, count, Str[0], Str);
297 xkey = LOWORD(keysym);
298 key_type = HIBYTE(xkey);
299 key = LOBYTE(xkey);
300 dprintf_key(stddeb," key_type=%X, key=%X\n", key_type, key);
302 if (key_type == 0xFF) /* non-character key */
304 if (key >= 0x08 && key <= 0x1B) /* special key */
305 vkey = special_key[key - 0x08];
306 else if (key >= 0x50 && key <= 0x57) /* cursor key */
307 vkey = cursor_key[key - 0x50];
308 else if (key >= 0x60 && key <= 0x6B) /* miscellaneous key */
309 vkey = misc_key[key - 0x60];
310 else if (key >= 0x7E && key <= 0xB9) /* keypad key */
312 vkey = keypad_key[key - 0x7E];
313 extended = TRUE;
315 else if (key >= 0xBE && key <= 0xCD) /* function key */
317 vkey = function_key[key - 0xBE];
318 extended = TRUE;
320 else if (key >= 0xE1 && key <= 0xEA) /* modifier key */
321 vkey = modifier_key[key - 0xE1];
322 else if (key == 0xFF) /* DEL key */
323 vkey = VK_DELETE;
325 else if (key_type == 0) /* character key */
327 if (isalnum(key))
328 vkey = toupper(key); /* convert lower to uppercase */
329 else
330 vkey = 0xbe;
333 if (event->type == KeyPress)
335 if (vkey == VK_MENU) ALTKeyState = TRUE;
336 if (!(KeyStateTable[vkey] & 0x0f))
337 KeyStateTable[vkey] ^= 0x80;
338 KeyStateTable[vkey] |= 0x01;
339 keylp.lp1.count = 1;
340 keylp.lp1.code = LOBYTE(event->keycode);
341 keylp.lp1.extended = (extended ? 1 : 0);
342 keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0);
343 keylp.lp1.previous = (KeyDown ? 0 : 1);
344 keylp.lp1.transition = 0;
345 dprintf_key(stddeb," wParam=%X, lParam=%lX\n",
346 vkey, keylp.lp2 );
347 dprintf_key(stddeb," KeyState=%X\n", KeyStateTable[vkey]);
348 hardware_event( ALTKeyState ? WM_SYSKEYDOWN : WM_KEYDOWN,
349 vkey, keylp.lp2,
350 event->x_root - desktopX, event->y_root - desktopY,
351 event->time, 0 );
352 KeyDown = TRUE;
354 /* The key translation ought to take place in TranslateMessage().
355 * However, there is no way of passing the required information
356 * in a Windows message, so TranslateMessage does not currently
357 * do anything and the translation is done here.
359 if (count == 1) /* key has an ASCII representation */
361 dprintf_key(stddeb,"WM_CHAR : wParam=%X\n", (WORD)Str[0] );
362 PostMessage( GetFocus(), WM_CHAR, (WORD)(unsigned char)(Str[0]),
363 keylp.lp2 );
366 else
368 if (vkey == VK_MENU) ALTKeyState = FALSE;
369 KeyStateTable[vkey] &= 0xf0;
370 keylp.lp1.count = 1;
371 keylp.lp1.code = LOBYTE(event->keycode);
372 keylp.lp1.extended = (extended ? 1 : 0);
373 keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0);
374 keylp.lp1.previous = 1;
375 keylp.lp1.transition = 1;
376 dprintf_key(stddeb," wParam=%X, lParam=%lX\n",
377 vkey, keylp.lp2 );
378 dprintf_key(stddeb," KeyState=%X\n", KeyStateTable[vkey]);
379 hardware_event( ((ALTKeyState || vkey == VK_MENU) ?
380 WM_SYSKEYUP : WM_KEYUP),
381 vkey, keylp.lp2,
382 event->x_root - desktopX, event->y_root - desktopY,
383 event->time, 0 );
384 KeyDown = FALSE;
389 /***********************************************************************
390 * EVENT_MotionNotify
392 static void EVENT_MotionNotify( XMotionEvent *event )
394 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
395 event->x_root - desktopX, event->y_root - desktopY,
396 event->time, 0 );
400 /***********************************************************************
401 * EVENT_DummyMotionNotify
403 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
405 void EVENT_DummyMotionNotify(void)
407 Window root, child;
408 int rootX, rootY, childX, childY;
409 unsigned int state;
411 if (XQueryPointer( display, rootWindow, &root, &child,
412 &rootX, &rootY, &childX, &childY, &state ))
414 hardware_event(WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
415 rootX - desktopX, rootY - desktopY, GetTickCount(), 0 );
420 /***********************************************************************
421 * EVENT_ButtonPress
423 static void EVENT_ButtonPress( XButtonEvent *event )
425 static WORD messages[NB_BUTTONS] =
426 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
427 int buttonNum = event->button - 1;
429 if (buttonNum >= NB_BUTTONS) return;
430 MouseButtonsStates[buttonNum] = TRUE;
431 AsyncMouseButtonsStates[buttonNum] = TRUE;
432 hardware_event( messages[buttonNum],
433 EVENT_XStateToKeyState( event->state ), 0L,
434 event->x_root - desktopX, event->y_root - desktopY,
435 event->time, 0 );
439 /***********************************************************************
440 * EVENT_ButtonRelease
442 static void EVENT_ButtonRelease( XButtonEvent *event )
444 static const WORD messages[NB_BUTTONS] =
445 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
446 int buttonNum = event->button - 1;
448 if (buttonNum >= NB_BUTTONS) return;
449 MouseButtonsStates[buttonNum] = FALSE;
450 hardware_event( messages[buttonNum],
451 EVENT_XStateToKeyState( event->state ), 0L,
452 event->x_root - desktopX, event->y_root - desktopY,
453 event->time, 0 );
457 /**********************************************************************
458 * EVENT_FocusOut
460 * Note: only top-level override-redirect windows get FocusOut events.
462 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
464 if (event->detail == NotifyPointer) return;
465 if (hwnd == GetActiveWindow()) WINPOS_ChangeActiveWindow( 0, FALSE );
466 if ((hwnd == GetFocus()) || IsChild( hwnd, GetFocus())) SetFocus( 0 );
470 /**********************************************************************
471 * EVENT_ConfigureNotify
473 * The ConfigureNotify event is only selected on the desktop window.
475 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
477 desktopX = event->x;
478 desktopY = event->y;
482 /***********************************************************************
483 * EVENT_SelectionRequest
485 static void EVENT_SelectionRequest( HWND hwnd, XSelectionRequestEvent *event )
487 XSelectionEvent result;
488 Atom rprop;
489 Window request=event->requestor;
490 rprop=None;
491 if(event->target == XA_STRING)
493 HANDLE hText;
494 LPSTR text;
495 rprop=event->property;
496 if(rprop == None)rprop=event->target;
497 if(event->selection!=XA_PRIMARY)rprop=None;
498 else if(!IsClipboardFormatAvailable(CF_TEXT))rprop=None;
499 else{
500 /* Don't worry if we can't open */
501 BOOL couldOpen=OpenClipboard(hwnd);
502 hText=GetClipboardData(CF_TEXT);
503 text=GlobalLock(hText);
504 XChangeProperty(display,request,rprop,XA_STRING,
505 8,PropModeReplace,text,strlen(text));
506 GlobalUnlock(hText);
507 /* close only if we opened before */
508 if(couldOpen)CloseClipboard();
511 if(rprop==None) dprintf_event(stddeb,"Request for %s ignored\n",
512 XGetAtomName(display,event->target));
513 result.type=SelectionNotify;
514 result.display=display;
515 result.requestor=request;
516 result.selection=event->selection;
517 result.property=rprop;
518 result.target=event->target;
519 result.time=event->time;
520 XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
524 /***********************************************************************
525 * EVENT_SelectionNotify
527 static void EVENT_SelectionNotify(HWND hwnd, XSelectionEvent *event)
529 if(event->selection!=XA_PRIMARY)return;
530 if(event->target!=XA_STRING)CLIPBOARD_ReadSelection(0,None);
531 CLIPBOARD_ReadSelection(event->requestor,event->property);
535 /***********************************************************************
536 * EVENT_SelectionClear
538 static void EVENT_SelectionClear(HWND hwnd, XSelectionClearEvent *event)
540 if(event->selection!=XA_PRIMARY)return;
541 CLIPBOARD_ReleaseSelection(hwnd);
544 /**********************************************************************
545 * SetCapture (USER.18)
547 HWND SetCapture( HWND hwnd )
549 Window win;
550 HWND old_capture_wnd = captureWnd;
552 if (!hwnd)
554 ReleaseCapture();
555 return old_capture_wnd;
557 if (!(win = WIN_GetXWindow( hwnd ))) return 0;
558 if (XGrabPointer(display, win, False,
559 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
560 GrabModeAsync, GrabModeAsync,
561 None, None, CurrentTime ) == GrabSuccess)
563 dprintf_win(stddeb, "SetCapture: "NPFMT"\n", hwnd);
564 captureWnd = hwnd;
565 return old_capture_wnd;
567 else return 0;
571 /**********************************************************************
572 * ReleaseCapture (USER.19)
574 void ReleaseCapture()
576 if (captureWnd == 0) return;
577 XUngrabPointer( display, CurrentTime );
578 captureWnd = 0;
579 dprintf_win(stddeb, "ReleaseCapture\n");
582 /**********************************************************************
583 * GetCapture (USER.236)
585 HWND GetCapture()
587 return captureWnd;
591 /***********************************************************************
592 * GetMouseEventProc (USER.337)
594 FARPROC GetMouseEventProc(void)
596 char name[] = "Mouse_Event";
597 return GetProcAddress( GetModuleHandle("USER"), MAKE_SEGPTR(name) );
601 /***********************************************************************
602 * Mouse_Event (USER.299)
604 #ifndef WINELIB
605 void Mouse_Event( struct sigcontext_struct context )
607 /* Register values:
608 * AX = mouse event
609 * BX = horizontal displacement if AX & ME_MOVE
610 * CX = vertical displacement if AX & ME_MOVE
611 * DX = button state (?)
612 * SI = mouse event flags (?)
614 Window root, child;
615 int rootX, rootY, childX, childY;
616 unsigned int state;
618 if (AX_reg(&context) & ME_MOVE)
620 /* We have to actually move the cursor */
621 XWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
622 (short)BX_reg(&context), (short)CX_reg(&context) );
623 return;
625 if (!XQueryPointer( display, rootWindow, &root, &child,
626 &rootX, &rootY, &childX, &childY, &state )) return;
627 if (AX_reg(&context) & ME_LDOWN)
628 hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
629 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
630 if (AX_reg(&context) & ME_LUP)
631 hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
632 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
633 if (AX_reg(&context) & ME_RDOWN)
634 hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
635 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
636 if (AX_reg(&context) & ME_RUP)
637 hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
638 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
640 #endif
643 /**********************************************************************
644 * EnableHardwareInput [USER.331]
646 BOOL EnableHardwareInput(BOOL bEnable)
648 BOOL bOldState = InputEnabled;
649 dprintf_event(stdnimp,"EMPTY STUB !!! EnableHardwareInput(%d);\n", bEnable);
650 InputEnabled = bEnable;
651 return (bOldState && !bEnable);