Release 950522
[wine.git] / windows / event.c
blob05c21ce2a59d2d32aed1f50b4164909942035c18
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;
122 static char *event_names[] =
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"
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);
147 /***********************************************************************
148 * EVENT_ProcessEvent
150 * Process an X event.
152 void EVENT_ProcessEvent( XEvent *event )
154 HWND hwnd;
155 XPointer ptr;
157 XFindContext( display, ((XAnyEvent *)event)->window, winContext, &ptr );
158 hwnd = (HWND) (int)ptr;
160 dprintf_event(stddeb, "Got event %s for hwnd %d\n",
161 event_names[event->type], hwnd );
163 switch(event->type)
165 case KeyPress:
166 case KeyRelease:
167 EVENT_key( (XKeyEvent*)event );
168 break;
170 case ButtonPress:
171 EVENT_ButtonPress( (XButtonEvent*)event );
172 break;
174 case ButtonRelease:
175 EVENT_ButtonRelease( (XButtonEvent*)event );
176 break;
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.
187 while (XCheckTypedWindowEvent(display, ((XAnyEvent *)event)->window,
188 MotionNotify, event));
189 EVENT_MotionNotify( (XMotionEvent*)event );
190 break;
192 case FocusOut:
193 EVENT_FocusOut( hwnd, (XFocusChangeEvent*)event );
194 break;
196 case Expose:
197 EVENT_Expose( hwnd, (XExposeEvent*)event );
198 break;
200 case ConfigureNotify:
201 EVENT_ConfigureNotify( hwnd, (XConfigureEvent*)event );
202 break;
204 case SelectionRequest:
205 EVENT_SelectionRequest( hwnd, (XSelectionRequestEvent*)event );
206 break;
208 case SelectionNotify:
209 EVENT_SelectionNotify( hwnd, (XSelectionEvent*)event );
210 break;
212 case SelectionClear:
213 EVENT_SelectionClear( hwnd, (XSelectionClearEvent*) event );
214 break;
216 default:
217 dprintf_event(stddeb, "Unprocessed event %s for hwnd %d\n",
218 event_names[event->type], hwnd );
219 break;
224 /***********************************************************************
225 * EVENT_RegisterWindow
227 * Associate an X window to a HWND.
229 void EVENT_RegisterWindow( Window w, HWND hwnd )
231 if (!winContext) winContext = XUniqueContext();
232 XSaveContext( display, w, winContext, (XPointer)(int)hwnd );
236 /***********************************************************************
237 * EVENT_XStateToKeyState
239 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
240 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
242 static WORD EVENT_XStateToKeyState( int state )
244 int kstate = 0;
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;
255 /***********************************************************************
256 * EVENT_Expose
258 static void EVENT_Expose( HWND hwnd, XExposeEvent *event )
260 RECT rect;
261 WND * wndPtr = WIN_FindWndPtr( hwnd );
262 if (!wndPtr) return;
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;
270 RedrawWindow( hwnd, &rect, 0,
271 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
272 (event->count ? 0 : RDW_ERASENOW) );
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 (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_ButtonPress
401 static void EVENT_ButtonPress( XButtonEvent *event )
403 static WORD messages[NB_BUTTONS] =
404 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
405 int buttonNum = event->button - 1;
407 if (buttonNum >= NB_BUTTONS) return;
408 MouseButtonsStates[buttonNum] = TRUE;
409 AsyncMouseButtonsStates[buttonNum] = TRUE;
410 hardware_event( messages[buttonNum],
411 EVENT_XStateToKeyState( event->state ), 0L,
412 event->x_root - desktopX, event->y_root - desktopY,
413 event->time, 0 );
417 /***********************************************************************
418 * EVENT_ButtonRelease
420 static void EVENT_ButtonRelease( XButtonEvent *event )
422 static const WORD messages[NB_BUTTONS] =
423 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
424 int buttonNum = event->button - 1;
426 if (buttonNum >= NB_BUTTONS) return;
427 MouseButtonsStates[buttonNum] = FALSE;
428 hardware_event( messages[buttonNum],
429 EVENT_XStateToKeyState( event->state ), 0L,
430 event->x_root - desktopX, event->y_root - desktopY,
431 event->time, 0 );
435 /**********************************************************************
436 * EVENT_FocusOut
438 * Note: only top-level override-redirect windows get FocusOut events.
440 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
442 if (event->detail == NotifyPointer) return;
443 if (hwnd == GetActiveWindow()) WINPOS_ChangeActiveWindow( 0, FALSE );
444 if ((hwnd == GetFocus()) || IsChild( hwnd, GetFocus())) SetFocus( 0 );
448 /**********************************************************************
449 * EVENT_ConfigureNotify
451 * The ConfigureNotify event is only selected on the desktop window.
453 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
455 desktopX = event->x;
456 desktopY = event->y;
460 /***********************************************************************
461 * EVENT_SelectionRequest
463 static void EVENT_SelectionRequest( HWND hwnd, XSelectionRequestEvent *event )
465 XSelectionEvent result;
466 Atom rprop;
467 Window request=event->requestor;
468 rprop=None;
469 if(event->target == XA_STRING)
471 HANDLE hText;
472 LPSTR text;
473 rprop=event->property;
474 if(rprop == None)rprop=event->target;
475 if(event->selection!=XA_PRIMARY)rprop=None;
476 else if(!IsClipboardFormatAvailable(CF_TEXT))rprop=None;
477 else{
478 /* Don't worry if we can't open */
479 BOOL couldOpen=OpenClipboard(hwnd);
480 hText=GetClipboardData(CF_TEXT);
481 text=GlobalLock(hText);
482 XChangeProperty(display,request,rprop,XA_STRING,
483 8,PropModeReplace,text,strlen(text));
484 GlobalUnlock(hText);
485 /* close only if we opened before */
486 if(couldOpen)CloseClipboard();
489 if(rprop==None) dprintf_event(stddeb,"Request for %s ignored\n",
490 XGetAtomName(display,event->target));
491 result.type=SelectionNotify;
492 result.display=display;
493 result.requestor=request;
494 result.selection=event->selection;
495 result.property=rprop;
496 result.target=event->target;
497 result.time=event->time;
498 XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
502 /***********************************************************************
503 * EVENT_SelectionNotify
505 static void EVENT_SelectionNotify(HWND hwnd, XSelectionEvent *event)
507 if(event->selection!=XA_PRIMARY)return;
508 if(event->target!=XA_STRING)CLIPBOARD_ReadSelection(0,None);
509 CLIPBOARD_ReadSelection(event->requestor,event->property);
513 /***********************************************************************
514 * EVENT_SelectionClear
516 static void EVENT_SelectionClear(HWND hwnd, XSelectionClearEvent *event)
518 if(event->selection!=XA_PRIMARY)return;
519 CLIPBOARD_ReleaseSelection(hwnd);
522 /**********************************************************************
523 * SetCapture (USER.18)
525 HWND SetCapture( HWND hwnd )
527 Window win;
528 HWND old_capture_wnd = captureWnd;
530 if (!hwnd)
532 ReleaseCapture();
533 return old_capture_wnd;
535 if (!(win = WIN_GetXWindow( hwnd ))) return 0;
536 if (XGrabPointer(display, win, False,
537 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
538 GrabModeAsync, GrabModeAsync,
539 None, None, CurrentTime ) == GrabSuccess)
541 captureWnd = hwnd;
542 return old_capture_wnd;
544 else return 0;
548 /**********************************************************************
549 * ReleaseCapture (USER.19)
551 void ReleaseCapture()
553 if (captureWnd == 0) return;
554 XUngrabPointer( display, CurrentTime );
555 captureWnd = 0;
558 /**********************************************************************
559 * GetCapture (USER.236)
561 HWND GetCapture()
563 return captureWnd;
567 /**********************************************************************
568 * EnableHardwareInput [USER.331]
570 BOOL EnableHardwareInput(BOOL bEnable)
572 BOOL bOldState = InputEnabled;
573 dprintf_event(stdnimp,"EMPTY STUB !!! EnableHardwareInput(%d);\n", bEnable);
574 InputEnabled = bEnable;
575 return (bOldState && !bEnable);