2 * X events handling functions
4 * Copyright 1993 Alexandre Julliard
12 #include <X11/keysym.h>
14 #include <X11/Xresource.h>
15 #include <X11/Xutil.h>
16 #include <X11/Xatom.h>
21 #include "clipboard.h"
26 #include "registers.h"
27 #include "stackframe.h"
29 /* #define DEBUG_EVENT */
30 /* #define DEBUG_KEY */
36 typedef char *XPointer;
40 #ifdef WHO_NEEDS_DIRTY_HACKS
42 /* Dirty hack to compile with Sun's OpenWindows */
43 typedef char *XPointer;
47 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
49 /* X context to associate a hwnd to an X window */
50 static XContext winContext = 0;
53 BOOL MouseButtonsStates[NB_BUTTONS] = { FALSE, FALSE, FALSE };
54 BOOL AsyncMouseButtonsStates[NB_BUTTONS] = { FALSE, FALSE, FALSE };
55 BYTE KeyStateTable[256];
56 BYTE AsyncKeyStateTable[256];
59 WPARAM lastEventChar = 0; /* this will have to be changed once
60 * ToAscii starts working */
62 static HWND captureWnd = 0;
63 static BOOL InputEnabled = TRUE;
65 /* Keyboard translation tables */
66 static int special_key[] =
68 VK_BACK, VK_TAB, 0, VK_CLEAR, 0, VK_RETURN, 0, 0, /* FF08 */
69 0, 0, 0, VK_PAUSE, VK_SCROLL, 0, 0, 0, /* FF10 */
70 0, 0, 0, VK_ESCAPE /* FF18 */
75 VK_HOME, VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_PRIOR,
76 VK_NEXT, VK_END /* FF50 */
81 VK_SELECT, VK_SNAPSHOT, VK_EXECUTE, VK_INSERT, 0, 0, 0, 0, /* FF60 */
82 VK_CANCEL, VK_HELP, VK_CANCEL, VK_MENU /* FF68 */
87 VK_MENU, VK_NUMLOCK, /* FF7E */
88 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
89 0, 0, 0, 0, 0, VK_RETURN, 0, 0, /* FF88 */
90 0, 0, 0, 0, 0, 0, 0, 0, /* FF90 */
91 0, 0, 0, 0, 0, 0, 0, 0, /* FF98 */
92 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
93 0, 0, VK_MULTIPLY, VK_ADD, VK_SEPARATOR, VK_SUBTRACT,
94 VK_DECIMAL, VK_DIVIDE, /* FFA8 */
95 VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4,
96 VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, /* FFB0 */
97 VK_NUMPAD8, VK_NUMPAD9 /* FFB8 */
100 static function_key[] =
102 VK_F1, VK_F2, /* FFBE */
103 VK_F3, VK_F4, VK_F5, VK_F6, VK_F7, VK_F8, VK_F9, VK_F10, /* FFC0 */
104 VK_F11, VK_F12, VK_F13, VK_F14, VK_F15, VK_F16 /* FFC8 */
107 static modifier_key[] =
109 VK_SHIFT, VK_SHIFT, VK_CONTROL, VK_CONTROL, VK_CAPITAL,
111 0, VK_MENU, VK_MENU /* FFE8 */
118 unsigned long count : 16;
119 unsigned long code : 8;
120 unsigned long extended : 1;
122 unsigned long reserved : 2;
123 unsigned long context : 1;
124 unsigned long previous : 1;
125 unsigned long transition : 1;
130 static BOOL KeyDown = FALSE;
132 static const char *event_names[] =
134 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
135 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
136 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
137 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
138 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
139 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
140 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
141 "ClientMessage", "MappingNotify"
145 static void EVENT_key( XKeyEvent *event );
146 static void EVENT_ButtonPress( XButtonEvent *event );
147 static void EVENT_ButtonRelease( XButtonEvent *event );
148 static void EVENT_MotionNotify( XMotionEvent *event );
149 static void EVENT_FocusIn( HWND hwnd, XFocusChangeEvent *event );
150 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event );
151 static void EVENT_Expose( HWND hwnd, XExposeEvent *event );
152 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event );
153 static void EVENT_SelectionRequest( HWND hwnd, XSelectionRequestEvent *event);
154 static void EVENT_SelectionNotify( HWND hwnd, XSelectionEvent *event);
155 static void EVENT_SelectionClear( HWND hwnd, XSelectionClearEvent *event);
156 static void EVENT_ClientMessage( HWND hwnd, XClientMessageEvent *event );
159 /***********************************************************************
162 * Process an X event.
164 void EVENT_ProcessEvent( XEvent *event )
169 XFindContext( display, ((XAnyEvent *)event)->window, winContext, &ptr );
170 hwnd = (HWND) (int)ptr;
172 dprintf_event(stddeb, "Got event %s for hwnd %04x\n",
173 event_names[event->type], hwnd );
179 EVENT_key( (XKeyEvent*)event );
183 EVENT_ButtonPress( (XButtonEvent*)event );
187 EVENT_ButtonRelease( (XButtonEvent*)event );
191 /* Wine between two fast machines across the overloaded campus
192 ethernet gets very boged down in MotionEvents. The following
193 simply finds the last motion event in the queue and drops
194 the rest. On a good link events are servered before they build
195 up so this doesn't take place. On a slow link this may cause
196 problems if the event order is important. I'm not yet seen
197 of any problems. Jon 7/6/96.
199 while (XCheckTypedWindowEvent(display, ((XAnyEvent *)event)->window,
200 MotionNotify, event));
201 EVENT_MotionNotify( (XMotionEvent*)event );
205 EVENT_FocusIn( hwnd, (XFocusChangeEvent*)event );
209 EVENT_FocusOut( hwnd, (XFocusChangeEvent*)event );
213 EVENT_Expose( hwnd, (XExposeEvent*)event );
216 case ConfigureNotify:
217 EVENT_ConfigureNotify( hwnd, (XConfigureEvent*)event );
220 case SelectionRequest:
221 EVENT_SelectionRequest( hwnd, (XSelectionRequestEvent*)event );
224 case SelectionNotify:
225 EVENT_SelectionNotify( hwnd, (XSelectionEvent*)event );
229 EVENT_SelectionClear( hwnd, (XSelectionClearEvent*) event );
233 EVENT_ClientMessage( hwnd, (XClientMessageEvent *) event );
237 dprintf_event(stddeb, "Unprocessed event %s for hwnd %04x\n",
238 event_names[event->type], hwnd );
244 /***********************************************************************
245 * EVENT_RegisterWindow
247 * Associate an X window to a HWND.
249 void EVENT_RegisterWindow( Window w, HWND hwnd )
251 if (!winContext) winContext = XUniqueContext();
252 XSaveContext( display, w, winContext, (XPointer)(int)hwnd );
256 /***********************************************************************
257 * EVENT_XStateToKeyState
259 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
260 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
262 static WORD EVENT_XStateToKeyState( int state )
266 if (state & Button1Mask) kstate |= MK_LBUTTON;
267 if (state & Button2Mask) kstate |= MK_MBUTTON;
268 if (state & Button3Mask) kstate |= MK_RBUTTON;
269 if (state & ShiftMask) kstate |= MK_SHIFT;
270 if (state & ControlMask) kstate |= MK_CONTROL;
275 /***********************************************************************
278 static void EVENT_Expose( HWND hwnd, XExposeEvent *event )
281 WND * wndPtr = WIN_FindWndPtr( hwnd );
284 /* Make position relative to client area instead of window */
285 rect.left = event->x - (wndPtr->rectClient.left - wndPtr->rectWindow.left);
286 rect.top = event->y - (wndPtr->rectClient.top - wndPtr->rectWindow.top);
287 rect.right = rect.left + event->width;
288 rect.bottom = rect.top + event->height;
290 RedrawWindow( hwnd, &rect, 0,
291 RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE |
292 (event->count ? 0 : RDW_ERASENOW) );
296 /***********************************************************************
299 * Handle a X key event
301 static void EVENT_key( XKeyEvent *event )
307 WORD xkey, key_type, key;
309 BOOL extended = FALSE;
311 int ascii_chars = XLookupString(event, Str, 1, &keysym, &cs);
313 Str[ascii_chars] = '\0';
314 dprintf_key(stddeb,"WM_KEY??? : keysym=%lX, ascii chars=%u / %X / '%s'\n",
315 keysym, ascii_chars, Str[0], Str);
317 /* Ctrl-Alt-Return enters the debugger */
318 if ((keysym == XK_Return) && (event->type == KeyPress) &&
319 (event->state & ControlMask) && (event->state & Mod1Mask))
320 DEBUG_EnterDebugger();
322 xkey = LOWORD(keysym);
323 key_type = HIBYTE(xkey);
325 dprintf_key(stddeb," key_type=%X, key=%X\n", key_type, key);
327 if (key_type == 0xFF) /* non-character key */
329 if (key >= 0x08 && key <= 0x1B) /* special key */
330 vkey = special_key[key - 0x08];
331 else if (key >= 0x50 && key <= 0x57) /* cursor key */
332 vkey = cursor_key[key - 0x50];
333 else if (key >= 0x60 && key <= 0x6B) /* miscellaneous key */
334 vkey = misc_key[key - 0x60];
335 else if (key >= 0x7E && key <= 0xB9) /* keypad key */
337 vkey = keypad_key[key - 0x7E];
340 else if (key >= 0xBE && key <= 0xCD) /* function key */
342 vkey = function_key[key - 0xBE];
345 else if (key >= 0xE1 && key <= 0xEA) /* modifier key */
346 vkey = modifier_key[key - 0xE1];
347 else if (key == 0xFF) /* DEL key */
350 else if (key_type == 0) /* character key */
353 vkey = toupper(key); /* convert lower to uppercase */
358 if (event->type == KeyPress)
360 if (!(KeyStateTable[vkey] & 0x80))
361 KeyStateTable[vkey] ^= 0x01;
362 KeyStateTable[vkey] |= 0x80;
364 keylp.lp1.code = LOBYTE(event->keycode) - 8;
365 keylp.lp1.extended = (extended ? 1 : 0);
366 keylp.lp1.reserved = (ascii_chars ? 1 : 0);
367 keylp.lp1.context = ( (event->state & Mod1Mask) ||
368 (KeyStateTable[VK_MENU] & 0x80)) ? 1 : 0;
369 keylp.lp1.previous = (KeyDown ? 0 : 1);
370 keylp.lp1.transition = 0;
371 dprintf_key(stddeb," wParam=%X, lParam=%lX\n",
373 dprintf_key(stddeb," KeyState=%X\n", KeyStateTable[vkey]);
374 hardware_event( KeyStateTable[VK_MENU] & 0x80 ? WM_SYSKEYDOWN : WM_KEYDOWN,
376 event->x_root - desktopX, event->y_root - desktopY,
380 /* Currently we use reserved field in the scan-code byte to
381 * make it possible for TranslateMessage to recognize character keys
382 * and get them from lastEventChar global variable.
384 * ToAscii should handle it.
387 if( ascii_chars ) lastEventChar = Str[0];
391 UINT sysKey = KeyStateTable[VK_MENU];
393 KeyStateTable[vkey] &= ~0x80;
395 keylp.lp1.code = LOBYTE(event->keycode) - 8;
396 keylp.lp1.extended = (extended ? 1 : 0);
397 keylp.lp1.reserved = 0;
398 keylp.lp1.context = (event->state & Mod1Mask ? 1 : 0);
399 keylp.lp1.previous = 1;
400 keylp.lp1.transition = 1;
401 dprintf_key(stddeb," wParam=%X, lParam=%lX\n",
403 dprintf_key(stddeb," KeyState=%X\n", KeyStateTable[vkey]);
404 hardware_event( sysKey & 0x80 ? WM_SYSKEYUP : WM_KEYUP,
406 event->x_root - desktopX, event->y_root - desktopY,
413 /***********************************************************************
416 static void EVENT_MotionNotify( XMotionEvent *event )
418 hardware_event( WM_MOUSEMOVE, EVENT_XStateToKeyState( event->state ), 0L,
419 event->x_root - desktopX, event->y_root - desktopY,
424 /***********************************************************************
425 * EVENT_DummyMotionNotify
427 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
429 void EVENT_DummyMotionNotify(void)
432 int rootX, rootY, childX, childY;
435 if (XQueryPointer( display, rootWindow, &root, &child,
436 &rootX, &rootY, &childX, &childY, &state ))
438 hardware_event(WM_MOUSEMOVE, EVENT_XStateToKeyState( state ), 0L,
439 rootX - desktopX, rootY - desktopY, GetTickCount(), 0 );
444 /***********************************************************************
447 static void EVENT_ButtonPress( XButtonEvent *event )
449 static WORD messages[NB_BUTTONS] =
450 { WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN };
451 int buttonNum = event->button - 1;
453 if (buttonNum >= NB_BUTTONS) return;
454 MouseButtonsStates[buttonNum] = 0x8000;
455 AsyncMouseButtonsStates[buttonNum] = 0x8000;
456 hardware_event( messages[buttonNum],
457 EVENT_XStateToKeyState( event->state ), 0L,
458 event->x_root - desktopX, event->y_root - desktopY,
463 /***********************************************************************
464 * EVENT_ButtonRelease
466 static void EVENT_ButtonRelease( XButtonEvent *event )
468 static const WORD messages[NB_BUTTONS] =
469 { WM_LBUTTONUP, WM_MBUTTONUP, WM_RBUTTONUP };
470 int buttonNum = event->button - 1;
472 if (buttonNum >= NB_BUTTONS) return;
473 MouseButtonsStates[buttonNum] = FALSE;
474 hardware_event( messages[buttonNum],
475 EVENT_XStateToKeyState( event->state ), 0L,
476 event->x_root - desktopX, event->y_root - desktopY,
481 /**********************************************************************
484 static void EVENT_FocusIn (HWND hwnd, XFocusChangeEvent *event )
486 if (event->detail == NotifyPointer) return;
487 if (hwnd != GetActiveWindow()) WINPOS_ChangeActiveWindow( hwnd, FALSE );
488 if ((hwnd != GetFocus()) && ! IsChild( hwnd, GetFocus())) SetFocus( hwnd );
492 /**********************************************************************
495 * Note: only top-level override-redirect windows get FocusOut events.
497 static void EVENT_FocusOut( HWND hwnd, XFocusChangeEvent *event )
499 if (event->detail == NotifyPointer) return;
500 if (hwnd == GetActiveWindow()) WINPOS_ChangeActiveWindow( 0, FALSE );
501 if ((hwnd == GetFocus()) || IsChild( hwnd, GetFocus())) SetFocus( 0 );
505 /**********************************************************************
506 * EVENT_ConfigureNotify
508 * The ConfigureNotify event is only selected on the desktop window
509 * and on top-level windows when the -managed flag is used.
511 static void EVENT_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
513 if (hwnd == GetDesktopWindow())
520 /* A managed window; most of this code is shamelessly
521 * stolen from SetWindowPos
526 RECT newWindowRect, newClientRect;
528 if (!(wndPtr = WIN_FindWndPtr( hwnd )))
530 dprintf_event(stddeb,"ConfigureNotify: invalid HWND %04x\n",hwnd);
534 /* Artificial messages */
535 SendMessage(hwnd, WM_ENTERSIZEMOVE, 0, 0);
536 SendMessage(hwnd, WM_EXITSIZEMOVE, 0, 0);
538 /* Fill WINDOWPOS struct */
539 winpos.flags = SWP_NOACTIVATE | SWP_NOZORDER;
543 winpos.cx = event->width;
544 winpos.cy = event->height;
546 /* Check for unchanged attributes */
547 if(winpos.x == wndPtr->rectWindow.left &&
548 winpos.y == wndPtr->rectWindow.top)
549 winpos.flags |= SWP_NOMOVE;
550 if(winpos.cx == wndPtr->rectWindow.right - wndPtr->rectWindow.left &&
551 winpos.cy == wndPtr->rectWindow.bottom - wndPtr->rectWindow.top)
552 winpos.flags |= SWP_NOSIZE;
554 /* Send WM_WINDOWPOSCHANGING */
555 SendMessage(hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)MAKE_SEGPTR(&winpos));
557 /* Calculate new position and size */
558 newWindowRect.left = event->x;
559 newWindowRect.right = event->x + event->width;
560 newWindowRect.top = event->y;
561 newWindowRect.bottom = event->y + event->height;
563 WINPOS_SendNCCalcSize( winpos.hwnd, TRUE, &newWindowRect,
564 &wndPtr->rectWindow, &wndPtr->rectClient,
565 &winpos, &newClientRect );
567 /* Set new size and position */
568 wndPtr->rectWindow = newWindowRect;
569 wndPtr->rectClient = newClientRect;
570 SendMessage(hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)MAKE_SEGPTR(&winpos));
575 /***********************************************************************
576 * EVENT_SelectionRequest
578 static void EVENT_SelectionRequest( HWND hwnd, XSelectionRequestEvent *event )
580 XSelectionEvent result;
582 Window request=event->requestor;
584 if(event->target == XA_STRING)
588 rprop=event->property;
589 if(rprop == None)rprop=event->target;
590 if(event->selection!=XA_PRIMARY)rprop=None;
591 else if(!IsClipboardFormatAvailable(CF_TEXT))rprop=None;
593 /* Don't worry if we can't open */
594 BOOL couldOpen=OpenClipboard(hwnd);
595 hText=GetClipboardData(CF_TEXT);
596 text=GlobalLock(hText);
597 XChangeProperty(display,request,rprop,XA_STRING,
598 8,PropModeReplace,text,strlen(text));
600 /* close only if we opened before */
601 if(couldOpen)CloseClipboard();
604 if(rprop==None) dprintf_event(stddeb,"Request for %s ignored\n",
605 XGetAtomName(display,event->target));
606 result.type=SelectionNotify;
607 result.display=display;
608 result.requestor=request;
609 result.selection=event->selection;
610 result.property=rprop;
611 result.target=event->target;
612 result.time=event->time;
613 XSendEvent(display,event->requestor,False,NoEventMask,(XEvent*)&result);
617 /***********************************************************************
618 * EVENT_SelectionNotify
620 static void EVENT_SelectionNotify(HWND hwnd, XSelectionEvent *event)
622 if(event->selection!=XA_PRIMARY)return;
623 if(event->target!=XA_STRING)CLIPBOARD_ReadSelection(0,None);
624 CLIPBOARD_ReadSelection(event->requestor,event->property);
628 /***********************************************************************
629 * EVENT_SelectionClear
631 static void EVENT_SelectionClear(HWND hwnd, XSelectionClearEvent *event)
633 if(event->selection!=XA_PRIMARY)return;
634 CLIPBOARD_ReleaseSelection(hwnd);
638 /**********************************************************************
639 * EVENT_ClientMessage
641 static void EVENT_ClientMessage (HWND hwnd, XClientMessageEvent *event )
643 static Atom wmProtocols = None;
644 static Atom wmDeleteWindow = None;
646 if (wmProtocols == None)
647 wmProtocols = XInternAtom( display, "WM_PROTOCOLS", True );
648 if (wmDeleteWindow == None)
649 wmDeleteWindow = XInternAtom( display, "WM_DELETE_WINDOW", True );
651 if ((event->format != 32) || (event->message_type != wmProtocols) ||
652 (((Atom) event->data.l[0]) != wmDeleteWindow))
654 dprintf_event( stddeb, "unrecognized ClientMessage\n" );
657 SendMessage( hwnd, WM_SYSCOMMAND, SC_CLOSE, 0 );
661 /**********************************************************************
662 * SetCapture (USER.18)
664 HWND SetCapture( HWND hwnd )
667 HWND old_capture_wnd = captureWnd;
672 return old_capture_wnd;
674 if (!(win = WIN_GetXWindow( hwnd ))) return 0;
675 if (XGrabPointer(display, win, False,
676 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
677 GrabModeAsync, GrabModeAsync,
678 None, None, CurrentTime ) == GrabSuccess)
680 dprintf_win(stddeb, "SetCapture: %04x\n", hwnd);
682 return old_capture_wnd;
688 /**********************************************************************
689 * ReleaseCapture (USER.19)
691 void ReleaseCapture()
693 if (captureWnd == 0) return;
694 XUngrabPointer( display, CurrentTime );
696 dprintf_win(stddeb, "ReleaseCapture\n");
699 /**********************************************************************
700 * GetCapture (USER.236)
708 /***********************************************************************
709 * GetMouseEventProc (USER.337)
711 FARPROC GetMouseEventProc(void)
713 char name[] = "Mouse_Event";
714 return GetProcAddress( GetModuleHandle("USER"), MAKE_SEGPTR(name) );
718 /***********************************************************************
719 * Mouse_Event (USER.299)
722 void Mouse_Event( struct sigcontext_struct context )
726 * BX = horizontal displacement if AX & ME_MOVE
727 * CX = vertical displacement if AX & ME_MOVE
728 * DX = button state (?)
729 * SI = mouse event flags (?)
732 int rootX, rootY, childX, childY;
735 if (AX_reg(&context) & ME_MOVE)
737 /* We have to actually move the cursor */
738 XWarpPointer( display, rootWindow, None, 0, 0, 0, 0,
739 (short)BX_reg(&context), (short)CX_reg(&context) );
742 if (!XQueryPointer( display, rootWindow, &root, &child,
743 &rootX, &rootY, &childX, &childY, &state )) return;
744 if (AX_reg(&context) & ME_LDOWN)
745 hardware_event( WM_LBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
746 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
747 if (AX_reg(&context) & ME_LUP)
748 hardware_event( WM_LBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
749 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
750 if (AX_reg(&context) & ME_RDOWN)
751 hardware_event( WM_RBUTTONDOWN, EVENT_XStateToKeyState( state ), 0L,
752 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
753 if (AX_reg(&context) & ME_RUP)
754 hardware_event( WM_RBUTTONUP, EVENT_XStateToKeyState( state ), 0L,
755 rootX - desktopX, rootY - desktopY, GetTickCount(), 0);
760 /**********************************************************************
761 * EnableHardwareInput [USER.331]
763 BOOL EnableHardwareInput(BOOL bEnable)
765 BOOL bOldState = InputEnabled;
766 dprintf_event(stdnimp,"EMPTY STUB !!! EnableHardwareInput(%d);\n", bEnable);
767 InputEnabled = bEnable;
768 return (bOldState && !bEnable);