mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-05-07 15:28:07 +02:00
evdev: implement support for the MOUSE_WHEEL_CLICK_COUNT property
Not all mice have a click angle with integer degrees. The new MOUSE_WHEEL_CLICK_COUNT property specifies how many clicks per full rotation, the angle can be calculated from that. See https://github.com/systemd/systemd/pull/4440 for more information CLICK_COUNT overrides CLICK_ANGLE, so we check for the former first and then fall back to the angle if need be. No changes to the user-facing API. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
e0ccfc87f0
commit
58c7a9cbf0
10 changed files with 229 additions and 17 deletions
51
src/evdev.c
51
src/evdev.c
|
|
@ -2008,7 +2008,7 @@ evdev_device_init_pointer_acceleration(struct evdev_device *device,
|
||||||
static inline bool
|
static inline bool
|
||||||
evdev_read_wheel_click_prop(struct evdev_device *device,
|
evdev_read_wheel_click_prop(struct evdev_device *device,
|
||||||
const char *prop,
|
const char *prop,
|
||||||
int *angle)
|
double *angle)
|
||||||
{
|
{
|
||||||
int val;
|
int val;
|
||||||
|
|
||||||
|
|
@ -2032,18 +2032,53 @@ evdev_read_wheel_click_prop(struct evdev_device *device,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
evdev_read_wheel_click_count_prop(struct evdev_device *device,
|
||||||
|
const char *prop,
|
||||||
|
double *angle)
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
|
||||||
|
prop = udev_device_get_property_value(device->udev_device, prop);
|
||||||
|
if (!prop)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
val = parse_mouse_wheel_click_angle_property(prop);
|
||||||
|
if (val) {
|
||||||
|
*angle = 360.0/val;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error(evdev_libinput_context(device),
|
||||||
|
"Mouse wheel click count '%s' is present but invalid, "
|
||||||
|
"using %d degrees for angle instead instead\n",
|
||||||
|
device->devname,
|
||||||
|
DEFAULT_WHEEL_CLICK_ANGLE);
|
||||||
|
*angle = DEFAULT_WHEEL_CLICK_ANGLE;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static inline struct wheel_angle
|
static inline struct wheel_angle
|
||||||
evdev_read_wheel_click_props(struct evdev_device *device)
|
evdev_read_wheel_click_props(struct evdev_device *device)
|
||||||
{
|
{
|
||||||
struct wheel_angle angles;
|
struct wheel_angle angles;
|
||||||
|
|
||||||
evdev_read_wheel_click_prop(device,
|
/* CLICK_COUNT overrides CLICK_ANGLE */
|
||||||
"MOUSE_WHEEL_CLICK_ANGLE",
|
if (!evdev_read_wheel_click_count_prop(device,
|
||||||
&angles.x);
|
"MOUSE_WHEEL_CLICK_COUNT",
|
||||||
if (!evdev_read_wheel_click_prop(device,
|
&angles.x))
|
||||||
"MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL",
|
evdev_read_wheel_click_prop(device,
|
||||||
&angles.y))
|
"MOUSE_WHEEL_CLICK_ANGLE",
|
||||||
angles.y = angles.x;
|
&angles.x);
|
||||||
|
if (!evdev_read_wheel_click_count_prop(device,
|
||||||
|
"MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL",
|
||||||
|
&angles.y)) {
|
||||||
|
if (!evdev_read_wheel_click_prop(device,
|
||||||
|
"MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL",
|
||||||
|
&angles.y))
|
||||||
|
angles.y = angles.x;
|
||||||
|
}
|
||||||
|
|
||||||
return angles;
|
return angles;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ struct normalized_range_coords {
|
||||||
|
|
||||||
/* A pair of angles in degrees */
|
/* A pair of angles in degrees */
|
||||||
struct wheel_angle {
|
struct wheel_angle {
|
||||||
int x, y;
|
double x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A pair of angles in degrees */
|
/* A pair of angles in degrees */
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,38 @@ parse_mouse_dpi_property(const char *prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Helper function to parse the MOUSE_WHEEL_CLICK_COUNT property from udev.
|
||||||
|
* Property is of the form:
|
||||||
|
* MOUSE_WHEEL_CLICK_COUNT=<integer>
|
||||||
|
* Where the number indicates the number of wheel clicks per 360 deg
|
||||||
|
* rotation.
|
||||||
|
*
|
||||||
|
* We skip preceding whitespaces and parse the first number seen. If
|
||||||
|
* multiple numbers are specified, we ignore those.
|
||||||
|
*
|
||||||
|
* @param prop The value of the udev property (without the MOUSE_WHEEL_CLICK_COUNT=)
|
||||||
|
* @return The click count of the wheel (may be negative) or 0 on error.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
parse_mouse_wheel_click_count_property(const char *prop)
|
||||||
|
{
|
||||||
|
int count = 0,
|
||||||
|
nread = 0;
|
||||||
|
|
||||||
|
while(*prop != 0 && *prop == ' ')
|
||||||
|
prop++;
|
||||||
|
|
||||||
|
sscanf(prop, "%d%n", &count, &nread);
|
||||||
|
if (nread == 0 || count == 0 || abs(count) > 360)
|
||||||
|
return 0;
|
||||||
|
if (prop[nread] != ' ' && prop[nread] != '\0')
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
* Helper function to parse the MOUSE_WHEEL_CLICK_ANGLE property from udev.
|
* Helper function to parse the MOUSE_WHEEL_CLICK_ANGLE property from udev.
|
||||||
* Property is of the form:
|
* Property is of the form:
|
||||||
* MOUSE_WHEEL_CLICK_ANGLE=<integer>
|
* MOUSE_WHEEL_CLICK_ANGLE=<integer>
|
||||||
|
|
|
||||||
|
|
@ -370,6 +370,7 @@ enum ratelimit_state ratelimit_test(struct ratelimit *r);
|
||||||
|
|
||||||
int parse_mouse_dpi_property(const char *prop);
|
int parse_mouse_dpi_property(const char *prop);
|
||||||
int parse_mouse_wheel_click_angle_property(const char *prop);
|
int parse_mouse_wheel_click_angle_property(const char *prop);
|
||||||
|
int parse_mouse_wheel_click_count_property(const char *prop);
|
||||||
double parse_trackpoint_accel_property(const char *prop);
|
double parse_trackpoint_accel_property(const char *prop);
|
||||||
bool parse_dimension_property(const char *prop, size_t *width, size_t *height);
|
bool parse_dimension_property(const char *prop, size_t *width, size_t *height);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ liblitest_la_SOURCES = \
|
||||||
litest-device-mouse-roccat.c \
|
litest-device-mouse-roccat.c \
|
||||||
litest-device-mouse-low-dpi.c \
|
litest-device-mouse-low-dpi.c \
|
||||||
litest-device-mouse-wheel-click-angle.c \
|
litest-device-mouse-wheel-click-angle.c \
|
||||||
|
litest-device-mouse-wheel-click-count.c \
|
||||||
litest-device-ms-surface-cover.c \
|
litest-device-ms-surface-cover.c \
|
||||||
litest-device-protocol-a-touch-screen.c \
|
litest-device-protocol-a-touch-screen.c \
|
||||||
litest-device-qemu-usb-tablet.c \
|
litest-device-qemu-usb-tablet.c \
|
||||||
|
|
|
||||||
77
test/litest-device-mouse-wheel-click-count.c
Normal file
77
test/litest-device-mouse-wheel-click-count.c
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2016 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "litest.h"
|
||||||
|
#include "litest-int.h"
|
||||||
|
|
||||||
|
static void litest_mouse_setup(void)
|
||||||
|
{
|
||||||
|
struct litest_device *d = litest_create_device(LITEST_MOUSE_WHEEL_CLICK_COUNT);
|
||||||
|
litest_set_current_device(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct input_id input_id = {
|
||||||
|
.bustype = 0x3,
|
||||||
|
.vendor = 0x1234,
|
||||||
|
.product = 0x5678,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int events[] = {
|
||||||
|
EV_KEY, BTN_LEFT,
|
||||||
|
EV_KEY, BTN_RIGHT,
|
||||||
|
EV_KEY, BTN_MIDDLE,
|
||||||
|
EV_REL, REL_X,
|
||||||
|
EV_REL, REL_Y,
|
||||||
|
EV_REL, REL_WHEEL,
|
||||||
|
-1 , -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char udev_rule[] =
|
||||||
|
"ACTION==\"remove\", GOTO=\"wheel_click_count_end\"\n"
|
||||||
|
"KERNEL!=\"event*\", GOTO=\"wheel_click_count_end\"\n"
|
||||||
|
"\n"
|
||||||
|
"ATTRS{name}==\"litest Wheel Click Count Mouse*\",\\\n"
|
||||||
|
" ENV{MOUSE_WHEEL_CLICK_ANGLE}=\"-15\",\n"
|
||||||
|
" ENV{MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL}=\"13\",\n\\"
|
||||||
|
" ENV{MOUSE_WHEEL_CLICK_COUNT}=\"-14\",\n"
|
||||||
|
" ENV{MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL}=\"27\"\\\n"
|
||||||
|
"\n"
|
||||||
|
"LABEL=\"wheel_click_count_end\"";
|
||||||
|
|
||||||
|
struct litest_test_device litest_mouse_wheel_click_count_device = {
|
||||||
|
.type = LITEST_MOUSE_WHEEL_CLICK_COUNT,
|
||||||
|
.features = LITEST_RELATIVE | LITEST_BUTTON | LITEST_WHEEL,
|
||||||
|
.shortname = "mouse-wheelclickcount",
|
||||||
|
.setup = litest_mouse_setup,
|
||||||
|
.interface = NULL,
|
||||||
|
|
||||||
|
.name = "Wheel Click Count Mouse",
|
||||||
|
.id = &input_id,
|
||||||
|
.absinfo = NULL,
|
||||||
|
.events = events,
|
||||||
|
.udev_rule = udev_rule,
|
||||||
|
};
|
||||||
|
|
@ -402,6 +402,7 @@ extern struct litest_test_device litest_wacom_cintiq_13hdt_finger_device;
|
||||||
extern struct litest_test_device litest_wacom_cintiq_13hdt_pen_device;
|
extern struct litest_test_device litest_wacom_cintiq_13hdt_pen_device;
|
||||||
extern struct litest_test_device litest_wacom_cintiq_13hdt_pad_device;
|
extern struct litest_test_device litest_wacom_cintiq_13hdt_pad_device;
|
||||||
extern struct litest_test_device litest_wacom_hid4800_tablet_device;
|
extern struct litest_test_device litest_wacom_hid4800_tablet_device;
|
||||||
|
extern struct litest_test_device litest_mouse_wheel_click_count_device;
|
||||||
|
|
||||||
struct litest_test_device* devices[] = {
|
struct litest_test_device* devices[] = {
|
||||||
&litest_synaptics_clickpad_device,
|
&litest_synaptics_clickpad_device,
|
||||||
|
|
@ -458,6 +459,7 @@ struct litest_test_device* devices[] = {
|
||||||
&litest_wacom_cintiq_13hdt_pen_device,
|
&litest_wacom_cintiq_13hdt_pen_device,
|
||||||
&litest_wacom_cintiq_13hdt_pad_device,
|
&litest_wacom_cintiq_13hdt_pad_device,
|
||||||
&litest_wacom_hid4800_tablet_device,
|
&litest_wacom_hid4800_tablet_device,
|
||||||
|
&litest_mouse_wheel_click_count_device,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -224,6 +224,7 @@ enum litest_device_type {
|
||||||
LITEST_WACOM_CINTIQ_13HDT_PAD,
|
LITEST_WACOM_CINTIQ_13HDT_PAD,
|
||||||
LITEST_WACOM_CINTIQ_13HDT_FINGER,
|
LITEST_WACOM_CINTIQ_13HDT_FINGER,
|
||||||
LITEST_WACOM_HID4800_PEN,
|
LITEST_WACOM_HID4800_PEN,
|
||||||
|
LITEST_MOUSE_WHEEL_CLICK_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum litest_device_feature {
|
enum litest_device_feature {
|
||||||
|
|
|
||||||
30
test/misc.c
30
test/misc.c
|
|
@ -750,6 +750,35 @@ START_TEST(wheel_click_parser)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
START_TEST(wheel_click_count_parser)
|
||||||
|
{
|
||||||
|
struct parser_test tests[] = {
|
||||||
|
{ "1", 1 },
|
||||||
|
{ "10", 10 },
|
||||||
|
{ "-12", -12 },
|
||||||
|
{ "360", 360 },
|
||||||
|
{ "66 ", 66 },
|
||||||
|
{ " 100 ", 100 },
|
||||||
|
|
||||||
|
{ "0", 0 },
|
||||||
|
{ "-0", 0 },
|
||||||
|
{ "a", 0 },
|
||||||
|
{ "10a", 0 },
|
||||||
|
{ "10-", 0 },
|
||||||
|
{ "sadfasfd", 0 },
|
||||||
|
{ "361", 0 },
|
||||||
|
{ NULL, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
int i, angle;
|
||||||
|
|
||||||
|
for (i = 0; tests[i].tag != NULL; i++) {
|
||||||
|
angle = parse_mouse_wheel_click_count_property(tests[i].tag);
|
||||||
|
ck_assert_int_eq(angle, tests[i].expected_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
struct parser_test_float {
|
struct parser_test_float {
|
||||||
char *tag;
|
char *tag;
|
||||||
double expected_value;
|
double expected_value;
|
||||||
|
|
@ -956,6 +985,7 @@ litest_setup_tests_misc(void)
|
||||||
litest_add_no_device("misc:ratelimit", ratelimit_helpers);
|
litest_add_no_device("misc:ratelimit", ratelimit_helpers);
|
||||||
litest_add_no_device("misc:parser", dpi_parser);
|
litest_add_no_device("misc:parser", dpi_parser);
|
||||||
litest_add_no_device("misc:parser", wheel_click_parser);
|
litest_add_no_device("misc:parser", wheel_click_parser);
|
||||||
|
litest_add_no_device("misc:parser", wheel_click_count_parser);
|
||||||
litest_add_no_device("misc:parser", trackpoint_accel_parser);
|
litest_add_no_device("misc:parser", trackpoint_accel_parser);
|
||||||
litest_add_no_device("misc:parser", dimension_prop_parser);
|
litest_add_no_device("misc:parser", dimension_prop_parser);
|
||||||
litest_add_no_device("misc:time", time_conversion);
|
litest_add_no_device("misc:time", time_conversion);
|
||||||
|
|
|
||||||
|
|
@ -473,14 +473,45 @@ START_TEST(pointer_button_auto_release)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
static inline int
|
static inline double
|
||||||
|
wheel_click_count(struct litest_device *dev, int which)
|
||||||
|
{
|
||||||
|
struct udev_device *d;
|
||||||
|
const char *prop = NULL;
|
||||||
|
int count;
|
||||||
|
double angle = 0.0;
|
||||||
|
|
||||||
|
d = libinput_device_get_udev_device(dev->libinput_device);
|
||||||
|
litest_assert_ptr_notnull(d);
|
||||||
|
|
||||||
|
if (which == REL_HWHEEL)
|
||||||
|
prop = udev_device_get_property_value(d, "MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL");
|
||||||
|
if(!prop)
|
||||||
|
prop = udev_device_get_property_value(d, "MOUSE_WHEEL_CLICK_COUNT");
|
||||||
|
if (!prop)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
count = parse_mouse_wheel_click_count_property(prop);
|
||||||
|
angle = 360.0/count;
|
||||||
|
|
||||||
|
out:
|
||||||
|
udev_device_unref(d);
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline double
|
||||||
wheel_click_angle(struct litest_device *dev, int which)
|
wheel_click_angle(struct litest_device *dev, int which)
|
||||||
{
|
{
|
||||||
struct udev_device *d;
|
struct udev_device *d;
|
||||||
const char *prop = NULL;
|
const char *prop = NULL;
|
||||||
const int default_angle = 15;
|
const int default_angle = 15;
|
||||||
int angle = default_angle;
|
double angle;
|
||||||
|
|
||||||
|
angle = wheel_click_count(dev, which);
|
||||||
|
if (angle != 0.0)
|
||||||
|
return angle;
|
||||||
|
|
||||||
|
angle = default_angle;
|
||||||
d = libinput_device_get_udev_device(dev->libinput_device);
|
d = libinput_device_get_udev_device(dev->libinput_device);
|
||||||
litest_assert_ptr_notnull(d);
|
litest_assert_ptr_notnull(d);
|
||||||
|
|
||||||
|
|
@ -492,7 +523,7 @@ wheel_click_angle(struct litest_device *dev, int which)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
angle = parse_mouse_wheel_click_angle_property(prop);
|
angle = parse_mouse_wheel_click_angle_property(prop);
|
||||||
if (angle == 0)
|
if (angle == 0.0)
|
||||||
angle = default_angle;
|
angle = default_angle;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
@ -508,7 +539,7 @@ test_wheel_event(struct litest_device *dev, int which, int amount)
|
||||||
struct libinput_event_pointer *ptrev;
|
struct libinput_event_pointer *ptrev;
|
||||||
enum libinput_pointer_axis axis;
|
enum libinput_pointer_axis axis;
|
||||||
|
|
||||||
int scroll_step, expected, discrete;;
|
double scroll_step, expected, discrete;
|
||||||
|
|
||||||
scroll_step = wheel_click_angle(dev, which);
|
scroll_step = wheel_click_angle(dev, which);
|
||||||
expected = amount * scroll_step;
|
expected = amount * scroll_step;
|
||||||
|
|
@ -535,10 +566,12 @@ test_wheel_event(struct litest_device *dev, int which, int amount)
|
||||||
axis,
|
axis,
|
||||||
LIBINPUT_POINTER_AXIS_SOURCE_WHEEL);
|
LIBINPUT_POINTER_AXIS_SOURCE_WHEEL);
|
||||||
|
|
||||||
litest_assert_int_eq(libinput_event_pointer_get_axis_value(ptrev, axis),
|
litest_assert_double_eq(
|
||||||
expected);
|
libinput_event_pointer_get_axis_value(ptrev, axis),
|
||||||
litest_assert_int_eq(libinput_event_pointer_get_axis_value_discrete(ptrev, axis),
|
expected);
|
||||||
discrete);
|
litest_assert_double_eq(
|
||||||
|
libinput_event_pointer_get_axis_value_discrete(ptrev, axis),
|
||||||
|
discrete);
|
||||||
libinput_event_destroy(event);
|
libinput_event_destroy(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue