wayland: Add high resolution scroll wheel support

Update the Wayland core protocol spec file and add support for the new axis_value120 event to handle high resolution scroll wheels.

The axis_value120 replaces the axis_discrete event, which is no longer sent as of version 8 of the protocol.  Note that unlike the axis_discrete event, no mention in the spec is made regarding how many axis_value120 events may occur per-axis per-frame, so the values are accumulated and committed when the pointer frame event occurs.
This commit is contained in:
Frank Praznik
2022-07-15 13:44:49 -04:00
committed by Sam Lantinga
parent d731ad769d
commit 057086e389
3 changed files with 295 additions and 61 deletions

View File

@@ -632,37 +632,75 @@ pointer_handle_axis_common_v1(struct SDL_WaylandInput *input,
}
static void
pointer_handle_axis_common(struct SDL_WaylandInput *input, SDL_bool discrete,
pointer_handle_axis_common(struct SDL_WaylandInput *input, enum SDL_WaylandAxisEvent type,
uint32_t axis, wl_fixed_t value)
{
enum wl_pointer_axis a = axis;
if (input->pointer_focus) {
switch (a) {
case WL_POINTER_AXIS_VERTICAL_SCROLL:
if (discrete) {
/* this is a discrete axis event so we process it and flag
* to ignore future continuous axis events in this frame */
input->pointer_curr_axis_info.is_y_discrete = SDL_TRUE;
} else if(input->pointer_curr_axis_info.is_y_discrete) {
/* this is a continuous axis event and we have already
* processed a discrete axis event before so we ignore it */
break;
case WL_POINTER_AXIS_VERTICAL_SCROLL:
switch (type) {
case AXIS_EVENT_VALUE120:
/*
* High resolution scroll event. The spec doesn't state that axis_value120
* events are limited to one per frame, so the values are accumulated.
*/
if (input->pointer_curr_axis_info.y_axis_type != AXIS_EVENT_VALUE120) {
input->pointer_curr_axis_info.y_axis_type = AXIS_EVENT_VALUE120;
input->pointer_curr_axis_info.y = 0.0f;
}
input->pointer_curr_axis_info.y = 0 - (float)wl_fixed_to_double(value);
input->pointer_curr_axis_info.y += 0 - (float)wl_fixed_to_double(value);
break;
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
if (discrete) {
/* this is a discrete axis event so we process it and flag
* to ignore future continuous axis events in this frame */
input->pointer_curr_axis_info.is_x_discrete = SDL_TRUE;
} else if(input->pointer_curr_axis_info.is_x_discrete) {
/* this is a continuous axis event and we have already
* processed a discrete axis event before so we ignore it */
break;
case AXIS_EVENT_DISCRETE:
/*
* This is a discrete axis event, so we process it and set the
* flag to ignore future continuous axis events in this frame.
*/
if (input->pointer_curr_axis_info.y_axis_type != AXIS_EVENT_DISCRETE) {
input->pointer_curr_axis_info.y_axis_type = AXIS_EVENT_DISCRETE;
input->pointer_curr_axis_info.y = 0 - (float)wl_fixed_to_double(value);
}
input->pointer_curr_axis_info.x = (float)wl_fixed_to_double(value);
break;
case AXIS_EVENT_CONTINUOUS:
/* Only process continuous events if no discrete events have been received. */
if (input->pointer_curr_axis_info.y_axis_type == AXIS_EVENT_CONTINUOUS) {
input->pointer_curr_axis_info.y = 0 - (float)wl_fixed_to_double(value);
}
break;
}
break;
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
switch (type) {
case AXIS_EVENT_VALUE120:
/*
* High resolution scroll event. The spec doesn't state that axis_value120
* events are limited to one per frame, so the values are accumulated.
*/
if (input->pointer_curr_axis_info.x_axis_type != AXIS_EVENT_VALUE120) {
input->pointer_curr_axis_info.x_axis_type = AXIS_EVENT_VALUE120;
input->pointer_curr_axis_info.x = 0.0f;
}
input->pointer_curr_axis_info.x += (float)wl_fixed_to_double(value);
break;
case AXIS_EVENT_DISCRETE:
/*
* This is a discrete axis event, so we process it and set the
* flag to ignore future continuous axis events in this frame.
*/
if (input->pointer_curr_axis_info.x_axis_type != AXIS_EVENT_DISCRETE) {
input->pointer_curr_axis_info.x_axis_type = AXIS_EVENT_DISCRETE;
input->pointer_curr_axis_info.x = (float)wl_fixed_to_double(value);
}
break;
case AXIS_EVENT_CONTINUOUS:
/* Only process continuous events if no discrete events have been received. */
if (input->pointer_curr_axis_info.x_axis_type == AXIS_EVENT_CONTINUOUS) {
input->pointer_curr_axis_info.x = (float)wl_fixed_to_double(value);
}
break;
}
break;
}
}
}
@@ -674,7 +712,7 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer,
struct SDL_WaylandInput *input = data;
if(wl_seat_get_version(input->seat) >= 5)
pointer_handle_axis_common(input, SDL_FALSE, axis, value);
pointer_handle_axis_common(input, AXIS_EVENT_CONTINUOUS, axis, value);
else
pointer_handle_axis_common_v1(input, time, axis, value);
}
@@ -686,15 +724,29 @@ pointer_handle_frame(void *data, struct wl_pointer *pointer)
SDL_WindowData *window = input->pointer_focus;
float x, y;
if (input->pointer_curr_axis_info.is_x_discrete)
x = input->pointer_curr_axis_info.x;
else
switch(input->pointer_curr_axis_info.x_axis_type) {
case AXIS_EVENT_CONTINUOUS:
x = input->pointer_curr_axis_info.x / WAYLAND_WHEEL_AXIS_UNIT;
break;
case AXIS_EVENT_DISCRETE:
x = input->pointer_curr_axis_info.x;
break;
case AXIS_EVENT_VALUE120:
x = input->pointer_curr_axis_info.x / 120.0f;
break;
}
if (input->pointer_curr_axis_info.is_y_discrete)
y = input->pointer_curr_axis_info.y;
else
switch(input->pointer_curr_axis_info.y_axis_type) {
case AXIS_EVENT_CONTINUOUS:
y = input->pointer_curr_axis_info.y / WAYLAND_WHEEL_AXIS_UNIT;
break;
case AXIS_EVENT_DISCRETE:
y = input->pointer_curr_axis_info.y;
break;
case AXIS_EVENT_VALUE120:
y = input->pointer_curr_axis_info.y / 120.0f;
break;
}
/* clear pointer_curr_axis_info for next frame */
SDL_memset(&input->pointer_curr_axis_info, 0, sizeof input->pointer_curr_axis_info);
@@ -725,9 +777,17 @@ pointer_handle_axis_discrete(void *data, struct wl_pointer *pointer,
{
struct SDL_WaylandInput *input = data;
pointer_handle_axis_common(input, SDL_TRUE, axis, wl_fixed_from_int(discrete));
pointer_handle_axis_common(input, AXIS_EVENT_DISCRETE, axis, wl_fixed_from_int(discrete));
}
static void
pointer_handle_axis_value120(void *data, struct wl_pointer *pointer,
uint32_t axis, int32_t value120)
{
struct SDL_WaylandInput *input = data;
pointer_handle_axis_common(input, AXIS_EVENT_VALUE120, axis, wl_fixed_from_int(value120));
}
static const struct wl_pointer_listener pointer_listener = {
pointer_handle_enter,
@@ -739,6 +799,7 @@ static const struct wl_pointer_listener pointer_listener = {
pointer_handle_axis_source, // Version 5
pointer_handle_axis_stop, // Version 5
pointer_handle_axis_discrete, // Version 5
pointer_handle_axis_value120 // Version 8
};
static void

View File

@@ -29,6 +29,13 @@
#include "SDL_waylanddatamanager.h"
#include "SDL_waylandkeyboard.h"
enum SDL_WaylandAxisEvent
{
AXIS_EVENT_CONTINUOUS = 0,
AXIS_EVENT_DISCRETE,
AXIS_EVENT_VALUE120
};
struct SDL_WaylandTabletSeat;
struct SDL_WaylandTabletObjectListNode {
@@ -113,10 +120,10 @@ struct SDL_WaylandInput {
/* information about axis events on current frame */
struct {
SDL_bool is_x_discrete;
enum SDL_WaylandAxisEvent x_axis_type;
float x;
SDL_bool is_y_discrete;
enum SDL_WaylandAxisEvent y_axis_type;
float y;
} pointer_curr_axis_info;