Fixed xinput and x11 event priority

* Prefer xinput events over x11 events for mouse input
* Prefer xinput raw events over xinput events:
  * Only use when the mouse is grabbed (events are not bound to a
    specific window but are global)
  * Only use for relative mouse input
This commit is contained in:
akallabeth 2022-01-22 13:29:28 +01:00 committed by akallabeth
parent 54259bc37c
commit e136444f51
7 changed files with 186 additions and 75 deletions

View File

@ -766,10 +766,7 @@ void xf_toggle_fullscreen(xfContext* xfc)
to allow keyboard usage on the debugger
*/
if (xfc->debug)
{
XUngrabKeyboard(xfc->display, CurrentTime);
XUngrabPointer(xfc->display, CurrentTime);
}
xf_ungrab(xfc);
xfc->fullscreen = (xfc->fullscreen) ? FALSE : TRUE;
xfc->decorations = (xfc->fullscreen) ? FALSE : settings->Decorations;

View File

@ -444,12 +444,13 @@ BOOL xf_generic_RawMotionNotify(xfContext* xfc, int x, int y, Window window, BOO
static BOOL xf_event_MotionNotify(xfContext* xfc, const XMotionEvent* event, BOOL app)
{
WINPR_ASSERT(xfc);
if (xfc->xi_event || xfc->xi_rawevent)
return TRUE;
if (xfc->window)
xf_floatbar_set_root_y(xfc->window->floatbar, event->y);
if (xfc->use_xinput)
return TRUE;
return xf_generic_MotionNotify(xfc, event->x, event->y, event->state, event->window, app);
}
@ -533,6 +534,7 @@ static BOOL xf_grab_mouse(xfContext* xfc)
ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask |
EnterWindowMask | LeaveWindowMask,
GrabModeAsync, GrabModeAsync, xfc->window->handle, None, CurrentTime);
xfc->mouse_grabbed = TRUE;
}
return TRUE;
}
@ -551,18 +553,18 @@ static BOOL xf_grab_kbd(xfContext* xfc)
static BOOL xf_event_ButtonPress(xfContext* xfc, const XButtonEvent* event, BOOL app)
{
xf_grab_mouse(xfc);
if (xfc->use_xinput)
return TRUE;
if (xfc->xi_event || xfc->xi_rawevent)
return TRUE;
return xf_generic_ButtonEvent(xfc, event->x, event->y, event->button, event->window, app, TRUE);
}
static BOOL xf_event_ButtonRelease(xfContext* xfc, const XButtonEvent* event, BOOL app)
{
xf_grab_mouse(xfc);
if (xfc->use_xinput)
return TRUE;
if (xfc->xi_event || xfc->xi_rawevent)
return TRUE;
return xf_generic_ButtonEvent(xfc, event->x, event->y, event->button, event->window, app,
FALSE);
}

View File

