winex11: Retrieve raw mouse events through XInput2 while the cursor is clipped.
This commit is contained in:
parent
338fe8b9ac
commit
bd3ec1a973
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -238,6 +249,124 @@ void sync_window_cursor( Window window )
|
|||
set_window_cursor( window, cursor );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* 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
|
||||
*
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1174,6 +1307,42 @@ static void X11DRV_RawMotion( XIRawEvent *event )
|
|||
#endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* 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
|
||||
*/
|
||||
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in New Issue