[x11] Add initial support for XInput2

Right now, only raw pointer motion and button events are handled, and
the mouse escapes the window, and there are some issues with focus in
focus-follows-mouse environments. However, this should be a much nicer
setup than DGA.
This commit is contained in:
Bill Currie 2021-11-21 23:01:12 +09:00
parent 4944c40f86
commit e45d19835c
5 changed files with 195 additions and 10 deletions

View file

@ -33,6 +33,26 @@ if test "x$HAVE_VIDMODE" != xno; then
fi
AC_SUBST(VIDMODE_LIBS)
dnl Check for XInput2 support
AC_ARG_ENABLE(xi2,
[ --disable-xi2 do not use Xorg XInput2 extension],
HAVE_XI2=$enable_xi2, HAVE_XI2=auto)
if test "x$HAVE_XI2" != xno; then
save_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$X_CFLAGS $CPPFLAGS"
AC_CHECK_HEADER(X11/extensions/XInput2.h,
dnl Make sure the library works
[AC_CHECK_LIB(Xi, XIQueryVersion,
AC_DEFINE(HAVE_XI2, 1, [Define if you have the Xorg XInput2 extension])
XI2_LIBS="-lXi",,
[$X_LIBS -lXext -lX11 $X_EXTRA_LIBS]
)],,
[#include <X11/Xlib.h>]
)
CPPFLAGS="$save_CPPFLAGS"
fi
AC_SUBST(XI2_LIBS)
dnl Check for DGA support
AC_ARG_ENABLE(dga,
[ --disable-dga do not use XFree86 DGA extension],

View file

@ -59,7 +59,10 @@
# include <X11/extensions/xf86dga.h>
# else
# include <X11/extensions/Xxf86dga.h>
# endif
#endif
#ifdef HAVE_XI2
# include <X11/extensions/XInput2.h>
#endif
#include "QF/cdaudio.h"
@ -135,6 +138,8 @@ static IE_mouse_event_t x11_mouse;
static IE_key_event_t x11_key;
static int input_grabbed = 0;
static int xi_opcode;
static int x11_have_xi;
static int x11_fd;
static int x11_driver_handle = -1;
@ -833,6 +838,93 @@ event_key (XEvent *event)
}
}
static void
xi_raw_motion (void *event)
{
int root_x, root_y;
Window root_w, child_w;
XIRawEvent *re = event;
x11_mouse_axes[0].value = re->raw_values[0];
x11_mouse_axes[1].value = re->raw_values[1];
XQueryPointer (x_disp, x_win, &root_w, &child_w, &root_x, &root_y,
&x11_mouse.x, &x11_mouse.y, &x11_mouse.shift);
// want only the modifier state
x11_mouse.shift &= 0xff;
if (!in_x11_send_mouse_event (ie_mousemove)) {
in_x11_send_axis_event (x11_mouse_device.devid,
&x11_mouse_axes[0]);
in_x11_send_axis_event (x11_mouse_device.devid,
&x11_mouse_axes[1]);
}
}
static void
xi_raw_button (void *event, int press)
{
int root_x, root_y;
Window root_w, child_w;
unsigned button;
XIRawEvent *re = event;
// x11 buttons are 1-based
button = re->detail - 1;
if (button > X11_MOUSE_BUTTONS) {
return;
}
XQueryPointer (x_disp, x_win, &root_w, &child_w, &root_x, &root_y,
&x11_mouse.x, &x11_mouse.y, &x11_mouse.shift);
// want only the modifier state
x11_mouse.shift &= 0xff;
if (press) {
x11_mouse.buttons |= 1 << button;
} else {
x11_mouse.buttons &= ~(1 << button);
}
if (!in_x11_send_mouse_event (press ? ie_mousedown : ie_mouseup)) {
in_x11_send_button_event (x11_mouse_device.devid,
&x11_mouse_buttons[button],
x11_mouse_device.event_data);
}
}
static void
xi_raw_button_press (void *event)
{
xi_raw_button (event, 1);
}
static void
xi_raw_button_resease (void *event)
{
xi_raw_button (event, 0);
}
static void
event_generic (XEvent *event)
{
// XI_LASTEVENT is the actual last event, not +1
static void (*xi_event_handlers[XI_LASTEVENT + 1]) (void *) = {
[XI_RawMotion] = xi_raw_motion,
[XI_RawButtonPress] = xi_raw_button_press,
[XI_RawButtonRelease] = xi_raw_button_resease,
};
XGenericEventCookie *cookie = &event->xcookie;
if (cookie->type != GenericEvent || cookie->extension != xi_opcode
|| !XGetEventData (x_disp, cookie)) {
return;
}
if ((unsigned) cookie->evtype <= XI_LASTEVENT
&& xi_event_handlers[cookie->evtype]) {
xi_event_handlers[cookie->evtype] (cookie->data);
}
XFreeEventData (x_disp, cookie);
}
static void
grab_error (int code, const char *device)
{
@ -861,6 +953,7 @@ grab_error (int code, const char *device)
static void
in_x11_grab_input (void *data, int grab)
{
return;//FIXME
if (!x_disp || !x_win)
return;
@ -1064,7 +1157,7 @@ in_x11_init_cvars (void *data)
{
in_snd_block = Cvar_Get ("in_snd_block", "0", CVAR_ARCHIVE, NULL,
"block sound output on window focus loss");
in_dga = Cvar_Get ("in_dga", "0", CVAR_ARCHIVE, in_dga_f, //FIXME 0 until X fixed
in_dga = Cvar_Get ("in_dga", "0", CVAR_ARCHIVE, in_dga_f,
"DGA Input support");
in_mouse_accel = Cvar_Get ("in_mouse_accel", "1", CVAR_ARCHIVE,
in_mouse_accel_f,
@ -1083,6 +1176,72 @@ x11_add_device (x11_device_t *dev)
dev->devid = IN_AddDevice (x11_driver_handle, dev, dev->name, dev->name);
}
static int
in_x11_check_xi2 (void)
{
// Support XI 2.2
int major = 2, minor = 2;
int event, error;
int ret;
if (!XQueryExtension (x_disp, "XInputExtension",
&xi_opcode, &event, &error)) {
Sys_MaskPrintf (SYS_vid, "X Input extenions not available.\n");
return 0;
}
if ((ret = XIQueryVersion (x_disp, &major, &minor)) == BadRequest) {
Sys_MaskPrintf (SYS_vid,
"No XI2 support. Server supports only %d.%d\n",
major, minor);
return 0;
} else if (ret != Success) {
Sys_MaskPrintf (SYS_vid, "in_x11_check_xi2: Xlib return bad: %d\n",
ret);
}
Sys_MaskPrintf (SYS_vid, "XI2 supported: version %d.%d\n", major, minor);
return 1;
}
static void
in_x11_xi_select_events (void)
{
//Raw events do not have target windows, so must specify the root
//window
//XISelectEvents(x_disp, x_root, &evmask, 1);
//XFlush (x_disp);
}
static void
in_x11_xi_setup_grabs (void)
{
// FIXME normal apps aren't supposed to care about the client pointer,
// but grabbing all master devices grabs the keyboard, too, which blocks
// alt-tab and the like
int dev;
XIGetClientPointer (x_disp, x_win, &dev);
byte mask[(XI_LASTEVENT + 7) / 8] = {};
XIEventMask evmask = {
.deviceid = dev,
.mask_len = sizeof (mask),
.mask = mask,
};
XISetMask (mask, XI_RawMotion);
XISetMask (mask, XI_RawButtonPress);
XISetMask (mask, XI_RawButtonRelease);
XIGrabModifiers modif = {
.modifiers = XIAnyModifier,
};
XIGrabEnter (x_disp, dev, x_win, None, XIGrabModeAsync, XIGrabModeAsync,
0, &evmask, 1, &modif);
//FIXME doesn't seem to do anything. Is it actually necessary?
//here for reference
//XIGrabFocusIn (x_disp, dev, x_win, XIGrabModeAsync, XIGrabModeAsync,
// 0, &evmask, 1, &modif);
}
long
IN_X11_Preinit (void)
{
@ -1099,9 +1258,13 @@ IN_X11_Preinit (void)
X11_AddEvent (EnterNotify, &enter_notify);
if (!COM_CheckParm ("-nomouse")) {
X11_AddEvent (MotionNotify, &event_motion);
X11_AddEvent (ButtonPress, &event_button);
X11_AddEvent (ButtonRelease, &event_button);
if ((x11_have_xi = in_x11_check_xi2 ())) {
X11_AddEvent (GenericEvent, &event_generic);
} else {
X11_AddEvent (MotionNotify, &event_motion);
X11_AddEvent (ButtonPress, &event_button);
X11_AddEvent (ButtonRelease, &event_button);
}
}
Cmd_AddCommand ("in_paste_buffer", in_paste_buffer_f,
@ -1118,12 +1281,14 @@ IN_X11_Postinit (void)
Sys_Error ("IN: No window!!");
if (!COM_CheckParm ("-nomouse")) {
dga_avail = VID_CheckDGA (x_disp, NULL, NULL, NULL);
Sys_MaskPrintf (SYS_vid, "VID_CheckDGA returned %d\n", dga_avail);
if (x11_have_xi) {
in_x11_xi_select_events ();
in_x11_xi_setup_grabs ();
} else {
dga_avail = VID_CheckDGA (x_disp, NULL, NULL, NULL);
Sys_MaskPrintf (SYS_vid, "VID_CheckDGA returned %d\n",
dga_avail);
}
}
}

View file

@ -134,7 +134,7 @@ nq_x11_libs= \
$(nq_client_LIBS)
nq_x11_SOURCES= nq/source/sys_unix.c
nq_x11_LDADD= $(nq_x11_libs) \
$(VIDMODE_LIBS) $(DGA_LIBS) $(X_LIBS) -lX11 \
$(VIDMODE_LIBS) $(DGA_LIBS) $(XI2_LIBS) $(X_LIBS) -lX11 \
$(X_EXTRA_LIBS) $(X_SHM_LIB) $(NET_LIBS) $(DL_LIBS)
nq_x11_LDFLAGS= $(common_ldflags)
nq_x11_DEPENDENCIES= $(nq_x11_libs)

View file

@ -161,7 +161,7 @@ qw_client_x11_libs= \
$(qw_client_LIBS)
qw_client_x11_SOURCES= qw/source/cl_sys_unix.c
qw_client_x11_LDADD= $(qw_client_x11_libs) \
$(VIDMODE_LIBS) $(DGA_LIBS) $(X_LIBS) -lX11 \
$(VIDMODE_LIBS) $(DGA_LIBS) $(XI2_LIBS) $(X_LIBS) -lX11 \
$(X_EXTRA_LIBS) $(X_SHM_LIB) $(NET_LIBS) $(LIBCURL_LIBS) $(DL_LIBS)
qw_client_x11_LDFLAGS= $(common_ldflags)
qw_client_x11_DEPENDENCIES= $(qw_client_x11_libs)

View file

@ -115,7 +115,7 @@ qwaq_x11_libs= \
$(qwaq_client_libs)
ruamoko_qwaq_qwaq_x11_SOURCES=ruamoko/qwaq/builtins/qwaq.c ruamoko/qwaq/builtins/qwaq-bi.c
ruamoko_qwaq_qwaq_x11_LDADD= $(qwaq_x11_libs) $(QWAQ_LIBS) \
$(VIDMODE_LIBS) $(DGA_LIBS) $(X_LIBS) -lX11 \
$(VIDMODE_LIBS) $(DGA_LIBS) $(XI2_LIBS) $(X_LIBS) -lX11 \
$(X_EXTRA_LIBS) $(X_SHM_LIB) $(DL_LIBS)
ruamoko_qwaq_qwaq_x11_LDFLAGS=
ruamoko_qwaq_qwaq_x11_DEPENDENCIES= $(qwaq_x11_libs) $(QWAQ_DEPS)