Providing a relative axis in the axis_get_value() is inconsistent with the
other axes, this will be fixed in a follow-up commit.

Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net>
---
 src/evdev-tablet.c     | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/evdev-tablet.h     | 18 ++++++++++++++++
 src/libinput-private.h |  2 +-
 src/libinput.c         |  1 +
 src/libinput.h         |  4 ++++
 test/tablet.c          | 54 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/event-debug.c    | 11 +++++++++-
 7 files changed, 144 insertions(+), 2 deletions(-)

diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index d05b6c2..0fd5033 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -82,6 +82,10 @@ tablet_device_has_axis(struct tablet_dispatch *tablet,
                            libevdev_has_event_code(evdev,
                                                    EV_ABS,
                                                    ABS_TILT_Y));
+       } else if (axis == LIBINPUT_TABLET_AXIS_REL_WHEEL) {
+               has_axis = libevdev_has_event_code(evdev,
+                                                  EV_REL,
+                                                  REL_WHEEL);
        } else {
                code = axis_to_evcode(axis);
                has_axis = libevdev_has_event_code(evdev,
@@ -251,6 +255,15 @@ convert_to_degrees(const struct input_absinfo *absinfo, 
double offset)
        return fmod(value * 360.0 + offset, 360.0);
 }
 
+static inline double
+normalize_wheel(struct tablet_dispatch *tablet,
+               int value)
+{
+       struct evdev_device *device = tablet->device;
+
+       return value * device->scroll.wheel_click_angle;
+}
+
 static void
 tablet_check_notify_axes(struct tablet_dispatch *tablet,
                         struct evdev_device *device,
@@ -282,6 +295,11 @@ tablet_check_notify_axes(struct tablet_dispatch *tablet,
                        axes[LIBINPUT_TABLET_AXIS_TILT_Y] = 0;
                        axes[a] = tablet->axes[a];
                        continue;
+               } else if (a == LIBINPUT_TABLET_AXIS_REL_WHEEL) {
+                       tablet->axes[a] = normalize_wheel(tablet,
+                                                         tablet->deltas[a]);
+                       axes[a] = tablet->axes[a];
+                       break;
                }
 
                absinfo = libevdev_get_abs_info(device->evdev,
@@ -442,6 +460,35 @@ tablet_process_key(struct tablet_dispatch *tablet,
 }
 
 static void
+tablet_process_relative(struct tablet_dispatch *tablet,
+                       struct evdev_device *device,
+                       struct input_event *e,
+                       uint32_t time)
+{
+       enum libinput_tablet_axis axis;
+       switch (e->code) {
+       case REL_WHEEL:
+               axis = rel_evcode_to_axis(e->code);
+               if (axis == LIBINPUT_TABLET_AXIS_NONE) {
+                       log_bug_libinput(device->base.seat->libinput,
+                                        "Invalid ABS event code %#x\n",
+                                        e->code);
+                       break;
+               }
+               set_bit(tablet->changed_axes, axis);
+               tablet->deltas[axis] = e->value;
+               tablet_set_status(tablet, TABLET_AXES_UPDATED);
+               break;
+       default:
+               log_info(tablet->device->base.seat->libinput,
+                        "Unhandled relative axis %s (%#x)\n",
+                        libevdev_event_code_get_name(EV_REL, e->code),
+                        e->code);
+               return;
+       }
+}
+
+static void
 tablet_process_misc(struct tablet_dispatch *tablet,
                    struct evdev_device *device,
                    struct input_event *e,
@@ -535,6 +582,11 @@ tool_set_bits_from_libwacom(const struct tablet_dispatch 
*tablet,
                break;
        case WSTYLUS_PUCK:
                copy_axis_cap(tablet, tool, LIBINPUT_TABLET_AXIS_ROTATION_Z);
+               /* lens cursors don't have a wheel */
+               if (!libwacom_stylus_has_lens(s))
+                       copy_axis_cap(tablet,
+                                     tool,
+                                     LIBINPUT_TABLET_AXIS_REL_WHEEL);
                break;
        default:
                break;
@@ -578,6 +630,7 @@ tool_set_bits(const struct tablet_dispatch *tablet,
        case LIBINPUT_TOOL_MOUSE:
        case LIBINPUT_TOOL_LENS:
                copy_axis_cap(tablet, tool, LIBINPUT_TABLET_AXIS_ROTATION_Z);
+               copy_axis_cap(tablet, tool, LIBINPUT_TABLET_AXIS_REL_WHEEL);
                break;
        default:
                break;
@@ -824,6 +877,9 @@ tablet_process(struct evdev_dispatch *dispatch,
        case EV_ABS:
                tablet_process_absolute(tablet, device, e, time);
                break;
+       case EV_REL:
+               tablet_process_relative(tablet, device, e, time);
+               break;
        case EV_KEY:
                tablet_process_key(tablet, device, e, time);
                break;
diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h
index 7c472cf..ea103b0 100644
--- a/src/evdev-tablet.h
+++ b/src/evdev-tablet.h
@@ -50,6 +50,7 @@ struct tablet_dispatch {
        unsigned char status;
        unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_MAX + 1)];
        double axes[LIBINPUT_TABLET_AXIS_MAX + 1];
+       double deltas[LIBINPUT_TABLET_AXIS_MAX + 1];
        unsigned char axis_caps[NCHARS(LIBINPUT_TABLET_AXIS_MAX + 1)];
 
        /* Only used for tablets that don't report serial numbers */
@@ -101,6 +102,23 @@ evcode_to_axis(const uint32_t evcode)
        return axis;
 }
 
+static inline enum libinput_tablet_axis
+rel_evcode_to_axis(const uint32_t evcode)
+{
+       enum libinput_tablet_axis axis;
+
+       switch (evcode) {
+       case REL_WHEEL:
+               axis = LIBINPUT_TABLET_AXIS_REL_WHEEL;
+               break;
+       default:
+               axis = LIBINPUT_TABLET_AXIS_NONE;
+               break;
+       }
+
+       return axis;
+}
+
 static inline uint32_t
 axis_to_evcode(const enum libinput_tablet_axis axis)
 {
diff --git a/src/libinput-private.h b/src/libinput-private.h
index 84e5aaa..071204e 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -30,7 +30,7 @@
 #include "libinput.h"
 #include "libinput-util.h"
 
-#define LIBINPUT_TABLET_AXIS_MAX LIBINPUT_TABLET_AXIS_SLIDER
+#define LIBINPUT_TABLET_AXIS_MAX LIBINPUT_TABLET_AXIS_REL_WHEEL
 
 struct libinput_source;
 
diff --git a/src/libinput.c b/src/libinput.c
index 9df3d48..2640321 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -586,6 +586,7 @@ libinput_event_tablet_get_axis_value(struct 
libinput_event_tablet *event,
                case LIBINPUT_TABLET_AXIS_TILT_Y:
                case LIBINPUT_TABLET_AXIS_ROTATION_Z:
                case LIBINPUT_TABLET_AXIS_SLIDER:
+               case LIBINPUT_TABLET_AXIS_REL_WHEEL:
                        return event->axes[axis];
                default:
                        return 0;
diff --git a/src/libinput.h b/src/libinput.h
index 87d220b..5737873 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -144,6 +144,7 @@ enum libinput_tablet_axis {
        LIBINPUT_TABLET_AXIS_TILT_Y = 6,
        LIBINPUT_TABLET_AXIS_ROTATION_Z = 7,
        LIBINPUT_TABLET_AXIS_SLIDER = 8,
+       LIBINPUT_TABLET_AXIS_REL_WHEEL = 9,
 };
 
 /**
@@ -1060,6 +1061,9 @@ libinput_event_tablet_axis_has_changed(struct 
libinput_event_tablet *event,
  *   position is with the buttons pointing up.
  * - @ref LIBINPUT_TABLET_AXIS_SLIDER - A slider on the tool, normalized
  *   from 0 to 1. e.g. the wheel-like tool on the Wacom Airbrush.
+ * - @ref LIBINPUT_TABLET_AXIS_REL_WHEEL - A relative wheel on the tool,
+ *   similar or equivalent to a mouse wheel. The value is a delta from the
+ *   device's previous position, in degrees.
  *
  * @note This function may be called for a specific axis even if
  * libinput_event_tablet_axis_has_changed() returns 0 for that axis.
diff --git a/test/tablet.c b/test/tablet.c
index afc654e..e46314a 100644
--- a/test/tablet.c
+++ b/test/tablet.c
@@ -1273,6 +1273,59 @@ START_TEST(mouse_rotation)
 }
 END_TEST
 
+START_TEST(mouse_wheel)
+{
+       struct litest_device *dev = litest_current_device();
+       struct libinput *li = dev->libinput;
+       struct libinput_event *event;
+       struct libinput_event_tablet *tev;
+       struct libinput_tool *tool;
+       double val;
+
+       if (!libevdev_has_event_code(dev->evdev,
+                                    EV_REL,
+                                    REL_WHEEL))
+               return;
+
+       litest_drain_events(li);
+
+       litest_event(dev, EV_KEY, BTN_TOOL_MOUSE, 1);
+       litest_event(dev, EV_ABS, ABS_MISC, 0x806); /* 5-button mouse tool_id */
+       litest_event(dev, EV_MSC, MSC_SERIAL, 1000);
+       litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+       litest_wait_for_event_of_type(li,
+                                     LIBINPUT_EVENT_TABLET_PROXIMITY,
+                                     -1);
+       event = libinput_get_event(li);
+       tev = libinput_event_get_tablet_event(event);
+       tool = libinput_event_tablet_get_tool(tev);
+       ck_assert_notnull(tool);
+       libinput_tool_ref(tool);
+
+       libinput_event_destroy(event);
+
+       ck_assert(libinput_tool_has_axis(tool,
+                                        LIBINPUT_TABLET_AXIS_REL_WHEEL));
+
+       litest_event(dev, EV_REL, REL_WHEEL, -1);
+       litest_event(dev, EV_SYN, SYN_REPORT, 0);
+
+       litest_wait_for_event_of_type(li, LIBINPUT_EVENT_TABLET_AXIS, -1);
+
+       event = libinput_get_event(li);
+       tev = libinput_event_get_tablet_event(event);
+       ck_assert(libinput_event_tablet_axis_has_changed(tev,
+                                       LIBINPUT_TABLET_AXIS_REL_WHEEL));
+       val = libinput_event_tablet_get_axis_value(tev,
+                                       LIBINPUT_TABLET_AXIS_REL_WHEEL);
+       ck_assert_int_eq(val, 15);
+       libinput_event_destroy(event);
+
+       libinput_tool_unref(tool);
+}
+END_TEST
+
 START_TEST(airbrush_tool)
 {
        struct litest_device *dev = litest_current_device();
@@ -1475,6 +1528,7 @@ main(int argc, char **argv)
        litest_add("tablet:mouse", mouse_tool, LITEST_TABLET, LITEST_ANY);
        litest_add("tablet:mouse", mouse_buttons, LITEST_TABLET, LITEST_ANY);
        litest_add("tablet:mouse", mouse_rotation, LITEST_TABLET, LITEST_ANY);
+       litest_add("tablet:mouse", mouse_wheel, LITEST_TABLET, LITEST_ANY);
        litest_add("tablet:airbrush", airbrush_tool, LITEST_TABLET, LITEST_ANY);
        litest_add("tablet:airbrush", airbrush_wheel, LITEST_TABLET, 
LITEST_ANY);
        litest_add("tablet:artpen", artpen_tool, LITEST_TABLET, LITEST_ANY);
diff --git a/tools/event-debug.c b/tools/event-debug.c
index 94a90ec..09edac0 100644
--- a/tools/event-debug.c
+++ b/tools/event-debug.c
@@ -293,7 +293,7 @@ print_tablet_axes(struct libinput_event_tablet *t)
        struct libinput_tool *tool = libinput_event_tablet_get_tool(t);
        double x, y;
        double dist, pressure;
-       double rotation, slider;
+       double rotation, slider, wheel;
 
        x = libinput_event_tablet_get_axis_value(t, LIBINPUT_TABLET_AXIS_X);
        y = libinput_event_tablet_get_axis_value(t, LIBINPUT_TABLET_AXIS_Y);
@@ -350,6 +350,15 @@ print_tablet_axes(struct libinput_event_tablet *t)
                       tablet_axis_changed_sym(t,
                                       LIBINPUT_TABLET_AXIS_SLIDER));
        }
+
+       if (libinput_tool_has_axis(tool, LIBINPUT_TABLET_AXIS_REL_WHEEL)) {
+               wheel = libinput_event_tablet_get_axis_value(t,
+                                       LIBINPUT_TABLET_AXIS_REL_WHEEL);
+               printf("\twheel: %.2f%s",
+                      wheel,
+                      tablet_axis_changed_sym(t,
+                                      LIBINPUT_TABLET_AXIS_REL_WHEEL));
+       }
 }
 
 static void
-- 
2.1.0

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to