@ -68,6 +68,117 @@ static const char* xf_input_get_class_string(int class)
return "XIUnknownClass";
}
static BOOL register_input_events(xfContext* xfc, Window window)
{
int i, ndevices;
int nmasks = 0;
XIDeviceInfo* info;
rdpSettings* settings;
XIEventMask evmasks[64] = { 0 };
BYTE masks[8][XIMaskLen(XI_LASTEVENT)] = { 0 };
WINPR_ASSERT(xfc);
settings = xfc->common.context.settings;
WINPR_ASSERT(settings);
info = XIQueryDevice(xfc->display, XIAllDevices, &ndevices);
for (i = 0; i < MIN(ndevices, 64); i++)
{
int j;
BOOL used = FALSE;
XIDeviceInfo* dev = &info[i];
evmasks[nmasks].mask = masks[nmasks];
evmasks[nmasks].mask_len = sizeof(masks[0]);
evmasks[nmasks].deviceid = dev->deviceid;
/* Ignore virtual core pointer */
if (strcmp(dev->name, "Virtual core pointer") == 0)
continue;
for (j = 0; j < dev->num_classes; j++)
{
const XIAnyClassInfo* class = dev->classes[j];
switch (class->type)
{
case XITouchClass:
if (settings->MultiTouchInput)
{
XITouchClassInfo* t = (XITouchClassInfo*)class;
if (t->mode == XIDirectTouch)
{
WLog_INFO(
TAG,
"%s %s touch device (id: %d, mode: %d), supporting %d touches.",
dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent",
dev->deviceid, t->mode, t->num_touches);
XISetMask(masks[nmasks], XI_TouchBegin);
XISetMask(masks[nmasks], XI_TouchUpdate);
XISetMask(masks[nmasks], XI_TouchEnd);
}
}
break;
case XIButtonClass:
{
XIButtonClassInfo* t = (XIButtonClassInfo*)class;
WLog_INFO(TAG, "%s button device (id: %d, mode: %d)", dev->name, dev->deviceid,
t->num_buttons);
XISetMask(masks[nmasks], XI_ButtonPress);
XISetMask(masks[nmasks], XI_ButtonRelease);
XISetMask(masks[nmasks], XI_Motion);
used = TRUE;
}
break;
default:
break;
}
}
if (used)
nmasks++;
}
XIFreeDeviceInfo(info);
if (nmasks > 0)
{
Status xstatus = XISelectEvents(xfc->display, window, evmasks, nmasks);
if (xstatus != 0)
WLog_WARN(TAG, "XISelectEvents returned %d", xstatus);
}
return TRUE;
}
static BOOL register_raw_events(xfContext* xfc, Window window)
{
XIEventMask mask;
unsigned char mask_bytes[XIMaskLen(XI_LASTEVENT)] = { 0 };
rdpSettings* settings;
WINPR_ASSERT(xfc);
settings = xfc->common.context.settings;
WINPR_ASSERT(settings);
if (freerdp_settings_get_bool(settings, FreeRDP_MouseUseRelativeMove))
{
XISetMask(mask_bytes, XI_RawMotion);
XISetMask(mask_bytes, XI_RawButtonPress);
XISetMask(mask_bytes, XI_RawButtonRelease);
mask.deviceid = XIAllMasterDevices;
mask.mask_len = sizeof(mask_bytes);
mask.mask = mask_bytes;
XISelectEvents(xfc->display, window, &mask, 1);
}
return TRUE;
}
int xf_input_init(xfContext* xfc, Window window)
{
int major = XI_2_Major;
@ -101,40 +212,15 @@ int xf_input_init(xfContext* xfc, Window window)
WLog_WARN(TAG, "Server does not support XI 2.2");
return -1;
}
else
{
XIEventMask mask;
unsigned char mask_bytes[XIMaskLen(XI_LASTEVENT)] = { 0 };
int scr = DefaultScreen(xfc->display);
Window root = RootWindow(xfc->display, scr);
if (freerdp_settings_get_bool(settings, FreeRDP_MouseUseRelativeMove))
{
XISetMask(mask_bytes, XI_RawMotion);
XISetMask(mask_bytes, XI_RawButtonPress);
XISetMask(mask_bytes, XI_RawButtonRelease);
}
else
{
XISetMask(mask_bytes, XI_Motion);
XISetMask(mask_bytes, XI_ButtonPress);
XISetMask(mask_bytes, XI_ButtonRelease);
}
if (freerdp_settings_get_bool(settings, FreeRDP_MultiTouchGestures) ||
freerdp_settings_get_bool(settings, FreeRDP_MultiTouchInput))
{
XISetMask(mask_bytes, XI_TouchBegin);
XISetMask(mask_bytes, XI_TouchUpdate);
XISetMask(mask_bytes, XI_TouchEnd);
}
mask.deviceid = XIAllMasterDevices;
mask.mask_len = sizeof(mask_bytes);
mask.mask = mask_bytes;
int scr = DefaultScreen(xfc->display);
Window root = RootWindow(xfc->display, scr);
XISelectEvents(xfc->display, root, &mask, 1);
if (!register_raw_events(xfc, root))
return -1;
if (!register_input_events(xfc, window))
return -1;
}
return 0;
@ -547,59 +633,70 @@ static int xf_input_touch_remote(xfContext* xfc, XIDeviceEvent* event, int evtyp
int xf_input_event(xfContext* xfc, const XEvent* xevent, XIDeviceEvent* event, int evtype)
{
Window w;
const rdpSettings* settings;
WINPR_ASSERT(xfc);
WINPR_ASSERT(xevent);
WINPR_ASSERT(event);
w = xevent->xany.window;
if (w != xfc->window)
{
if (!xfc->remote_app)
return 0;
}
settings = xfc->common.context.settings;
WINPR_ASSERT(settings);
xf_input_show_cursor(xfc);
switch (evtype)
{
case XI_ButtonPress:
xf_generic_ButtonEvent(xfc, (int)event->event_x, (int)event->event_y, event->detail,
event->event, xfc->remote_app, TRUE);
xfc->xi_event = TRUE;
if (!xfc->xi_rawevent)
xf_generic_ButtonEvent(xfc, (int)event->event_x, (int)event->event_y, event->detail,
event->event, xfc->remote_app, TRUE);
break;
case XI_ButtonRelease:
xf_generic_ButtonEvent(xfc, (int)event->event_x, (int)event->event_y, event->detail,
event->event, xfc->remote_app, FALSE);
xfc->xi_event = TRUE;
if (!xfc->xi_rawevent)
xf_generic_ButtonEvent(xfc, (int)event->event_x, (int)event->event_y, event->detail,
event->event, xfc->remote_app, FALSE);
break;
case XI_Motion:
xf_generic_MotionNotify(xfc, (int)event->event_x, (int)event->event_y, event->detail,
event->event, xfc->remote_app);
xfc->xi_event = TRUE;
if (!xfc->xi_rawevent)
xf_generic_MotionNotify(xfc, (int)event->event_x, (int)event->event_y,
event->detail, event->event, xfc->remote_app);
break;
case XI_RawButtonPress:
case XI_RawButtonRelease:
{
const XIRawEvent* ev = event;
xf_generic_RawButtonEvent(xfc, ev->detail, xfc->remote_app,
evtype == XI_RawButtonPress);
}
xfc->xi_rawevent = xfc->mouse_grabbed &&
freerdp_settings_get_bool(settings, FreeRDP_MouseUseRelativeMove);
if (xfc->xi_rawevent)
{
const XIRawEvent* ev = (const XIRawEvent*)event;
xf_generic_RawButtonEvent(xfc, ev->detail, xfc->remote_app,
evtype == XI_RawButtonPress);
}
break;
case XI_RawMotion:
{
const XIRawEvent* ev = event;
double x = 0.0;
double y = 0.0;
if (XIMaskIsSet(ev->valuators.mask, 0))
x = ev->raw_values[0];
if (XIMaskIsSet(ev->valuators.mask, 1))
y = ev->raw_values[1];
xf_generic_RawMotionNotify(xfc, (int)x, (int)y, event->event, xfc->remote_app);
}
xfc->xi_rawevent = xfc->mouse_grabbed &&
freerdp_settings_get_bool(settings, FreeRDP_MouseUseRelativeMove);
if (xfc->xi_rawevent)
{
const XIRawEvent* ev = (const XIRawEvent*)event;
double x = 0.0;
double y = 0.0;
if (XIMaskIsSet(ev->valuators.mask, 0))
x = ev->raw_values[0];
if (XIMaskIsSet(ev->valuators.mask, 1))
y = ev->raw_values[1];
xf_generic_RawMotionNotify(xfc, (int)x, (int)y, event->event, xfc->remote_app);
}
break;
default:
WLog_INFO(TAG, "xcxx");
WLog_WARN(TAG, "[%s] Unhandled event %d: Event was registered but is not handled!");
break;
}

View File

@ -698,8 +698,7 @@ void xf_keyboard_handle_special_keys_release(xfContext* xfc, KeySym keysym)
}
xfc->mouse_active = FALSE;
XUngrabKeyboard(xfc->display, CurrentTime);
XUngrabPointer(xfc->display, CurrentTime);
xf_ungrab(xfc);
}
// ungrabbed
@ -728,3 +727,11 @@ BOOL xf_keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeSta
imeId, imeState, imeConvMode);
return TRUE;
}
BOOL xf_ungrab(xfContext* xfc)
{
WINPR_ASSERT(xfc);
XUngrabKeyboard(xfc->display, CurrentTime);
XUngrabPointer(xfc->display, CurrentTime);
xfc->mouse_grabbed = FALSE;
}

