mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-03 13:30:27 +01: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
|
||||
evdev_read_wheel_click_prop(struct evdev_device *device,
|
||||
const char *prop,
|
||||
int *angle)
|
||||
double *angle)
|
||||
{
|
||||
int val;
|
||||
|
||||
|
|
@ -2032,18 +2032,53 @@ evdev_read_wheel_click_prop(struct evdev_device *device,
|
|||
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
|
||||
evdev_read_wheel_click_props(struct evdev_device *device)
|
||||
{
|
||||
struct wheel_angle angles;
|
||||
|
||||
evdev_read_wheel_click_prop(device,
|
||||
"MOUSE_WHEEL_CLICK_ANGLE",
|
||||
&angles.x);
|
||||
if (!evdev_read_wheel_click_prop(device,
|
||||
"MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL",
|
||||
&angles.y))
|
||||
angles.y = angles.x;
|
||||
/* CLICK_COUNT overrides CLICK_ANGLE */
|
||||
if (!evdev_read_wheel_click_count_prop(device,
|
||||
"MOUSE_WHEEL_CLICK_COUNT",
|
||||
&angles.x))
|
||||
evdev_read_wheel_click_prop(device,
|
||||
"MOUSE_WHEEL_CLICK_ANGLE",
|
||||
&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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ struct normalized_range_coords {
|
|||
|
||||
/* A pair of angles in degrees */
|
||||
struct wheel_angle {
|
||||
int x, y;
|
||||
double x, y;
|
||||
};
|
||||
|
||||
/* 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.
|
||||
* Property is of the form:
|
||||
* 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_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);
|
||||
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-low-dpi.c \
|
||||
litest-device-mouse-wheel-click-angle.c \
|
||||
litest-device-mouse-wheel-click-count.c \
|
||||
litest-device-ms-surface-cover.c \
|
||||
litest-device-protocol-a-touch-screen.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_pad_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[] = {
|
||||
&litest_synaptics_clickpad_device,
|
||||
|
|
@ -458,6 +459,7 @@ struct litest_test_device* devices[] = {
|
|||
&litest_wacom_cintiq_13hdt_pen_device,
|
||||
&litest_wacom_cintiq_13hdt_pad_device,
|
||||
&litest_wacom_hid4800_tablet_device,
|
||||
&litest_mouse_wheel_click_count_device,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -224,6 +224,7 @@ enum litest_device_type {
|
|||
LITEST_WACOM_CINTIQ_13HDT_PAD,
|
||||
LITEST_WACOM_CINTIQ_13HDT_FINGER,
|
||||
LITEST_WACOM_HID4800_PEN,
|
||||
LITEST_MOUSE_WHEEL_CLICK_COUNT,
|
||||
};
|
||||
|
||||
enum litest_device_feature {
|
||||
|
|
|
|||
30
test/misc.c
30
test/misc.c
|
|
@ -750,6 +750,35 @@ START_TEST(wheel_click_parser)
|
|||
}
|
||||
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 {
|
||||
char *tag;
|
||||
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:parser", dpi_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", dimension_prop_parser);
|
||||
litest_add_no_device("misc:time", time_conversion);
|
||||
|
|
|
|||
|
|
@ -473,14 +473,45 @@ START_TEST(pointer_button_auto_release)
|
|||
}
|
||||
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)
|
||||
{
|
||||
struct udev_device *d;
|
||||
const char *prop = NULL;
|
||||
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);
|
||||
litest_assert_ptr_notnull(d);
|
||||
|
||||
|
|
@ -492,7 +523,7 @@ wheel_click_angle(struct litest_device *dev, int which)
|
|||
goto out;
|
||||
|
||||
angle = parse_mouse_wheel_click_angle_property(prop);
|
||||
if (angle == 0)
|
||||
if (angle == 0.0)
|
||||
angle = default_angle;
|
||||
|
||||
out:
|
||||
|
|
@ -508,7 +539,7 @@ test_wheel_event(struct litest_device *dev, int which, int amount)
|
|||
struct libinput_event_pointer *ptrev;
|
||||
enum libinput_pointer_axis axis;
|
||||
|
||||
int scroll_step, expected, discrete;;
|
||||
double scroll_step, expected, discrete;
|
||||
|
||||
scroll_step = wheel_click_angle(dev, which);
|
||||
expected = amount * scroll_step;
|
||||
|
|
@ -535,10 +566,12 @@ test_wheel_event(struct litest_device *dev, int which, int amount)
|
|||
axis,
|
||||
LIBINPUT_POINTER_AXIS_SOURCE_WHEEL);
|
||||
|
||||
litest_assert_int_eq(libinput_event_pointer_get_axis_value(ptrev, axis),
|
||||
expected);
|
||||
litest_assert_int_eq(libinput_event_pointer_get_axis_value_discrete(ptrev, axis),
|
||||
discrete);
|
||||
litest_assert_double_eq(
|
||||
libinput_event_pointer_get_axis_value(ptrev, axis),
|
||||
expected);
|
||||
litest_assert_double_eq(
|
||||
libinput_event_pointer_get_axis_value_discrete(ptrev, axis),
|
||||
discrete);
|
||||
libinput_event_destroy(event);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue