Alexandre Julliard : winex11: Retrieve raw mouse events through XInput2 while the cursor is clipped.
Alexandre Julliard
julliard at winehq.org
Thu Apr 14 11:58:19 CDT 2011
Module: wine
Branch: master
Commit: bd3ec1a973fef5ff46a6242aa4e04dd4b7a40799
URL: http://source.winehq.org/git/wine.git/?a=commit;h=bd3ec1a973fef5ff46a6242aa4e04dd4b7a40799
Author: Alexandre Julliard <julliard at winehq.org>
Date: Wed Apr 13 20:18:30 2011 +0200
winex11: Retrieve raw mouse events through XInput2 while the cursor is clipped.
---
dlls/winex11.drv/event.c | 2 +-
dlls/winex11.drv/mouse.c | 178 +++++++++++++++++++++++++++++++++++++++-
dlls/winex11.drv/x11drv.h | 3 +
dlls/winex11.drv/x11drv_main.c | 1 +
4 files changed, 179 insertions(+), 5 deletions(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index d3ed4b0..62aea5e 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -795,7 +795,7 @@ static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
*/
static void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
{
- if (event->xany.window == clip_window) clipping_cursor = 0;
+ if (event->xany.window == clip_window) clipping_window_unmapped();
}
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index e3774dc..a1c913f 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -128,6 +128,17 @@ static XContext cursor_context;
static RECT clip_rect;
static Cursor create_cursor( HANDLE handle );
+#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
+static BOOL xinput2_available;
+static int xinput2_opcode;
+static int xinput2_core_pointer;
+#define MAKE_FUNCPTR(f) static typeof(f) * p##f
+MAKE_FUNCPTR(XIFreeDeviceInfo);
+MAKE_FUNCPTR(XIQueryDevice);
+MAKE_FUNCPTR(XIQueryVersion);
+MAKE_FUNCPTR(XISelectEvents);
+#undef MAKE_FUNCPTR
+#endif
/***********************************************************************
* X11DRV_Xcursor_Init
@@ -239,6 +250,124 @@ void sync_window_cursor( Window window )
}
/***********************************************************************
+ * enable_xinput2
+ */
+static void enable_xinput2(void)
+{
+#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
+ struct x11drv_thread_data *data = x11drv_thread_data();
+ XIDeviceInfo *devices;
+ XIEventMask mask;
+ unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)];
+ int i, count;
+
+ if (!xinput2_available) return;
+
+ if (data->xi2_state == xi_unknown)
+ {
+ int major = 2, minor = 0;
+ wine_tsx11_lock();
+ if (!pXIQueryVersion( data->display, &major, &minor )) data->xi2_state = xi_disabled;
+ else
+ {
+ data->xi2_state = xi_unavailable;
+ WARN( "X Input 2 not available\n" );
+ }
+ wine_tsx11_unlock();
+ }
+ if (data->xi2_state == xi_unavailable) return;
+
+ wine_tsx11_lock();
+ devices = pXIQueryDevice( data->display, XIAllDevices, &count );
+ for (i = 0; i < count; ++i)
+ {
+ if (devices[i].use != XIMasterPointer) continue;
+ TRACE( "Using %u (%s) as core pointer\n",
+ devices[i].deviceid, debugstr_a(devices[i].name) );
+ xinput2_core_pointer = devices[i].deviceid;
+ break;
+ }
+
+ mask.mask = mask_bits;
+ mask.mask_len = sizeof(mask_bits);
+ memset( mask_bits, 0, sizeof(mask_bits) );
+
+ XISetMask( mask_bits, XI_RawButtonPress );
+ XISetMask( mask_bits, XI_RawButtonRelease );
+ XISetMask( mask_bits, XI_RawMotion );
+
+ for (i = 0; i < count; ++i)
+ {
+ if (devices[i].use == XISlavePointer && devices[i].attachment == xinput2_core_pointer)
+ {
+ TRACE( "Device %u (%s) is attached to the core pointer\n",
+ devices[i].deviceid, debugstr_a(devices[i].name) );
+ mask.deviceid = devices[i].deviceid;
+ pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 );
+ data->xi2_state = xi_enabled;
+ }
+ }
+
+ pXIFreeDeviceInfo( devices );
+ wine_tsx11_unlock();
+#endif
+}
+
+/***********************************************************************
+ * disable_xinput2
+ */
+static void disable_xinput2(void)
+{
+#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
+ struct x11drv_thread_data *data = x11drv_thread_data();
+ XIEventMask mask;
+ XIDeviceInfo *devices;
+ int i, count;
+
+ if (data->xi2_state != xi_enabled) return;
+
+ TRACE( "disabling\n" );
+ data->xi2_state = xi_disabled;
+
+ mask.mask = NULL;
+ mask.mask_len = 0;
+
+ wine_tsx11_lock();
+ devices = pXIQueryDevice( data->display, XIAllDevices, &count );
+ for (i = 0; i < count; ++i)
+ {
+ if (devices[i].use == XISlavePointer && devices[i].attachment == xinput2_core_pointer)
+ {
+ mask.deviceid = devices[i].deviceid;
+ pXISelectEvents( data->display, DefaultRootWindow( data->display ), &mask, 1 );
+ }
+ }
+ pXIFreeDeviceInfo( devices );
+ wine_tsx11_unlock();
+#endif
+}
+
+/***********************************************************************
+ * clipping_window_unmapped
+ *
+ * Turn off clipping when the window got unmapped.
+ */
+void clipping_window_unmapped(void)
+{
+ struct x11drv_thread_data *data = x11drv_thread_data();
+
+ clipping_cursor = 0;
+ if (data->xi2_state == xi_enabled)
+ {
+ RECT rect;
+ GetClipCursor( &rect );
+ if (EqualRect( &rect, &clip_rect )) return; /* still clipped */
+ disable_xinput2();
+ }
+}
+
+
+/***********************************************************************
* send_mouse_input
*
* Update the various window states on a mouse event.
@@ -254,7 +383,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU
{
input->u.mi.dx += clip_rect.left;
input->u.mi.dy += clip_rect.top;
- __wine_send_input( hwnd, input );
+ if (x11drv_thread_data()->xi2_state != xi_enabled) __wine_send_input( hwnd, input );
return;
}
@@ -913,14 +1042,16 @@ void CDECL X11DRV_SetCursor( HCURSOR handle )
*/
BOOL CDECL X11DRV_SetCursorPos( INT x, INT y )
{
- Display *display = thread_init_display();
+ struct x11drv_thread_data *data = x11drv_init_thread_data();
+
+ if (data->xi2_state == xi_enabled) return TRUE;
TRACE( "warping to (%d,%d)\n", x, y );
wine_tsx11_lock();
- XWarpPointer( display, root_window, root_window, 0, 0, 0, 0,
+ XWarpPointer( data->display, root_window, root_window, 0, 0, 0, 0,
x - virtual_screen_rect.left, y - virtual_screen_rect.top );
- XFlush( display ); /* avoids bad mouse lag in games that do their own mouse warping */
+ XFlush( data->display ); /* avoids bad mouse lag in games that do their own mouse warping */
wine_tsx11_unlock();
return TRUE;
}
@@ -983,6 +1114,7 @@ BOOL CDECL X11DRV_ClipCursor( LPCRECT clip )
if (clipping_cursor)
{
+ enable_xinput2();
sync_window_cursor( clip_window );
clip_rect = *clip;
return TRUE;
@@ -996,6 +1128,7 @@ BOOL CDECL X11DRV_ClipCursor( LPCRECT clip )
XUnmapWindow( display, clip_window );
wine_tsx11_unlock();
clipping_cursor = 0;
+ disable_xinput2();
return TRUE;
}
@@ -1175,6 +1308,42 @@ static void X11DRV_RawMotion( XIRawEvent *event )
/***********************************************************************
+ * X11DRV_XInput2_Init
+ */
+void X11DRV_XInput2_Init(void)
+{
+#if defined(SONAME_LIBXI) && defined(HAVE_X11_EXTENSIONS_XINPUT2_H)
+ int event, error;
+ void *libxi_handle = wine_dlopen( SONAME_LIBXI, RTLD_NOW, NULL, 0 );
+
+ if (!libxi_handle)
+ {
+ WARN( "couldn't load %s\n", SONAME_LIBXI );
+ return;
+ }
+#define LOAD_FUNCPTR(f) \
+ if (!(p##f = wine_dlsym( libxi_handle, #f, NULL, 0))) \
+ { \
+ WARN("Failed to load %s.\n", #f); \
+ return; \
+ }
+
+ LOAD_FUNCPTR(XIFreeDeviceInfo);
+ LOAD_FUNCPTR(XIQueryDevice);
+ LOAD_FUNCPTR(XIQueryVersion);
+ LOAD_FUNCPTR(XISelectEvents);
+#undef LOAD_FUNCPTR
+
+ wine_tsx11_lock();
+ xinput2_available = XQueryExtension( gdi_display, "XInputExtension", &xinput2_opcode, &event, &error );
+ wine_tsx11_unlock();
+#else
+ TRACE( "X Input 2 support not compiled in.\n" );
+#endif
+}
+
+
+/***********************************************************************
* X11DRV_GenericEvent
*/
void X11DRV_GenericEvent( HWND hwnd, XEvent *xev )
@@ -1183,6 +1352,7 @@ void X11DRV_GenericEvent( HWND hwnd, XEvent *xev )
XGenericEventCookie *event = &xev->xcookie;
if (!event->data) return;
+ if (event->extension != xinput2_opcode) return;
switch (event->evtype)
{
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index ae91fc9..8d05e27 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -258,6 +258,7 @@ extern void X11DRV_OpenGL_Cleanup(void);
extern void X11DRV_Xcursor_Init(void);
extern void X11DRV_BITMAP_Init(void);
extern void X11DRV_FONT_Init( int log_pixels_x, int log_pixels_y );
+extern void X11DRV_XInput2_Init(void);
extern int bitmap_info_size( const BITMAPINFO * info, WORD coloruse );
extern XImage *X11DRV_DIB_CreateXImage( int width, int height, int depth );
@@ -550,6 +551,7 @@ struct x11drv_thread_data
XFontSet font_set; /* international text drawing font set */
Window selection_wnd; /* window used for selection interactions */
HKL kbd_layout; /* active keyboard layout */
+ enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */
};
extern struct x11drv_thread_data *x11drv_init_thread_data(void);
@@ -823,6 +825,7 @@ extern void X11DRV_ResetSelectionOwner(void);
extern void CDECL X11DRV_SetFocus( HWND hwnd );
extern void set_window_cursor( Window window, HCURSOR handle );
extern void sync_window_cursor( Window window );
+extern void clipping_window_unmapped(void);
extern BOOL CDECL X11DRV_ClipCursor( LPCRECT clip );
extern void X11DRV_InitKeyboard( Display *display );
extern DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handles, DWORD timeout,
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c
index 9ac20c3..cb6d793 100644
--- a/dlls/winex11.drv/x11drv_main.c
+++ b/dlls/winex11.drv/x11drv_main.c
@@ -595,6 +595,7 @@ static BOOL process_attach(void)
#ifdef SONAME_LIBXCOMPOSITE
X11DRV_XComposite_Init();
#endif
+ X11DRV_XInput2_Init();
#ifdef HAVE_XKB
if (use_xkb) use_xkb = XkbUseExtension( gdi_display, NULL, NULL );
More information about the wine-cvs
mailing list