mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-09-17 02:32:04 +00:00
x11: Rescan the relative valuators on XI_DeviceChanged
XI_DeviceChanged can have a reason of XISlaveSwitch, which indicates that the valuators need to be updated for the specified device.
(cherry picked from commit b88e540783)
This commit is contained in:
@@ -28,6 +28,7 @@ typedef struct SDL_XInput2DeviceInfo
|
||||
int device_id;
|
||||
int number[2];
|
||||
bool relative[2];
|
||||
bool prev_coord_valid[2];
|
||||
double minval[2];
|
||||
double maxval[2];
|
||||
double prev_coords[2];
|
||||
|
||||
@@ -101,8 +101,12 @@ static void parse_relative_valuators(SDL_XInput2DeviceInfo *devinfo, const XIRaw
|
||||
if (devinfo->relative[j]) {
|
||||
processed_coords[j] = current_val;
|
||||
} else {
|
||||
processed_coords[j] = (current_val - devinfo->prev_coords[j]); // convert absolute to relative
|
||||
// The first absolute value is meaningless by itself and must be ignored, as it only establishes a baseline for future deltas.
|
||||
if (devinfo->prev_coord_valid[j]) {
|
||||
processed_coords[j] = (current_val - devinfo->prev_coords[j]); // convert absolute to relative
|
||||
}
|
||||
devinfo->prev_coords[j] = current_val;
|
||||
devinfo->prev_coord_valid[j] = true;
|
||||
}
|
||||
++found;
|
||||
|
||||
@@ -378,41 +382,20 @@ static void xinput2_remove_device_info(SDL_VideoData *videodata, const int devic
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_XInput2DeviceInfo *xinput2_get_device_info(SDL_VideoData *videodata, const int device_id)
|
||||
static void xinput2_reset_relative_valuators(SDL_VideoData *videodata)
|
||||
{
|
||||
// cache device info as we see new devices.
|
||||
SDL_XInput2DeviceInfo *prev = NULL;
|
||||
SDL_XInput2DeviceInfo *devinfo;
|
||||
XIDeviceInfo *xidevinfo;
|
||||
int i;
|
||||
|
||||
for (devinfo = videodata->mouse_device_info; devinfo; devinfo = devinfo->next) {
|
||||
if (devinfo->device_id == device_id) {
|
||||
SDL_assert((devinfo == videodata->mouse_device_info) == (prev == NULL));
|
||||
if (prev) { // move this to the front of the list, assuming we'll get more from this one.
|
||||
prev->next = devinfo->next;
|
||||
devinfo->next = videodata->mouse_device_info;
|
||||
videodata->mouse_device_info = devinfo;
|
||||
}
|
||||
return devinfo;
|
||||
}
|
||||
prev = devinfo;
|
||||
for (SDL_XInput2DeviceInfo *devinfo = videodata->mouse_device_info; devinfo; devinfo = devinfo->next) {
|
||||
devinfo->prev_coord_valid[0] = false;
|
||||
devinfo->prev_coord_valid[1] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// don't know about this device yet, query and cache it.
|
||||
devinfo = (SDL_XInput2DeviceInfo *)SDL_calloc(1, sizeof(SDL_XInput2DeviceInfo));
|
||||
static void xinput2_update_relative_valuators(SDL_XInput2DeviceInfo *devinfo, XIAnyClassInfo **classes, int num_classes)
|
||||
{
|
||||
if (!devinfo) {
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
xidevinfo = X11_XIQueryDevice(videodata->display, device_id, &i);
|
||||
if (!xidevinfo) {
|
||||
SDL_free(devinfo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
devinfo->device_id = device_id;
|
||||
|
||||
/* Search for relative axes with the following priority:
|
||||
* - Labelled 'Rel X'/'Rel Y'
|
||||
* - Labelled 'Abs X'/'Abs Y'
|
||||
@@ -421,8 +404,8 @@ static SDL_XInput2DeviceInfo *xinput2_get_device_info(SDL_VideoData *videodata,
|
||||
bool have_rel_x = false, have_rel_y = false;
|
||||
bool have_abs_x = false, have_abs_y = false;
|
||||
int axis_index = 0;
|
||||
for (i = 0; i < xidevinfo->num_classes; i++) {
|
||||
const XIValuatorClassInfo *v = (const XIValuatorClassInfo *)xidevinfo->classes[i];
|
||||
for (int i = 0; i < num_classes; ++i) {
|
||||
const XIValuatorClassInfo *v = (const XIValuatorClassInfo *)classes[i];
|
||||
if (v->type == XIValuatorClass) {
|
||||
if (v->label == xinput2_rel_x_atom || (v->label == xinput2_abs_x_atom && !have_rel_x) ||
|
||||
(axis_index == 0 && !have_rel_x && !have_abs_x)) {
|
||||
@@ -458,9 +441,51 @@ static SDL_XInput2DeviceInfo *xinput2_get_device_info(SDL_VideoData *videodata,
|
||||
++axis_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_XInput2DeviceInfo *xinput2_get_cached_device_info(SDL_VideoData *videodata, const int device_id)
|
||||
{
|
||||
for (SDL_XInput2DeviceInfo *devinfo = videodata->mouse_device_info, *prev = NULL; devinfo; devinfo = devinfo->next) {
|
||||
if (devinfo->device_id == device_id) {
|
||||
SDL_assert((devinfo == videodata->mouse_device_info) == (prev == NULL));
|
||||
if (prev) { // move this to the front of the list, assuming we'll get more from this one.
|
||||
prev->next = devinfo->next;
|
||||
devinfo->next = videodata->mouse_device_info;
|
||||
videodata->mouse_device_info = devinfo;
|
||||
}
|
||||
return devinfo;
|
||||
}
|
||||
prev = devinfo;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SDL_XInput2DeviceInfo *xinput2_get_device_info(SDL_VideoData *videodata, const int device_id)
|
||||
{
|
||||
// Cache device info as we see new devices.
|
||||
SDL_XInput2DeviceInfo *devinfo = xinput2_get_cached_device_info(videodata, device_id);
|
||||
if (devinfo) {
|
||||
return devinfo;
|
||||
}
|
||||
|
||||
// Don't know about this device yet, query and cache it.
|
||||
devinfo = (SDL_XInput2DeviceInfo *)SDL_calloc(1, sizeof(SDL_XInput2DeviceInfo));
|
||||
if (!devinfo) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int i;
|
||||
XIDeviceInfo *xidevinfo = X11_XIQueryDevice(videodata->display, device_id, &i);
|
||||
if (!xidevinfo) {
|
||||
SDL_free(devinfo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xinput2_update_relative_valuators(devinfo, xidevinfo->classes, xidevinfo->num_classes);
|
||||
X11_XIFreeDeviceInfo(xidevinfo);
|
||||
|
||||
devinfo->device_id = device_id;
|
||||
devinfo->next = videodata->mouse_device_info;
|
||||
videodata->mouse_device_info = devinfo;
|
||||
|
||||
@@ -481,8 +506,7 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
|
||||
case XI_HierarchyChanged:
|
||||
{
|
||||
const XIHierarchyEvent *hierev = (const XIHierarchyEvent *)cookie->data;
|
||||
int i;
|
||||
for (i = 0; i < hierev->num_info; i++) {
|
||||
for (int i = 0; i < hierev->num_info; ++i) {
|
||||
// pen stuff...
|
||||
if ((hierev->info[i].flags & (XISlaveRemoved | XIDeviceDisabled)) != 0) {
|
||||
X11_RemovePenByDeviceID(hierev->info[i].deviceid); // it's okay if this thing isn't actually a pen, it'll handle it.
|
||||
@@ -498,9 +522,18 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
|
||||
videodata->xinput_hierarchy_changed = true;
|
||||
} break;
|
||||
|
||||
// !!! FIXME: the pen code used to rescan all devices here, but we can do this device-by-device with XI_HierarchyChanged. When do these events fire and why?
|
||||
//case XI_PropertyEvent:
|
||||
//case XI_DeviceChanged:
|
||||
// !!! FIXME: XI_DeviceChanged fires when device valuator mappings need to be updated. Is XI_PropertyEvent needed for anything?
|
||||
// case XI_PropertyEvent:
|
||||
case XI_DeviceChanged:
|
||||
{
|
||||
const XIDeviceChangedEvent *dcev = (const XIDeviceChangedEvent *)cookie->data;
|
||||
if (dcev->reason == XISlaveSwitch) {
|
||||
SDL_XInput2DeviceInfo *devinfo = xinput2_get_cached_device_info(videodata, dcev->deviceid);
|
||||
if (devinfo) {
|
||||
xinput2_update_relative_valuators(devinfo, dcev->classes, dcev->num_classes);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case XI_PropertyEvent:
|
||||
{
|
||||
@@ -643,6 +676,7 @@ void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_SCROLLINFO
|
||||
case XI_Enter:
|
||||
xinput2_reset_scrollable_valuators();
|
||||
xinput2_reset_relative_valuators(videodata);
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user