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"
23 /* #define DEBUG_EVENT */
24 /* #define DEBUG_KEY */
30 typedef char *XPointer
;
34 #ifdef WHO_NEEDS_DIRTY_HACKS
36 /* Dirty hack to compile with Sun's OpenWindows */
37 typedef char *XPointer
;
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;
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 */
65 VK_HOME
, VK_LEFT
, VK_UP
, VK_RIGHT
, VK_DOWN
, VK_PRIOR
,
66 VK_NEXT
, VK_END
/* FF50 */
71 VK_SELECT
, VK_SNAPSHOT
, VK_EXECUTE
, VK_INSERT
, 0, 0, 0, 0, /* FF60 */
72 VK_CANCEL
, VK_HELP
, VK_CANCEL
, VK_MENU
/* FF68 */
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
,
101 0, VK_MENU
, VK_MENU
/* FFE8 */
108 unsigned long count
: 16;
109 unsigned long code
: 8;
110 unsigned long extended
: 1;
112 unsigned long context
: 1;
113 unsigned long previous
: 1;
114 unsigned long transition
: 1;
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"
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 /***********************************************************************
150 * Process an X event.
152 void EVENT_ProcessEvent( XEvent
*event
)
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
);
167 EVENT_key( (XKeyEvent
*)event
);
171 EVENT_ButtonPress( (XButtonEvent
*)event
);
175 EVENT_ButtonRelease( (XButtonEvent
*)event
);
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
);
193 EVENT_FocusOut( hwnd
, (XFocusChangeEvent
*)event
);
197 EVENT_Expose( hwnd
, (XExposeEvent
*)event
);
200 case ConfigureNotify
:
201 EVENT_ConfigureNotify( hwnd
, (XConfigureEvent
*)event
);
204 case SelectionRequest
:
205 EVENT_SelectionRequest( hwnd
, (XSelectionRequestEvent
*)event
);
208 case SelectionNotify
:
209 EVENT_SelectionNotify( hwnd
, (XSelectionEvent
*)event
);
213 EVENT_SelectionClear( hwnd
, (XSelectionClearEvent
*) event
);
217 dprintf_event(stddeb
, "Unprocessed event %s for hwnd %d\n",
218 event_names
[event
->type
], hwnd
);
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
)
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
;
255 /***********************************************************************
258 static void EVENT_Expose( HWND hwnd
, XExposeEvent
*event
)
261 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
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 /***********************************************************************
279 * Handle a X key event
281 static void EVENT_key( XKeyEvent
*event
)
286 WORD xkey
, vkey
, key_type
, key
;
288 BOOL extended
= FALSE
;
290 int count
= XLookupString(event
, Str
, 1, &keysym
, &cs
);
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
);
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];
313 else if (key
>= 0xBE && key
<= 0xCD) /* function key */
315 vkey
= function_key
[key
- 0xBE];
318 else if (key
>= 0xE1 && key
<= 0xEA) /* modifier key */
319 vkey
= modifier_key
[key
- 0xE1];
320 else if (key
== 0xFF) /* DEL key */
323 else if (key_type
== 0) /* character key */
326 vkey
= toupper(key
); /* convert lower to uppercase */
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;
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",
345 dprintf_key(stddeb
," KeyState=%X\n", KeyStateTable
[vkey
]);
346 hardware_event( ALTKeyState
? WM_SYSKEYDOWN
: WM_KEYDOWN
,
348 event
->x_root
- desktopX
, event
->y_root
- desktopY
,
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]),
366 if (vkey
== VK_MENU
) ALTKeyState
= FALSE
;
367 KeyStateTable
[vkey
] &= 0xf0;
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",
376 dprintf_key(stddeb
," KeyState=%X\n", KeyStateTable
[vkey
]);
377 hardware_event( ((ALTKeyState
|| vkey
== VK_MENU
) ?
378 WM_SYSKEYUP
: WM_KEYUP
),
380 event
->x_root
- desktopX
, event
->y_root
- desktopY
,
387 /***********************************************************************
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
,
398 /***********************************************************************
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
,
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
,
435 /**********************************************************************
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
)
460 /***********************************************************************
461 * EVENT_SelectionRequest
463 static void EVENT_SelectionRequest( HWND hwnd
, XSelectionRequestEvent
*event
)
465 XSelectionEvent result
;
467 Window request
=event
->requestor
;
469 if(event
->target
== XA_STRING
)
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
;
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
));
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
)
528 HWND old_capture_wnd
= captureWnd
;
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
)
542 return old_capture_wnd
;
548 /**********************************************************************
549 * ReleaseCapture (USER.19)
551 void ReleaseCapture()
553 if (captureWnd
== 0) return;
554 XUngrabPointer( display
, CurrentTime
);
558 /**********************************************************************
559 * GetCapture (USER.236)
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
);