2 * X events handling functions
4 * Copyright 1993 Alexandre Julliard
14 #include <sys/types.h>
16 #include <X11/keysym.h>
18 #include <X11/Xresource.h>
19 #include <X11/Xutil.h>
20 #include <X11/Xatom.h>
29 #include "clipboard.h"
44 #define NB_BUTTONS 3 /* Windows can handle 3 buttons */
46 #define DndNotDnd -1 /* OffiX drag&drop */
58 /* X context to associate a hwnd to an X window */
59 static XContext winContext
= 0;
62 BOOL MouseButtonsStates
[NB_BUTTONS
];
63 BOOL AsyncMouseButtonsStates
[NB_BUTTONS
];
64 BYTE InputKeyStateTable
[256];
66 static INT16 captureHT
= HTCLIENT
;
67 static HWND32 captureWnd
= 0;
68 static BOOL32 InputEnabled
= TRUE
;
70 static Atom wmProtocols
= None
;
71 static Atom wmDeleteWindow
= None
;
72 static Atom dndProtocol
= None
;
73 static Atom dndSelection
= None
;
75 static const char * const event_names
[] =
77 "", "", "KeyPress", "KeyRelease", "ButtonPress", "ButtonRelease",
78 "MotionNotify", "EnterNotify", "LeaveNotify", "FocusIn", "FocusOut",
79 "KeymapNotify", "Expose", "GraphicsExpose", "NoExpose", "VisibilityNotify",
80 "CreateNotify", "DestroyNotify", "UnmapNotify", "MapNotify", "MapRequest",
81 "ReparentNotify", "ConfigureNotify", "ConfigureRequest", "GravityNotify",
82 "ResizeRequest", "CirculateNotify", "CirculateRequest", "PropertyNotify",
83 "SelectionClear", "SelectionRequest", "SelectionNotify", "ColormapNotify",
84 "ClientMessage", "MappingNotify"
88 static void EVENT_key( XKeyEvent
*event
);
89 static void EVENT_ButtonPress( XButtonEvent
*event
);
90 static void EVENT_ButtonRelease( XButtonEvent
*event
);
91 static void EVENT_MotionNotify( XMotionEvent
*event
);
92 static void EVENT_FocusIn( HWND hwnd
, XFocusChangeEvent
*event
);
93 static void EVENT_FocusOut( HWND hwnd
, XFocusChangeEvent
*event
);
94 static void EVENT_Expose( WND
*pWnd
, XExposeEvent
*event
);
95 static void EVENT_GraphicsExpose( WND
*pWnd
, XGraphicsExposeEvent
*event
);
96 static void EVENT_ConfigureNotify( HWND hwnd
, XConfigureEvent
*event
);
97 static void EVENT_SelectionRequest( WND
*pWnd
, XSelectionRequestEvent
*event
);
98 static void EVENT_SelectionNotify( XSelectionEvent
*event
);
99 static void EVENT_SelectionClear( WND
*pWnd
, XSelectionClearEvent
*event
);
100 static void EVENT_ClientMessage( WND
*pWnd
, XClientMessageEvent
*event
);
101 static void EVENT_MapNotify( HWND hwnd
, XMapEvent
*event
);
103 /* Usable only with OLVWM - compile option perhaps?
104 static void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event );
107 extern void FOCUS_SetXFocus( HWND32
);
108 extern BOOL16
DRAG_QueryUpdate( HWND
, SEGPTR
, BOOL32
);
110 /***********************************************************************
113 * Process an X event.
115 void EVENT_ProcessEvent( XEvent
*event
)
119 if (XFindContext( display
, event
->xany
.window
, winContext
,
120 (char **)&pWnd
) != 0)
121 return; /* Not for a registered window */
123 dprintf_event( stddeb
, "Got event %s for hwnd %04x\n",
124 event_names
[event
->type
], pWnd
->hwndSelf
);
131 EVENT_key( (XKeyEvent
*)event
);
136 EVENT_ButtonPress( (XButtonEvent
*)event
);
141 EVENT_ButtonRelease( (XButtonEvent
*)event
);
145 /* Wine between two fast machines across the overloaded campus
146 ethernet gets very boged down in MotionEvents. The following
147 simply finds the last motion event in the queue and drops
148 the rest. On a good link events are servered before they build
149 up so this doesn't take place. On a slow link this may cause
150 problems if the event order is important. I'm not yet seen
151 of any problems. Jon 7/6/96.
155 while (XCheckTypedWindowEvent(display
,((XAnyEvent
*)event
)->window
,
156 MotionNotify
, event
));
157 EVENT_MotionNotify( (XMotionEvent
*)event
);
162 EVENT_FocusIn( pWnd
->hwndSelf
, (XFocusChangeEvent
*)event
);
166 EVENT_FocusOut( pWnd
->hwndSelf
, (XFocusChangeEvent
*)event
);
170 EVENT_Expose( pWnd
, (XExposeEvent
*)event
);
174 EVENT_GraphicsExpose( pWnd
, (XGraphicsExposeEvent
*)event
);
177 case ConfigureNotify
:
178 EVENT_ConfigureNotify( pWnd
->hwndSelf
, (XConfigureEvent
*)event
);
181 case SelectionRequest
:
182 EVENT_SelectionRequest( pWnd
, (XSelectionRequestEvent
*)event
);
185 case SelectionNotify
:
186 EVENT_SelectionNotify( (XSelectionEvent
*)event
);
190 EVENT_SelectionClear( pWnd
, (XSelectionClearEvent
*) event
);
194 EVENT_ClientMessage( pWnd
, (XClientMessageEvent
*) event
);
198 * EVENT_EnterNotify( pWnd, (XCrossingEvent *) event );
204 /* We get all these because of StructureNotifyMask. */
206 case CirculateNotify
:
214 EVENT_MapNotify( pWnd
->hwndSelf
, (XMapEvent
*)event
);
218 dprintf_event(stddeb
, "Unprocessed event %s for hwnd %04x\n",
219 event_names
[event
->type
], pWnd
->hwndSelf
);
225 /***********************************************************************
226 * EVENT_RegisterWindow
228 * Associate an X window to a HWND.
230 void EVENT_RegisterWindow( WND
*pWnd
)
232 if (wmProtocols
== None
)
233 wmProtocols
= XInternAtom( display
, "WM_PROTOCOLS", True
);
234 if (wmDeleteWindow
== None
)
235 wmDeleteWindow
= XInternAtom( display
, "WM_DELETE_WINDOW", True
);
236 if( dndProtocol
== None
)
237 dndProtocol
= XInternAtom( display
, "DndProtocol" , False
);
238 if( dndSelection
== None
)
239 dndSelection
= XInternAtom( display
, "DndSelection" , False
);
241 XSetWMProtocols( display
, pWnd
->window
, &wmDeleteWindow
, 1 );
243 if (!winContext
) winContext
= XUniqueContext();
244 XSaveContext( display
, pWnd
->window
, winContext
, (char *)pWnd
);
247 /***********************************************************************
248 * EVENT_DestroyWindow
250 void EVENT_DestroyWindow( WND
*pWnd
)
254 XDeleteContext( display
, pWnd
->window
, winContext
);
255 XDestroyWindow( display
, pWnd
->window
);
256 while( XCheckWindowEvent(display
, pWnd
->window
, NoEventMask
, &xe
) );
259 /***********************************************************************
262 * Wait for an X event, optionally sleeping until one arrives.
263 * Return TRUE if an event is pending, FALSE on timeout or error
264 * (for instance lost connection with the server).
266 BOOL32
EVENT_WaitXEvent( BOOL32 sleep
, BOOL32 peek
)
269 LONG maxWait
= sleep
? TIMER_GetNextExpiration() : 0;
271 /* Wait for an event or a timeout. If maxWait is -1, we have no timeout;
272 * in this case, we fall through directly to the XNextEvent loop.
275 if ((maxWait
!= -1) && !XPending(display
))
278 struct timeval timeout
;
279 int fd
= ConnectionNumber(display
);
281 FD_ZERO( &read_set
);
282 FD_SET( fd
, &read_set
);
284 timeout
.tv_usec
= (maxWait
% 1000) * 1000;
285 timeout
.tv_sec
= maxWait
/ 1000;
288 sigsetjmp(env_wait_x
, 1);
291 if (DDE_GetRemoteMessage()) {
292 while(DDE_GetRemoteMessage())
296 stop_wait_op
= STOP_WAIT_X
;
297 /* The code up to the next "stop_wait_op = CONT" must be reentrant */
298 if (select( fd
+1, &read_set
, NULL
, NULL
, &timeout
) != 1 &&
302 TIMER_ExpireTimers();
305 else stop_wait_op
= CONT
;
306 #else /* CONFIG_IPC */
307 if (select( fd
+1, &read_set
, NULL
, NULL
, &timeout
) != 1)
309 /* Timeout or error */
310 TIMER_ExpireTimers();
313 #endif /* CONFIG_IPC */
317 /* Process the event (and possibly others that occurred in the meantime) */
323 if (DDE_GetRemoteMessage())
325 while(DDE_GetRemoteMessage()) ;
328 #endif /* CONFIG_IPC */
330 XNextEvent( display
, &event
);
337 if (XFindContext( display
, ((XAnyEvent
*)&event
)->window
, winContext
,
338 (char **)&pWnd
) || (event
.type
== NoExpose
))
341 /* check for the "safe" hardware events */
343 if( event
.type
== MotionNotify
||
344 event
.type
== ButtonPress
|| event
.type
== ButtonRelease
||
345 event
.type
== KeyPress
|| event
.type
== KeyRelease
||
346 event
.type
== SelectionRequest
|| event
.type
== SelectionClear
)
348 EVENT_ProcessEvent( &event
);
353 if( (pQ
= (MESSAGEQUEUE
*)GlobalLock16(pWnd
->hmemTaskQ
)) )
355 pQ
->flags
|= QUEUE_FLAG_XEVENT
;
356 PostEvent(pQ
->hTask
);
357 XPutBackEvent(display
, &event
);
362 EVENT_ProcessEvent( &event
);
364 while (XPending( display
));
369 /***********************************************************************
372 * Synchronize with the X server. Should not be used too often.
374 void EVENT_Synchronize()
378 XSync( display
, False
);
379 while (XPending( display
))
381 XNextEvent( display
, &event
);
382 EVENT_ProcessEvent( &event
);
387 /***********************************************************************
388 * EVENT_XStateToKeyState
390 * Translate a X event state (Button1Mask, ShiftMask, etc...) to
391 * a Windows key state (MK_SHIFT, MK_CONTROL, etc...)
393 static WORD
EVENT_XStateToKeyState( int state
)
397 if (state
& Button1Mask
) kstate
|= MK_LBUTTON
;
398 if (state
& Button2Mask
) kstate
|= MK_MBUTTON
;
399 if (state
& Button3Mask
) kstate
|= MK_RBUTTON
;
400 if (state
& ShiftMask
) kstate
|= MK_SHIFT
;
401 if (state
& ControlMask
) kstate
|= MK_CONTROL
;
406 /***********************************************************************
409 static void EVENT_Expose( WND
*pWnd
, XExposeEvent
*event
)
413 /* Make position relative to client area instead of window */
414 rect
.left
= event
->x
- (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
);
415 rect
.top
= event
->y
- (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
);
416 rect
.right
= rect
.left
+ event
->width
;
417 rect
.bottom
= rect
.top
+ event
->height
;
419 PAINT_RedrawWindow( pWnd
->hwndSelf
, &rect
, 0,
420 RDW_INVALIDATE
| RDW_FRAME
| RDW_ALLCHILDREN
| RDW_ERASE
|
421 (event
->count
? 0 : RDW_ERASENOW
), 0 );
425 /***********************************************************************
426 * EVENT_GraphicsExpose
428 * This is needed when scrolling area is partially obscured
429 * by non-Wine X window.
431 static void EVENT_GraphicsExpose( WND
*pWnd
, XGraphicsExposeEvent
*event
)
435 /* Make position relative to client area instead of window */
436 rect
.left
= event
->x
- (pWnd
->rectClient
.left
- pWnd
->rectWindow
.left
);
437 rect
.top
= event
->y
- (pWnd
->rectClient
.top
- pWnd
->rectWindow
.top
);
438 rect
.right
= rect
.left
+ event
->width
;
439 rect
.bottom
= rect
.top
+ event
->height
;
441 PAINT_RedrawWindow( pWnd
->hwndSelf
, &rect
, 0,
442 RDW_INVALIDATE
| RDW_ALLCHILDREN
| RDW_ERASE
|
443 (event
->count
? 0 : RDW_ERASENOW
), 0 );
447 /***********************************************************************
450 * Handle a X key event
453 /* Keyboard translation tables */
454 static const int special_key
[] =
456 VK_BACK
, VK_TAB
, 0, VK_CLEAR
, 0, VK_RETURN
, 0, 0, /* FF08 */
457 0, 0, 0, VK_PAUSE
, VK_SCROLL
, 0, 0, 0, /* FF10 */
458 0, 0, 0, VK_ESCAPE
/* FF18 */
461 static const int cursor_key
[] =
463 VK_HOME
, VK_LEFT
, VK_UP
, VK_RIGHT
, VK_DOWN
, VK_PRIOR
,
464 VK_NEXT
, VK_END
/* FF50 */
467 static const int misc_key
[] =
469 VK_SELECT
, VK_SNAPSHOT
, VK_EXECUTE
, VK_INSERT
, 0, 0, 0, 0, /* FF60 */
470 VK_CANCEL
, VK_HELP
, VK_CANCEL
, VK_MENU
/* FF68 */
473 static const int keypad_key
[] =
475 0, VK_NUMLOCK
, /* FF7E */
476 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
477 0, 0, 0, 0, 0, VK_RETURN
, 0, 0, /* FF88 */
478 0, 0, 0, 0, 0, VK_HOME
, VK_LEFT
, VK_UP
, /* FF90 */
479 VK_RIGHT
, VK_DOWN
, VK_PRIOR
, VK_NEXT
, VK_END
, 0,
480 VK_INSERT
, VK_DELETE
, /* FF98 */
481 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
482 0, 0, VK_MULTIPLY
, VK_ADD
, VK_SEPARATOR
, VK_SUBTRACT
,
483 VK_DECIMAL
, VK_DIVIDE
, /* FFA8 */
484 VK_NUMPAD0
, VK_NUMPAD1
, VK_NUMPAD2
, VK_NUMPAD3
, VK_NUMPAD4
,
485 VK_NUMPAD5
, VK_NUMPAD6
, VK_NUMPAD7
, /* FFB0 */
486 VK_NUMPAD8
, VK_NUMPAD9
/* FFB8 */
489 static const int function_key
[] =
491 VK_F1
, VK_F2
, /* FFBE */
492 VK_F3
, VK_F4
, VK_F5
, VK_F6
, VK_F7
, VK_F8
, VK_F9
, VK_F10
, /* FFC0 */
493 VK_F11
, VK_F12
, VK_F13
, VK_F14
, VK_F15
, VK_F16
/* FFC8 */
496 static const int modifier_key
[] =
498 VK_SHIFT
, VK_SHIFT
, VK_CONTROL
, VK_CONTROL
, VK_CAPITAL
, 0, /* FFE1 */
499 VK_MENU
, VK_MENU
, VK_MENU
, VK_MENU
/* FFE7 */
502 static int AltGrMask
;
503 static int min_keycode
, max_keycode
;
504 static int keyc2vkey
[256];
505 /* For example : keyc2vkey[10] is the VK_* associated with keycode10 */
507 static WORD
EVENT_event_to_vkey( XKeyEvent
*e
)
509 static int keysyms_per_keycode
;
513 if (!keysyms_per_keycode
) /* First time : Initialization */
516 XModifierKeymap
*mmp
;
521 XDisplayKeycodes(e
->display
, &min_keycode
, &max_keycode
);
522 ksp
= XGetKeyboardMapping(e
->display
, min_keycode
,
523 max_keycode
+ 1 - min_keycode
, &keysyms_per_keycode
);
524 /* We are only interested in keysyms_per_keycode.
525 There is no need to hold a local copy of the keysyms table */
527 mmp
= XGetModifierMapping(e
->display
);
528 kcp
= mmp
->modifiermap
;
529 for (i
= 0; i
< 8; i
+= 1) /* There are 8 modifier keys */
533 for (j
= 0; j
< mmp
->max_keypermod
; j
+= 1, kcp
+= 1)
538 for (k
= 0; k
< keysyms_per_keycode
; k
+= 1)
539 if (XKeycodeToKeysym(e
->display
, *kcp
, k
)
543 dprintf_key(stddeb
, "AltGrMask is %x\n", AltGrMask
);
547 XFreeModifiermap(mmp
);
549 /* Now build two conversion arrays :
550 * keycode -> vkey + extended
551 * vkey + extended -> keycode */
553 e2
.display
= e
->display
;
556 OEMvkey
= 0xb9; /* first OEM virtual key available is ba */
557 for (e2
.keycode
=min_keycode
; e2
.keycode
<=max_keycode
; e2
.keycode
++)
559 XLookupString(&e2
, NULL
, 0, &keysym
, NULL
);
561 if (keysym
) /* otherwise, keycode not used */
563 if ((keysym
>> 8) == 0xFF) /* non-character key */
565 int key
= keysym
& 0xff;
567 if (key
>= 0x08 && key
<= 0x1B) /* special key */
568 vkey
= special_key
[key
- 0x08];
569 else if (key
>= 0x50 && key
<= 0x57) /* cursor key */
570 vkey
= cursor_key
[key
- 0x50];
571 else if (key
>= 0x60 && key
<= 0x6B) /* miscellaneous key */
572 vkey
= misc_key
[key
- 0x60];
573 else if (key
>= 0x7E && key
<= 0xB9) /* keypad key */
574 vkey
= keypad_key
[key
- 0x7E];
575 else if (key
>= 0xBE && key
<= 0xCD) /* function key */
577 vkey
= function_key
[key
- 0xBE];
578 vkey
|= 0x100; /* set extended bit */
580 else if (key
>= 0xE1 && key
<= 0xEA) /* modifier key */
581 vkey
= modifier_key
[key
- 0xE1];
582 else if (key
== 0xFF) /* DEL key */
584 /* extended must also be set for ALT_R, CTRL_R,
585 INS, DEL, HOME, END, PAGE_UP, PAGE_DOWN, ARROW keys,
586 keypad / and keypad ENTER (SDK 3.1 Vol.3 p 138) */
606 for (i
= 0; (i
< keysyms_per_keycode
) && (!vkey
); i
++)
608 keysym
= XLookupKeysym(&e2
, i
);
609 if ((keysym
>= VK_0
&& keysym
<= VK_9
)
610 || (keysym
>= VK_A
&& keysym
<= VK_Z
)
611 || keysym
== VK_SPACE
)
617 /* Others keys: let's assign OEM virtual key codes in the allowed range,
618 * that is ([0xba,0xc0], [0xdb,0xe4], 0xe6 (given up) et [0xe9,0xf5]) */
621 case 0xc1 : OEMvkey
=0xdb; break;
622 case 0xe5 : OEMvkey
=0xe9; break;
623 case 0xf6 : OEMvkey
=0xf5; fprintf(stderr
,"No more OEM vkey available!\n");
628 if (debugging_keyboard
)
630 fprintf(stddeb
,"OEM specific virtual key %X assigned to keycode %X :\n ("
631 ,OEMvkey
,e2
.keycode
);
632 for (i
= 0; i
< keysyms_per_keycode
; i
+= 1)
636 keysym
= XLookupKeysym(&e2
, i
);
637 ksname
= XKeysymToString(keysym
);
640 fprintf(stddeb
, "%lX (%s) ", keysym
, ksname
);
642 fprintf(stddeb
, ")\n");
646 keyc2vkey
[e2
.keycode
] = vkey
;
648 } /* Initialization */
650 return keyc2vkey
[e
->keycode
];
654 int EVENT_ToAscii(WORD wVirtKey
, WORD wScanCode
, LPSTR lpKeyState
,
655 LPVOID lpChar
, WORD wFlags
)
659 static XComposeStatus cs
;
665 for (keyc
=min_keycode
; keyc
<=max_keycode
; keyc
++)
666 { /* this could be speed up by making another table, an array of struct vkey,keycode
667 * (vkey -> keycode) with vkeys sorted .... but it takes memory (512*3 bytes)! DF */
668 if ((keyc2vkey
[keyc
] & 0xFF)== wVirtKey
) /* no need to make a more precise test (with the extended bit correctly set above wVirtKey ... VK* are different enough... */
670 if ((e
.keycode
) && ((wVirtKey
<0x10) || (wVirtKey
>0x12)))
671 /* it's normal to have 2 shift, control, and alt ! */
672 dprintf_keyboard(stddeb
,"Strange ... the keycodes %X and %X are matching!\n",
679 fprintf(stderr
,"Unknown virtual key %X !!! \n",wVirtKey
);
680 return wVirtKey
; /* whatever */
683 if (lpKeyState
[VK_SHIFT
] & 0x80)
684 e
.state
|= ShiftMask
;
685 if (lpKeyState
[VK_CAPITAL
] & 0x80)
687 if (lpKeyState
[VK_CONTROL
] & 0x80)
688 if (lpKeyState
[VK_MENU
] & 0x80)
689 e
.state
|= AltGrMask
;
691 e
.state
|= ControlMask
;
692 if (lpKeyState
[VK_NUMLOCK
] & 0x80)
694 dprintf_key(stddeb
, "EVENT_ToAscii(%04X, %04X) : faked state = %X\n",
695 wVirtKey
, wScanCode
, e
.state
);
696 ret
= XLookupString(&e
, lpChar
, 2, &keysym
, &cs
);
701 ((char*)lpChar
)[1] = '\0';
705 case 0x1000FE7E : /* Xfree's XK_Dtilde */
709 case 0x1000FE27 : /* Xfree's XK_Dacute_accent */
712 case XK_dead_circumflex
:
713 case 0x1000FE5E : /* Xfree's XK_Dcircumflex_accent */
717 case 0x1000FE60 : /* Xfree's XK_Dgrave_accent */
720 case XK_dead_diaeresis
:
721 case 0x1000FE22 : /* Xfree's XK_Ddiaeresis */
727 *(char*)lpChar
= dead_char
;
734 ksname
= XKeysymToString(keysym
);
737 if ((keysym
>> 8) != 0xff)
739 fprintf(stderr
, "Please report : no char for keysym %04lX (%s) :\n",
741 fprintf(stderr
, " wVirtKey = %X, wScanCode = %X, keycode = %X, state = %X\n",
742 wVirtKey
, wScanCode
, e
.keycode
, e
.state
);
746 dprintf_key(stddeb
, "EVENT_ToAscii about to return %d with char %x\n",
747 ret
, *(char*)lpChar
);
755 unsigned long count
: 16;
756 unsigned long code
: 8;
757 unsigned long extended
: 1;
758 unsigned long unused
: 2;
759 unsigned long win_internal
: 2;
760 unsigned long context
: 1;
761 unsigned long previous
: 1;
762 unsigned long transition
: 1;
767 static void EVENT_key( XKeyEvent
*event
)
775 static BOOL force_extended
= FALSE
; /* hack for AltGr translation */
777 int ascii_chars
= XLookupString(event
, Str
, 1, &keysym
, &cs
);
779 dprintf_key(stddeb
, "EVENT_key : state = %X\n", event
->state
);
780 if (keysym
== XK_Mode_switch
)
782 dprintf_key(stddeb
, "Alt Gr key event received\n");
783 event
->keycode
= XKeysymToKeycode(event
->display
, XK_Control_L
);
784 dprintf_key(stddeb
, "Control_L is keycode 0x%x\n", event
->keycode
);
786 event
->keycode
= XKeysymToKeycode(event
->display
, XK_Alt_L
);
787 dprintf_key(stddeb
, "Alt_L is keycode 0x%x\n", event
->keycode
);
788 force_extended
= TRUE
;
790 force_extended
= FALSE
;
794 Str
[ascii_chars
] = '\0';
799 ksname
= XKeysymToString(keysym
);
802 fprintf(stddeb
, "%s : keysym=%lX (%s), ascii chars=%u / %X / '%s'\n",
803 event_names
[event
->type
], keysym
, ksname
,
804 ascii_chars
, Str
[0] & 0xff, Str
);
808 /* Ctrl-Alt-Return enters the debugger */
809 if ((keysym
== XK_Return
) && (event
->type
== KeyPress
) &&
810 (event
->state
& ControlMask
) && (event
->state
& Mod1Mask
))
811 DEBUG_EnterDebugger();
814 vkey
= EVENT_event_to_vkey(event
);
815 if (force_extended
) vkey
|= 0x100;
817 dprintf_key(stddeb
, "keycode 0x%x converted to vkey 0x%x\n",
818 event
->keycode
, vkey
);
821 keylp
.lp1
.code
= LOBYTE(event
->keycode
) - 8;
822 keylp
.lp1
.extended
= (vkey
& 0x100 ? 1 : 0);
823 keylp
.lp1
.win_internal
= 0; /* this has something to do with dialogs,
824 * don't remember where I read it - AK */
825 /* it's '1' under windows, when a dialog box appears
826 * and you press one of the underlined keys - DF*/
828 if (event
->type
== KeyPress
)
830 keylp
.lp1
.previous
= (InputKeyStateTable
[vkey
] & 0x80) != 0;
831 if (!(InputKeyStateTable
[vkey
] & 0x80))
832 InputKeyStateTable
[vkey
] ^= 0x01;
833 InputKeyStateTable
[vkey
] |= 0x80;
834 keylp
.lp1
.transition
= 0;
835 message
= (InputKeyStateTable
[VK_MENU
] & 0x80)
836 && !(InputKeyStateTable
[VK_CONTROL
] & 0x80)
837 ? WM_SYSKEYDOWN
: WM_KEYDOWN
;
841 UINT sysKey
= (InputKeyStateTable
[VK_MENU
] & 0x80)
842 && !(InputKeyStateTable
[VK_CONTROL
] & 0x80)
843 && (force_extended
== FALSE
); /* for Alt from AltGr */
845 InputKeyStateTable
[vkey
] &= ~0x80;
846 keylp
.lp1
.previous
= 1;
847 keylp
.lp1
.transition
= 1;
848 message
= sysKey
? WM_SYSKEYUP
: WM_KEYUP
;
850 keylp
.lp1
.context
= ( (event
->state
& Mod1Mask
) ||
851 (InputKeyStateTable
[VK_MENU
] & 0x80)) ? 1 : 0;
852 dprintf_key(stddeb
," wParam=%04X, lParam=%08lX\n",
854 dprintf_key(stddeb
," InputKeyState=%X\n",
855 InputKeyStateTable
[vkey
]);
857 hardware_event( message
, vkey
, keylp
.lp2
, event
->x_root
- desktopX
,
858 event
->y_root
- desktopY
, event
->time
- MSG_WineStartTicks
, 0 );
862 /***********************************************************************
865 static void EVENT_MotionNotify( XMotionEvent
*event
)
867 hardware_event( WM_MOUSEMOVE
, EVENT_XStateToKeyState( event
->state
), 0L,
868 event
->x_root
- desktopX
, event
->y_root
- desktopY
,
869 event
->time
- MSG_WineStartTicks
, 0 );
873 /***********************************************************************
874 * EVENT_DummyMotionNotify
876 * Generate a dummy MotionNotify event. Used to force a WM_SETCURSOR message.
878 void EVENT_DummyMotionNotify(void)
881 int rootX
, rootY
, childX
, childY
;
884 if (XQueryPointer( display
, rootWindow
, &root
, &child
,
885 &rootX
, &rootY
, &childX
, &childY
, &state
))
887 hardware_event(WM_MOUSEMOVE
, EVENT_XStateToKeyState( state
), 0L,
888 rootX
- desktopX
, rootY
- desktopY
, GetTickCount(), 0 );
893 /***********************************************************************
896 static void EVENT_ButtonPress( XButtonEvent
*event
)
898 static WORD messages
[NB_BUTTONS
] =
899 { WM_LBUTTONDOWN
, WM_MBUTTONDOWN
, WM_RBUTTONDOWN
};
900 int buttonNum
= event
->button
- 1;
902 if (buttonNum
>= NB_BUTTONS
) return;
903 MouseButtonsStates
[buttonNum
] = 0x8000;
904 AsyncMouseButtonsStates
[buttonNum
] = 0x8000;
905 hardware_event( messages
[buttonNum
],
906 EVENT_XStateToKeyState( event
->state
), 0L,
907 event
->x_root
- desktopX
, event
->y_root
- desktopY
,
908 event
->time
- MSG_WineStartTicks
, 0 );
912 /***********************************************************************
913 * EVENT_ButtonRelease
915 static void EVENT_ButtonRelease( XButtonEvent
*event
)
917 static const WORD messages
[NB_BUTTONS
] =
918 { WM_LBUTTONUP
, WM_MBUTTONUP
, WM_RBUTTONUP
};
919 int buttonNum
= event
->button
- 1;
921 if (buttonNum
>= NB_BUTTONS
) return;
922 MouseButtonsStates
[buttonNum
] = FALSE
;
923 hardware_event( messages
[buttonNum
],
924 EVENT_XStateToKeyState( event
->state
), 0L,
925 event
->x_root
- desktopX
, event
->y_root
- desktopY
,
926 event
->time
- MSG_WineStartTicks
, 0 );
930 /**********************************************************************
933 static void EVENT_FocusIn (HWND hwnd
, XFocusChangeEvent
*event
)
935 if (event
->detail
== NotifyPointer
) return;
936 if (hwnd
!= GetActiveWindow()) WINPOS_ChangeActiveWindow( hwnd
, FALSE
);
937 if ((hwnd
!= GetFocus32()) && !IsChild( hwnd
, GetFocus32()))
942 /**********************************************************************
945 * Note: only top-level override-redirect windows get FocusOut events.
947 static void EVENT_FocusOut( HWND hwnd
, XFocusChangeEvent
*event
)
949 if (event
->detail
== NotifyPointer
) return;
950 if (hwnd
== GetActiveWindow()) WINPOS_ChangeActiveWindow( 0, FALSE
);
951 if ((hwnd
== GetFocus32()) || IsChild( hwnd
, GetFocus32()))
956 /**********************************************************************
957 * EVENT_ConfigureNotify
959 * The ConfigureNotify event is only selected on the desktop window
960 * and on top-level windows when the -managed flag is used.
962 static void EVENT_ConfigureNotify( HWND hwnd
, XConfigureEvent
*event
)
964 /* FIXME: with -desktop xxx we get this event _before_ desktop
965 * window structure is created. WIN_GetDesktop() check is a hack.
968 if ( !WIN_GetDesktop() || hwnd
== GetDesktopWindow32())
977 RECT16 newWindowRect
, newClientRect
;
978 HRGN32 hrgnOldPos
, hrgnNewPos
;
980 if (!(wndPtr
= WIN_FindWndPtr( hwnd
)) ||
981 !(wndPtr
->flags
& WIN_MANAGED
) )
984 if (!(winpos
= SEGPTR_NEW(WINDOWPOS16
))) return;
986 /* XTranslateCoordinates(display, event->window, rootWindow,
987 event->x, event->y, &event->x, &event->y, &child);
990 /* Fill WINDOWPOS struct */
991 winpos
->flags
= SWP_NOACTIVATE
| SWP_NOZORDER
;
993 winpos
->x
= event
->x
;
994 winpos
->y
= event
->y
;
995 winpos
->cx
= event
->width
;
996 winpos
->cy
= event
->height
;
998 /* Check for unchanged attributes */
999 if(winpos
->x
== wndPtr
->rectWindow
.left
&&
1000 winpos
->y
== wndPtr
->rectWindow
.top
)
1001 winpos
->flags
|= SWP_NOMOVE
;
1002 if(winpos
->cx
== wndPtr
->rectWindow
.right
- wndPtr
->rectWindow
.left
&&
1003 winpos
->cy
== wndPtr
->rectWindow
.bottom
- wndPtr
->rectWindow
.top
)
1004 winpos
->flags
|= SWP_NOSIZE
;
1006 /* Send WM_WINDOWPOSCHANGING */
1007 SendMessage16(hwnd
, WM_WINDOWPOSCHANGING
, 0, (LPARAM
)SEGPTR_GET(winpos
));
1009 /* Calculate new position and size */
1010 newWindowRect
.left
= event
->x
;
1011 newWindowRect
.right
= event
->x
+ event
->width
;
1012 newWindowRect
.top
= event
->y
;
1013 newWindowRect
.bottom
= event
->y
+ event
->height
;
1015 WINPOS_SendNCCalcSize( winpos
->hwnd
, TRUE
, &newWindowRect
,
1016 &wndPtr
->rectWindow
, &wndPtr
->rectClient
,
1017 SEGPTR_GET(winpos
), &newClientRect
);
1019 hrgnOldPos
= CreateRectRgnIndirect16( &wndPtr
->rectWindow
);
1020 hrgnNewPos
= CreateRectRgnIndirect16( &newWindowRect
);
1021 CombineRgn32( hrgnOldPos
, hrgnOldPos
, hrgnNewPos
, RGN_DIFF
);
1023 /* Set new size and position */
1024 wndPtr
->rectWindow
= newWindowRect
;
1025 wndPtr
->rectClient
= newClientRect
;
1026 SendMessage16( hwnd
, WM_WINDOWPOSCHANGED
, 0, (LPARAM
)SEGPTR_GET(winpos
));
1027 SEGPTR_FREE(winpos
);
1029 /* full window drag leaves unrepainted garbage without this */
1030 PAINT_RedrawWindow( 0, NULL
, hrgnOldPos
, RDW_INVALIDATE
|
1031 RDW_ALLCHILDREN
| RDW_ERASE
| RDW_ERASENOW
,
1033 DeleteObject32(hrgnOldPos
);
1034 DeleteObject32(hrgnNewPos
);
1039 /***********************************************************************
1040 * EVENT_SelectionRequest
1042 static void EVENT_SelectionRequest( WND
*pWnd
, XSelectionRequestEvent
*event
)
1044 XSelectionEvent result
;
1046 Window request
= event
->requestor
;
1048 if(event
->target
== XA_STRING
)
1054 rprop
= event
->property
;
1056 if(rprop
== None
) rprop
= event
->target
;
1058 if(event
->selection
!=XA_PRIMARY
) rprop
= None
;
1059 else if(!CLIPBOARD_IsPresent(CF_OEMTEXT
)) rprop
= None
;
1062 /* open to make sure that clipboard is available */
1064 BOOL couldOpen
= OpenClipboard( pWnd
->hwndSelf
);
1067 hText
= GetClipboardData(CF_TEXT
);
1068 text
= GlobalLock16(hText
);
1069 size
= GlobalSize16(hText
);
1071 /* remove carriage returns */
1073 lpstr
= (char*)xmalloc(size
--);
1074 for(i
=0,j
=0; i
< size
&& text
[i
]; i
++ )
1076 if( text
[i
] == '\r' &&
1077 (text
[i
+1] == '\n' || text
[i
+1] == '\0') ) continue;
1078 lpstr
[j
++] = text
[i
];
1082 XChangeProperty(display
, request
, rprop
,
1083 XA_STRING
, 8, PropModeReplace
,
1087 /* close only if we opened before */
1089 if(couldOpen
) CloseClipboard();
1094 dprintf_event(stddeb
,"Request for %s ignored\n", XGetAtomName(display
,event
->target
));
1096 result
.type
=SelectionNotify
;
1097 result
.display
=display
;
1098 result
.requestor
=request
;
1099 result
.selection
=event
->selection
;
1100 result
.property
=rprop
;
1101 result
.target
=event
->target
;
1102 result
.time
=event
->time
;
1103 XSendEvent(display
,event
->requestor
,False
,NoEventMask
,(XEvent
*)&result
);
1107 /***********************************************************************
1108 * EVENT_SelectionNotify
1110 static void EVENT_SelectionNotify( XSelectionEvent
*event
)
1112 if (event
->selection
!= XA_PRIMARY
) return;
1114 if (event
->target
!= XA_STRING
) CLIPBOARD_ReadSelection( 0, None
);
1115 else CLIPBOARD_ReadSelection( event
->requestor
, event
->property
);
1117 dprintf_clipboard(stddeb
,"\tSelectionNotify done!\n");
1121 /***********************************************************************
1122 * EVENT_SelectionClear
1124 static void EVENT_SelectionClear( WND
*pWnd
, XSelectionClearEvent
*event
)
1126 if (event
->selection
!= XA_PRIMARY
) return;
1127 CLIPBOARD_ReleaseSelection( event
->window
, pWnd
->hwndSelf
);
1131 /**********************************************************************
1132 * EVENT_ClientMessage
1134 static void EVENT_ClientMessage( WND
*pWnd
, XClientMessageEvent
*event
)
1136 if (event
->message_type
!= None
&& event
->format
== 32)
1138 if ((event
->message_type
== wmProtocols
) &&
1139 (((Atom
) event
->data
.l
[0]) == wmDeleteWindow
))
1140 SendMessage16( pWnd
->hwndSelf
, WM_SYSCOMMAND
, SC_CLOSE
, 0 );
1141 else if ( event
->message_type
== dndProtocol
&&
1142 (event
->data
.l
[0] == DndFile
|| event
->data
.l
[0] == DndFiles
) )
1144 unsigned long data_length
;
1145 unsigned long aux_long
;
1146 unsigned char* p_data
= NULL
;
1154 HGLOBAL16 hDragInfo
= GlobalAlloc16( GMEM_SHARE
| GMEM_ZEROINIT
, sizeof(DRAGINFO
));
1155 LPDRAGINFO lpDragInfo
= (LPDRAGINFO
) GlobalLock16(hDragInfo
);
1156 SEGPTR spDragInfo
= (SEGPTR
) WIN16_GlobalLock16(hDragInfo
);
1157 Window w_aux_root
, w_aux_child
;
1160 if( !lpDragInfo
|| !spDragInfo
) return;
1162 XQueryPointer( display
, pWnd
->window
, &w_aux_root
, &w_aux_child
,
1163 &x
, &y
, &u
.pt_aux
.x
, &u
.pt_aux
.y
, (unsigned int*)&aux_long
);
1165 lpDragInfo
->hScope
= pWnd
->hwndSelf
;
1166 lpDragInfo
->pt
.x
= (INT16
)x
; lpDragInfo
->pt
.y
= (INT16
)y
;
1168 /* find out drop point and drop window */
1169 if( x
< 0 || y
< 0 ||
1170 x
> (pWnd
->rectWindow
.right
- pWnd
->rectWindow
.left
) ||
1171 y
> (pWnd
->rectWindow
.bottom
- pWnd
->rectWindow
.top
) )
1172 { bAccept
= pWnd
->dwExStyle
& WS_EX_ACCEPTFILES
; x
= y
= 0; }
1175 bAccept
= DRAG_QueryUpdate( pWnd
->hwndSelf
, spDragInfo
, TRUE
);
1176 x
= lpDragInfo
->pt
.x
; y
= lpDragInfo
->pt
.y
;
1178 pDropWnd
= WIN_FindWndPtr( lpDragInfo
->hScope
);
1179 GlobalFree16( hDragInfo
);
1183 XGetWindowProperty( display
, DefaultRootWindow(display
),
1184 dndSelection
, 0, 65535, FALSE
,
1185 AnyPropertyType
, &u
.atom_aux
, &u
.pt_aux
.y
,
1186 &data_length
, &aux_long
, &p_data
);
1188 if( !aux_long
&& p_data
) /* don't bother if > 64K */
1190 char *p
= (char*) p_data
;
1194 while( *p
) /* calculate buffer size */
1197 if((u
.i
= *p
) != -1 )
1198 u
.i
= DRIVE_FindDriveRoot( (const char **)&p_drop
);
1199 if( u
.i
== -1 ) *p
= -1; /* mark as "bad" */
1202 INT32 len
= GetShortPathName32A( p
, NULL
, 0 );
1203 if (len
) aux_long
+= len
+ 1;
1208 if( aux_long
&& aux_long
< 65535 )
1211 LPDROPFILESTRUCT lpDrop
;
1213 aux_long
+= sizeof(DROPFILESTRUCT
) + 1;
1214 hDrop
= (HDROP16
)GlobalAlloc16( GMEM_SHARE
, aux_long
);
1215 lpDrop
= (LPDROPFILESTRUCT
) GlobalLock16( hDrop
);
1219 lpDrop
->wSize
= sizeof(DROPFILESTRUCT
);
1220 lpDrop
->ptMousePos
.x
= (INT16
)x
;
1221 lpDrop
->ptMousePos
.y
= (INT16
)y
;
1222 lpDrop
->fInNonClientArea
= (BOOL16
)
1223 ( x
< (pDropWnd
->rectClient
.left
- pDropWnd
->rectWindow
.left
) ||
1224 y
< (pDropWnd
->rectClient
.top
- pDropWnd
->rectWindow
.top
) ||
1225 x
> (pDropWnd
->rectClient
.right
- pDropWnd
->rectWindow
.left
) ||
1226 y
> (pDropWnd
->rectClient
.bottom
- pDropWnd
->rectWindow
.top
) );
1227 p_drop
= ((char*)lpDrop
) + sizeof(DROPFILESTRUCT
);
1231 if( *p
!= -1 ) /* use only "good" entries */
1233 GetShortPathName32A( p
, p_drop
, 65535 );
1234 p_drop
+= strlen( p_drop
) + 1;
1239 PostMessage( pWnd
->hwndSelf
, WM_DROPFILES
, (WPARAM16
)hDrop
, 0L );
1243 if( p_data
) XFree(p_data
);
1245 } /* WS_EX_ACCEPTFILES */
1248 dprintf_event( stddeb
, "unrecognized ClientMessage\n" );
1252 /**********************************************************************
1255 * Install colormap when Wine window is focused in
1256 * self-managed mode with private colormap
1259 void EVENT_EnterNotify( WND *pWnd, XCrossingEvent *event )
1261 if( !Options.managed && rootWindow == DefaultRootWindow(display) &&
1262 (COLOR_GetSystemPaletteFlags() & COLOR_PRIVATE) && GetFocus32() )
1263 XInstallColormap( display, COLOR_GetColormap() );
1267 /**********************************************************************
1270 void EVENT_MapNotify( HWND hWnd
, XMapEvent
*event
)
1272 HWND32 hwndFocus
= GetFocus32();
1274 if (hwndFocus
&& IsChild( hWnd
, hwndFocus
))
1275 FOCUS_SetXFocus( (HWND32
)hwndFocus
);
1280 /**********************************************************************
1283 * We need this to be able to generate double click messages
1284 * when menu code captures mouse in the window without CS_DBLCLK style.
1286 HWND32
EVENT_Capture(HWND32 hwnd
, INT16 ht
)
1289 HWND32 old_capture_wnd
= captureWnd
;
1294 return old_capture_wnd
;
1296 if ((win
= WIN_GetXWindow( hwnd
)))
1298 if (XGrabPointer(display
, win
, False
,
1299 ButtonPressMask
| ButtonReleaseMask
| PointerMotionMask
,
1300 GrabModeAsync
, GrabModeAsync
,
1301 None
, None
, CurrentTime
) == GrabSuccess
)
1303 dprintf_win(stddeb
, "SetCapture: %04x\n", hwnd
);
1306 return old_capture_wnd
;
1312 /**********************************************************************
1313 * EVENT_GetCaptureInfo
1315 INT16
EVENT_GetCaptureInfo()
1320 /**********************************************************************
1321 * SetCapture16 (USER.18)
1323 HWND16
SetCapture16( HWND16 hwnd
)
1325 return (HWND16
)EVENT_Capture( hwnd
, HTCLIENT
);
1329 /**********************************************************************
1330 * SetCapture32 (USER32.463)
1332 HWND32
SetCapture32( HWND32 hwnd
)
1334 return EVENT_Capture( hwnd
, HTCLIENT
);
1338 /**********************************************************************
1339 * ReleaseCapture (USER.19) (USER32.438)
1341 void ReleaseCapture(void)
1343 if (captureWnd
== 0) return;
1344 XUngrabPointer( display
, CurrentTime
);
1346 dprintf_win(stddeb
, "ReleaseCapture\n");
1350 /**********************************************************************
1351 * GetCapture16 (USER.236)
1353 HWND16
GetCapture16(void)
1355 return (HWND16
)captureWnd
;
1359 /**********************************************************************
1360 * GetCapture32 (USER32.207)
1362 HWND32
GetCapture32(void)
1368 /***********************************************************************
1369 * GetMouseEventProc (USER.337)
1371 FARPROC16
GetMouseEventProc(void)
1373 HMODULE16 hmodule
= GetModuleHandle("USER");
1374 return MODULE_GetEntryPoint( hmodule
,
1375 MODULE_GetOrdinal( hmodule
, "Mouse_Event" ) );
1379 /***********************************************************************
1380 * Mouse_Event (USER.299)
1382 void Mouse_Event( CONTEXT
*context
)
1386 * BX = horizontal displacement if AX & ME_MOVE
1387 * CX = vertical displacement if AX & ME_MOVE
1388 * DX = button state (?)
1389 * SI = mouse event flags (?)
1392 int rootX
, rootY
, childX
, childY
;
1395 if (AX_reg(context
) & ME_MOVE
)
1397 /* We have to actually move the cursor */
1398 XWarpPointer( display
, rootWindow
, None
, 0, 0, 0, 0,
1399 (short)BX_reg(context
), (short)CX_reg(context
) );
1402 if (!XQueryPointer( display
, rootWindow
, &root
, &child
,
1403 &rootX
, &rootY
, &childX
, &childY
, &state
)) return;
1404 if (AX_reg(context
) & ME_LDOWN
)
1405 hardware_event( WM_LBUTTONDOWN
, EVENT_XStateToKeyState( state
), 0L,
1406 rootX
- desktopX
, rootY
- desktopY
, GetTickCount(), 0);
1407 if (AX_reg(context
) & ME_LUP
)
1408 hardware_event( WM_LBUTTONUP
, EVENT_XStateToKeyState( state
), 0L,
1409 rootX
- desktopX
, rootY
- desktopY
, GetTickCount(), 0);
1410 if (AX_reg(context
) & ME_RDOWN
)
1411 hardware_event( WM_RBUTTONDOWN
, EVENT_XStateToKeyState( state
), 0L,
1412 rootX
- desktopX
, rootY
- desktopY
, GetTickCount(), 0);
1413 if (AX_reg(context
) & ME_RUP
)
1414 hardware_event( WM_RBUTTONUP
, EVENT_XStateToKeyState( state
), 0L,
1415 rootX
- desktopX
, rootY
- desktopY
, GetTickCount(), 0);
1419 /**********************************************************************
1420 * EnableHardwareInput (USER.331)
1422 BOOL16
EnableHardwareInput(BOOL16 bEnable
)
1424 BOOL16 bOldState
= InputEnabled
;
1425 dprintf_event(stdnimp
,"EnableHardwareInput(%d);\n", bEnable
);
1426 InputEnabled
= bEnable
;