Release 951003
[wine/hacks.git] / windows / event.c
bloba91d24832e36f4be64531685c5033d74835efc0d
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 "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 WHO_NEEDS_DIRTY_HACKS
35 #ifdef sparc
36 /* Dirty hack to compile with Sun's OpenWindows */
37 typedef char *XPointer;
38 #endif
39 #endif
41 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
43 /* X context to associate a hwnd to an X window */
44 static XContext winContext = 0;
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;
55 /* Keyboard translation tables */
56 static int special_key[] =
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 */
63 static cursor_key[] =
65 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR,
66 VK_NEXT, VK_END /* FF50 */
69 static misc_key[] =
71 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
72 VK_CANCEL, VK_HELP, VK_CANCEL, VK_MENU /* FF68 */
75 static keypad_key[] =
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 */
90 static function_key[] =
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 */
97 static modifier_key[] =
99 VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL,
100 0, 0, /* FFE1 */
101 0, VK_MENU, VK_MENU /* FFE8 */
104 typedef union
106 struct
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;
119 static BOOL KeyDown = FALSE;
121 static const char *event_names[] =
123 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
124 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
125 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
126 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
127 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
128 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
129 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
130 "ClientMessage", "MappingNotify"
133 /* Event handlers */
134 static void EVENT_key( XKeyEvent *event );
135 static void EVENT_ButtonPress( XButtonEvent *event );
136 static void EVENT_ButtonRelease( XButtonEvent *event );
137 static void EVENT_MotionNotify( XMotionEvent *event );
138 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event );
139 static void EVENT_Expose( HWND hwnd, XExposeEvent *event );
140 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
141 static void EVENT_SelectionRequest( HWND hwnd, XSelectionRequestEvent *event);
142 static void EVENT_SelectionNotify( HWND hwnd, XSelectionEvent *event);
143 static void EVENT_SelectionClear( HWND hwnd, XSelectionClearEvent *event);
146 /***********************************************************************
147 * EVENT_ProcessEvent
149 * Process an X event.
151 void EVENT_ProcessEvent( XEvent *event )
153 HWND hwnd;
154 XPointer ptr;
156 XFindContext( display, ((XAnyEvent *)event)->window, winContext, &ptr );
157 hwnd = (HWND) (int)ptr;
159 dprintf_event(stddeb, "Got event %s for hwnd "NPFMT"\n",
160 event_names[event->type], hwnd );
162 switch(event->type)
164 case KeyPress:
165 case KeyRelease:
166 EVENT_key( (XKeyEvent*)event );
167 break;
169 case ButtonPress:
170 EVENT_ButtonPress( (XButtonEvent*)event );
171 break;
173 case ButtonRelease:
174 EVENT_ButtonRelease( (XButtonEvent*)event );
175 break;
177 case MotionNotify:
178 /* Wine between two fast machines across the overloaded campus
179 ethernet gets very boged down in MotionEvents. The following
180 simply finds the last motion event in the queue and drops
181 the rest. On a good link events are servered before they build
182 up so this doesn't take place. On a slow link this may cause
183 problems if the event order is important. I'm not yet seen
184 of any problems. Jon 7/6/96.
186 while (XCheckTypedWindowEvent(display, ((XAnyEvent *)event)->window,
187 MotionNotify, event));
188 EVENT_MotionNotify( (XMotionEvent*)event );
189 break;
191 case FocusOut:
192 EVENT_FocusOut( hwnd, (XFocusChangeEvent*)event );
193 break;
195 case Expose:
196 EVENT_Expose( hwnd, (XExposeEvent*)event );
197 break;
199 case ConfigureNotify:
200 EVENT_ConfigureNotify( hwnd, (XConfigureEvent*)event );
201 break;
203 case SelectionRequest:
204 EVENT_SelectionRequest( hwnd, (XSelectionRequestEvent*)event );
205 break;
207 case SelectionNotify:
208 EVENT_SelectionNotify( hwnd, (XSelectionEvent*)event );
209 break;
211 case SelectionClear:
212 EVENT_SelectionClear( hwnd, (XSelectionClearEvent*) event );
213 break;
215 default:
216 dprintf_event(stddeb, "Unprocessed event %s for hwnd "NPFMT"\n",
217 event_names[event->type], hwnd );
218 break;
223 /***********************************************************************
224 * EVENT_RegisterWindow
226 * Associate an X window to a HWND.
228 void EVENT_RegisterWindow( Window w, HWND hwnd )
230 if (!winContext) winContext = XUniqueContext();
231 XSaveContext( display, w, winContext, (XPointer)(int)hwnd );
235 /***********************************************************************
236 * EVENT_XStateToKeyState
238 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
239 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
241 static WORD EVENT_XStateToKeyState( int state )
243 int kstate = 0;
245 if (state & Button1Mask) kstate |= MK_LBUTTON;
246 if (state & Button2Mask) kstate |= MK_MBUTTON;
247 if (state & Button3Mask) kstate |= MK_RBUTTON;
248 if (state & ShiftMask) kstate |= MK_SHIFT;
249 if (state & ControlMask) kstate |= MK_CONTROL;
250 return kstate;
254 /***********************************************************************
255 * EVENT_Expose
257 static void EVENT_Expose( HWND hwnd, XExposeEvent *event )
259 RECT rect;
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 RedrawWindow( hwnd, &rect, 0,
270 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
271 (event->count ? 0 : RDW_ERASENOW) );
275 /***********************************************************************
276 * EVENT_key
278 * Handle a X key event
280 static void EVENT_key( XKeyEvent *event )
282 char Str[24];
283 XComposeStatus cs;
284 KeySym keysym;
285 WORD vkey = 0;
286 WORD xkey, 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 (isalnum(key))
326 vkey = toupper(key); /* convert lower to uppercase */
327 else
328 vkey = 0xbe;
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)(unsigned char)(Str[0]),
361 keylp.lp2 );
364 else
366 if (vkey == VK_MENU) ALTKeyState = FALSE;
367 KeyStateTable[vkey] &= 0xf0;
368 keylp.lp1.count = 1;
369 keylp.lp1.code = LOBYTE(event->keycode);
370 keylp.lp1.extended = (extended ? 1 : 0);
371 keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0);
372 keylp.lp1.previous = 1;
373 keylp.lp1.transition = 1;
374 dprintf_key(stddeb," wParam=%X, lParam=%lX\n",
375 vkey, keylp.lp2 );
376 dprintf_key(stddeb," KeyState=%X\n", KeyStateTable[vkey]);
377 hardware_event( ((ALTKeyState || vkey == VK_MENU) ?
378 WM_SYSKEYUP : WM_KEYUP),
379 vkey, keylp.lp2,
380 event->x_root - desktopX, event->y_root - desktopY,
381 event->time, 0 );
382 KeyDown = FALSE;
387 /***********************************************************************
388 * EVENT_MotionNotify
390 static void EVENT_MotionNotify( XMotionEvent *event )
392 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
393 event->x_root - desktopX, event->y_root - desktopY,
394 event->time, 0 );
398 /***********************************************************************
399 * EVENT_DummyMotionNotify
401 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
403 void EVENT_DummyMotionNotify(void)
405 Window root, child;
406 int rootX, rootY, childX, childY;
407 unsigned int state;
409 if (XQueryPointer( display, rootWindow, &root, &child,
410 &rootX, &rootY, &childX, &childY, &state ))
412 hardware_event(WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
413 rootX - desktopX, rootY - desktopY, GetTickCount(), 0 );
418 /***********************************************************************
419 * EVENT_ButtonPress
421 static void EVENT_ButtonPress( XButtonEvent *event )
423 static WORD messages[NB_BUTTONS] =
424 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
425 int buttonNum = event->button - 1;
427 if (buttonNum >= NB_BUTTONS) return;
428 MouseButtonsStates[buttonNum] = TRUE;
429 AsyncMouseButtonsStates[buttonNum] = TRUE;
430 hardware_event( messages[buttonNum],
431 EVENT_XStateToKeyState( event->state ), 0L,
432 event->x_root - desktopX, event->y_root - desktopY,
433 event->time, 0 );
437 /***********************************************************************
438 * EVENT_ButtonRelease
440 static void EVENT_ButtonRelease( XButtonEvent *event )
442 static const WORD messages[NB_BUTTONS] =
443 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
444 int buttonNum = event->button - 1;
446 if (buttonNum >= NB_BUTTONS) return;
447 MouseButtonsStates[buttonNum] = FALSE;
448 hardware_event( messages[buttonNum],
449 EVENT_XStateToKeyState( event->state ), 0L,
450 event->x_root - desktopX, event->y_root - desktopY,
451 event->time, 0 );
455 /**********************************************************************
456 * EVENT_FocusOut
458 * Note: only top-level override-redirect windows get FocusOut events.
460 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
462 if (event->detail == NotifyPointer) return;
463 if (hwnd == GetActiveWindow()) WINPOS_ChangeActiveWindow( 0, FALSE );
464 if ((hwnd == GetFocus()) || IsChild( hwnd, GetFocus())) SetFocus( 0 );
468 /**********************************************************************
469 * EVENT_ConfigureNotify
471 * The ConfigureNotify event is only selected on the desktop window.
473 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
475 desktopX = event->x;
476 desktopY = event->y;
480 /***********************************************************************
481 * EVENT_SelectionRequest
483 static void EVENT_SelectionRequest( HWND hwnd, XSelectionRequestEvent *event )
485 XSelectionEvent result;
486 Atom rprop;
487 Window request=event->requestor;
488 rprop=None;
489 if(event->target == XA_STRING)
491 HANDLE hText;
492 LPSTR text;
493 rprop=event->property;
494 if(rprop == None)rprop=event->target;
495 if(event->selection!=XA_PRIMARY)rprop=None;
496 else if(!IsClipboardFormatAvailable(CF_TEXT))rprop=None;
497 else{
498 /* Don't worry if we can't open */
499 BOOL couldOpen=OpenClipboard(hwnd);
500 hText=GetClipboardData(CF_TEXT);
501 text=GlobalLock(hText);
502 XChangeProperty(display,request,rprop,XA_STRING,
503 8,PropModeReplace,text,strlen(text));
504 GlobalUnlock(hText);
505 /* close only if we opened before */
506 if(couldOpen)CloseClipboard();
509 if(rprop==None) dprintf_event(stddeb,"Request for %s ignored\n",
510 XGetAtomName(display,event->target));
511 result.type=SelectionNotify;
512 result.display=display;
513 result.requestor=request;
514 result.selection=event->selection;
515 result.property=rprop;
516 result.target=event->target;
517 result.time=event->time;
518 XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
522 /***********************************************************************
523 * EVENT_SelectionNotify
525 static void EVENT_SelectionNotify(HWND hwnd, XSelectionEvent *event)
527 if(event->selection!=XA_PRIMARY)return;
528 if(event->target!=XA_STRING)CLIPBOARD_ReadSelection(0,None);
529 CLIPBOARD_ReadSelection(event->requestor,event->property);
533 /***********************************************************************
534 * EVENT_SelectionClear
536 static void EVENT_SelectionClear(HWND hwnd, XSelectionClearEvent *event)
538 if(event->selection!=XA_PRIMARY)return;
539 CLIPBOARD_ReleaseSelection(hwnd);
542 /**********************************************************************
543 * SetCapture (USER.18)
545 HWND SetCapture( HWND hwnd )
547 Window win;
548 HWND old_capture_wnd = captureWnd;
550 if (!hwnd)
552 ReleaseCapture();
553 return old_capture_wnd;
555 if (!(win = WIN_GetXWindow( hwnd ))) return 0;
556 if (XGrabPointer(display, win, False,
557 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
558 GrabModeAsync, GrabModeAsync,
559 None, None, CurrentTime ) == GrabSuccess)
561 dprintf_win(stddeb, "SetCapture: "NPFMT"\n", hwnd);
562 captureWnd = hwnd;
563 return old_capture_wnd;
565 else return 0;
569 /**********************************************************************
570 * ReleaseCapture (USER.19)
572 void ReleaseCapture()
574 if (captureWnd == 0) return;
575 XUngrabPointer( display, CurrentTime );
576 captureWnd = 0;
577 dprintf_win(stddeb, "ReleaseCapture\n");
580 /**********************************************************************
581 * GetCapture (USER.236)
583 HWND GetCapture()
585 return captureWnd;
589 /**********************************************************************
590 * EnableHardwareInput [USER.331]
592 BOOL EnableHardwareInput(BOOL bEnable)
594 BOOL bOldState = InputEnabled;
595 dprintf_event(stdnimp,"EMPTY STUB !!! EnableHardwareInput(%d);\n", bEnable);
596 InputEnabled = bEnable;
597 return (bOldState && !bEnable);