View File

@ -60,4 +60,6 @@ BOOL xf_keyboard_set_indicators(rdpContext* context, UINT16 led_flags);
BOOL xf_keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState,
UINT32 imeConvMode);
BOOL xf_ungrab(xfContext* xfc);
#endif /* FREERDP_CLIENT_X11_XF_KEYBOARD_H */

View File

@ -55,6 +55,7 @@
#include "xf_rail.h"
#include "xf_input.h"
#include "xf_keyboard.h"
#define TAG CLIENT_TAG("x11")
@ -893,7 +894,9 @@ void xf_StartLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow, int direction
appWindow->local_move.root_y = y;
appWindow->local_move.state = LMS_STARTING;
appWindow->local_move.direction = direction;
XUngrabPointer(xfc->display, CurrentTime);
xf_ungrab(xfc);
xf_SendClientEvent(
xfc, appWindow->handle,
xfc->_NET_WM_MOVERESIZE, /* request X window manager to initiate a local move */

View File

@ -203,7 +203,6 @@ struct xf_context
#endif
BOOL focused;
BOOL use_xinput;
BOOL mouse_active;
BOOL fullscreen_toggle;
BOOL controlToggle;
@ -299,6 +298,10 @@ struct xf_context
double px_vector;
double py_vector;
#endif
BOOL xi_rawevent;
BOOL xi_event;
BOOL mouse_grabbed;
};
BOOL xf_create_window(xfContext* xfc);