2 * X events handling functions
4 * Copyright 1993 Alexandre Julliard
12 #include <X11/Xresource.h>
13 #include <X11/Xutil.h>
14 #include <X11/Xatom.h>
20 #include "clipboard.h"
22 #include "registers.h"
23 #include "stackframe.h"
25 /* #define DEBUG_EVENT */
26 /* #define DEBUG_KEY */
32 typedef char *XPointer
;
36 #ifdef WHO_NEEDS_DIRTY_HACKS
38 /* Dirty hack to compile with Sun's OpenWindows */
39 typedef char *XPointer
;
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;
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 */
67 VK_HOME
, VK_LEFT
, VK_UP
, VK_RIGHT
, VK_DOWN
, VK_PRIOR
,
68 VK_NEXT
, VK_END
/* FF50 */
73 VK_SELECT
, VK_SNAPSHOT
, VK_EXECUTE
, VK_INSERT
, 0, 0, 0, 0, /* FF60 */
74 VK_CANCEL
, VK_HELP
, VK_CANCEL
, VK_MENU
/* FF68 */
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
,
103 0, VK_MENU
, VK_MENU
/* FFE8 */
110 unsigned long count
: 16;
111 unsigned long code
: 8;
112 unsigned long extended
: 1;
114 unsigned long context
: 1;
115 unsigned long previous
: 1;
116 unsigned long transition
: 1;
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"
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 /***********************************************************************
151 * Process an X event.
153 void EVENT_ProcessEvent( XEvent
*event
)
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
);
168 EVENT_key( (XKeyEvent
*)event
);
172 EVENT_ButtonPress( (XButtonEvent
*)event
);
176 EVENT_ButtonRelease( (XButtonEvent
*)event
);
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
);
194 EVENT_FocusOut( hwnd
, (XFocusChangeEvent
*)event
);
198 EVENT_Expose( hwnd
, (XExposeEvent
*)event
);
201 case ConfigureNotify
:
202 EVENT_ConfigureNotify( hwnd
, (XConfigureEvent
*)event
);
205 case SelectionRequest
:
206 EVENT_SelectionRequest( hwnd
, (XSelectionRequestEvent
*)event
);
209 case SelectionNotify
:
210 EVENT_SelectionNotify( hwnd
, (XSelectionEvent
*)event
);
214 EVENT_SelectionClear( hwnd
, (XSelectionClearEvent
*) event
);
218 dprintf_event(stddeb
, "Unprocessed event %s for hwnd "NPFMT
"\n",
219 event_names
[event
->type
], hwnd
);
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
)
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
;
256 /***********************************************************************
259 static void EVENT_Expose( HWND hwnd
, XExposeEvent
*event
)
262 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
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 /***********************************************************************
280 * Handle a X key event
282 static void EVENT_key( XKeyEvent
*event
)
288 WORD xkey
, key_type
, key
;
290 BOOL extended
= FALSE
;
292 int count
= XLookupString(event
, Str
, 1, &keysym
, &cs
);
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
);
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];
315 else if (key
>= 0xBE && key
<= 0xCD) /* function key */
317 vkey
= function_key
[key
- 0xBE];
320 else if (key
>= 0xE1 && key
<= 0xEA) /* modifier key */
321 vkey
= modifier_key
[key
- 0xE1];
322 else if (key
== 0xFF) /* DEL key */
325 else if (key_type
== 0) /* character key */
328 vkey
= toupper(key
); /* convert lower to uppercase */
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;
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",
347 dprintf_key(stddeb
," KeyState=%X\n", KeyStateTable
[vkey
]);
348 hardware_event( ALTKeyState
? WM_SYSKEYDOWN
: WM_KEYDOWN
,
350 event
->x_root
- desktopX
, event
->y_root
- desktopY
,
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]),
368 if (vkey
== VK_MENU
) ALTKeyState
= FALSE
;
369 KeyStateTable
[vkey
] &= 0xf0;
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",
378 dprintf_key(stddeb
," KeyState=%X\n", KeyStateTable
[vkey
]);
379 hardware_event( ((ALTKeyState
|| vkey
== VK_MENU
) ?
380 WM_SYSKEYUP
: WM_KEYUP
),
382 event
->x_root
- desktopX
, event
->y_root
- desktopY
,
389 /***********************************************************************
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
,
400 /***********************************************************************
401 * EVENT_DummyMotionNotify
403 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
405 void EVENT_DummyMotionNotify(void)
408 int rootX
, rootY
, childX
, childY
;
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 /***********************************************************************
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
,
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
,
457 /**********************************************************************
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
)
482 /***********************************************************************
483 * EVENT_SelectionRequest
485 static void EVENT_SelectionRequest( HWND hwnd
, XSelectionRequestEvent
*event
)
487 XSelectionEvent result
;
489 Window request
=event
->requestor
;
491 if(event
->target
== XA_STRING
)
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
;
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
));
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
)
550 HWND old_capture_wnd
= captureWnd
;
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
);
565 return old_capture_wnd
;
571 /**********************************************************************
572 * ReleaseCapture (USER.19)
574 void ReleaseCapture()
576 if (captureWnd
== 0) return;
577 XUngrabPointer( display
, CurrentTime
);
579 dprintf_win(stddeb
, "ReleaseCapture\n");
582 /**********************************************************************
583 * GetCapture (USER.236)
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)
605 void Mouse_Event( struct sigcontext_struct context
)
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 (?)
615 int rootX
, rootY
, childX
, childY
;
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
) );
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);
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
);