Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 149 additions & 2 deletions android/patches/dlls_winex11_drv_mouse_c.patch
Original file line number Diff line number Diff line change
@@ -1,8 +1,107 @@
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index 2ba4960..74cdb87 100644
index 2ba49607bd2..0c579d015b9 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -1488,10 +1488,14 @@ BOOL X11DRV_SetCursorPos( INT x, INT y )
@@ -127,6 +127,8 @@ static const UINT button_up_data[NB_BUTTONS] =
XContext cursor_context = 0;

static RECT clip_rect;
+static POINT clip_center; /* center of clipping rect for relative motion synthesis */
+static BOOL needs_relative_motion; /* TRUE when game wants clipping but xinput2 unavailable */
static Cursor create_cursor( HANDLE handle );

#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
@@ -141,6 +143,21 @@ MAKE_FUNCPTR(XISelectEvents);
#undef MAKE_FUNCPTR
#endif

+/* When XInput2 is available, explorer.exe centralises WM_INPUT generation via
+ * SEND_HWMSG_NO_MSG raw events, so game processes must suppress their own raw
+ * input dispatch to avoid duplicates (SEND_HWMSG_NO_RAW = legacy only).
+ * When XInput2 is absent (e.g. Android / --without-xinput2 builds) there is no
+ * explorer.exe raw input pipeline at all, so each process must generate WM_INPUT
+ * itself alongside the legacy message (flags = 0). */
+#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
+static inline UINT get_send_mouse_flags(void)
+{
+ return xinput2_available ? SEND_HWMSG_NO_RAW : 0;
+}
+#else
+static inline UINT get_send_mouse_flags(void) { return 0; }
+#endif
+
#ifdef HAVE_X11_EXTENSIONS_XINPUT_H
#define MAKE_FUNCPTR(f) static typeof(f) * p##f
MAKE_FUNCPTR(XOpenDevice);
@@ -459,7 +476,6 @@ void x11drv_xinput2_init( struct x11drv_thread_data *data )
*/
static BOOL grab_clipping_window( const RECT *clip )
{
-#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
struct x11drv_thread_data *data = x11drv_thread_data();
Window clip_window;
HCURSOR cursor;
@@ -478,13 +494,17 @@ static BOOL grab_clipping_window( const RECT *clip )
WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) );
return FALSE;
}
+#ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
if (!xinput2_available)
+#endif
{
- WARN( "XInput2 not supported, refusing to clip to %s\n", wine_dbgstr_rect(clip) );
- NtUserClipCursor( NULL );
+ WARN( "XInput2 not available, enabling relative motion for %s\n", wine_dbgstr_rect(clip) );
+ clip_rect = *clip;
+ clip_center.x = (clip->left + clip->right) / 2;
+ clip_center.y = (clip->top + clip->bottom) / 2;
+ needs_relative_motion = TRUE;
return TRUE;
}
-
/* enable XInput2 unless we are already clipping */
if (!data->clipping_cursor) x11drv_xinput2_enable( data->display, DefaultRootWindow( data->display ) );

@@ -523,12 +543,8 @@ static BOOL grab_clipping_window( const RECT *clip )
return FALSE;
}
clip_rect = *clip;
data->clipping_cursor = TRUE;
return TRUE;
-#else
- WARN( "XInput2 was not available at compile time\n" );
- return FALSE;
-#endif
}

/***********************************************************************
@@ -552,6 +571,7 @@ void ungrab_clipping_window(void)
}
clipping_cursor = FALSE;
data->clipping_cursor = FALSE;
+ needs_relative_motion = FALSE;
x11drv_xinput2_disable( data->display, DefaultRootWindow( data->display ) );
}

@@ -640,7 +660,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU
{
struct x11drv_thread_data *thread_data = x11drv_thread_data();
if (!thread_data->clipping_cursor || thread_data->clip_window != window) return;
- NtUserSendHardwareInput( hwnd, SEND_HWMSG_NO_RAW, input, 0 );
+ NtUserSendHardwareInput( hwnd, get_send_mouse_flags(), input, 0 );
return;
}

@@ -664,7 +684,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU
SERVER_END_REQ;
}

- NtUserSendHardwareInput( hwnd, SEND_HWMSG_NO_RAW, input, 0 );
+ NtUserSendHardwareInput( hwnd, get_send_mouse_flags(), input, 0 );
}

#ifdef SONAME_LIBXCURSOR
@@ -1488,10 +1508,14 @@ BOOL X11DRV_SetCursorPos( INT x, INT y )
return FALSE;
}

Expand All @@ -17,3 +116,51 @@ index 2ba4960..74cdb87 100644
XFlush( data->display ); /* avoids bad mouse lag in games that do their own mouse warping */
TRACE( "warped to %d,%d serial %lu\n", x, y, data->warp_serial );
return TRUE;
@@ -1661,18 +1685,41 @@ BOOL X11DRV_MotionNotify( HWND hwnd, XEvent *xev )
TRACE( "hwnd %p/%lx pos %d,%d is_hint %d serial %lu\n",
hwnd, event->window, event->x, event->y, event->is_hint, event->serial );

- input.mi.dx = event->x;
- input.mi.dy = event->y;
+ if (is_old_motion_event( event->serial ))
+ {
+ TRACE( "pos %d,%d old serial %lu, ignoring\n", event->x, event->y, event->serial );
+ return FALSE;
+ }
+
input.mi.mouseData = 0;
- input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
input.mi.time = EVENT_x11_time_to_win32_time( event->time );
input.mi.dwExtraInfo = 0;

- if (is_old_motion_event( event->serial ))
+ /* Synthesize relative motion when game wants clipping but xinput2 unavailable */
+ if (needs_relative_motion && hwnd)
{
- TRACE( "pos %d,%d old serial %lu, ignoring\n", event->x, event->y, event->serial );
- return FALSE;
+ int dx = event->x_root - clip_center.x;
+ int dy = event->y_root - clip_center.y;
+
+ if (dx == 0 && dy == 0)
+ return FALSE;
+
+ input.mi.dx = dx;
+ input.mi.dy = dy;
+ input.mi.dwFlags = MOUSEEVENTF_MOVE;
+
+ /* Warp cursor back to center */
+ XWarpPointer( event->display, None, root_window, 0, 0, 0, 0, clip_center.x, clip_center.y );
+
+ send_mouse_input( hwnd, event->window, event->state, &input );
+ return TRUE;
}
+
+ /* Normal absolute motion */
+ input.mi.dx = event->x;
+ input.mi.dy = event->y;
+ input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
+
map_event_coords( hwnd, event->window, event->root, event->x_root, event->y_root, &input );
send_mouse_input( hwnd, event->window, event->state, &input );
return TRUE;