diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c index 15f0663b..a63b734a 100644 --- a/src/evdev-tablet.c +++ b/src/evdev-tablet.c @@ -302,6 +302,44 @@ tablet_get_tool(struct tablet_dispatch *tablet, .refcount = 1, }; + /* Determine the axis capabilities of the tool. Here's a break + * down of the heuristics used here: + * - The Wacom art pen supports all of the extra axes, along + * with rotation + * - All of normal pens and the airbrush support all of the + * extra axes if the tablet can report them + * - All of the mouse like devices don't really report any of + * the extra axes except for rotation. + * (as of writing this comment, rotation isn't supported, so you + * won't see the mouse or art pen here) + */ + switch (type) { + case LIBINPUT_TOOL_PEN: + case LIBINPUT_TOOL_ERASER: + case LIBINPUT_TOOL_PENCIL: + case LIBINPUT_TOOL_BRUSH: + case LIBINPUT_TOOL_AIRBRUSH: + if (bit_is_set(tablet->axis_caps, + LIBINPUT_TABLET_AXIS_PRESSURE)) + set_bit(tool->axis_caps, + LIBINPUT_TABLET_AXIS_PRESSURE); + if (bit_is_set(tablet->axis_caps, + LIBINPUT_TABLET_AXIS_DISTANCE)) + set_bit(tool->axis_caps, + LIBINPUT_TABLET_AXIS_DISTANCE); + if (bit_is_set(tablet->axis_caps, + LIBINPUT_TABLET_AXIS_TILT_X)) + set_bit(tool->axis_caps, + LIBINPUT_TABLET_AXIS_TILT_X); + if (bit_is_set(tablet->axis_caps, + LIBINPUT_TABLET_AXIS_TILT_Y)) + set_bit(tool->axis_caps, + LIBINPUT_TABLET_AXIS_TILT_Y); + break; + default: + break; + } + list_insert(tool_list, &tool->link); } @@ -510,12 +548,21 @@ static int tablet_init(struct tablet_dispatch *tablet, struct evdev_device *device) { + enum libinput_tablet_axis axis; + tablet->base.interface = &tablet_interface; tablet->device = device; tablet->status = TABLET_NONE; tablet->current_tool_type = LIBINPUT_TOOL_NONE; list_init(&tablet->tool_list); + for (axis = 0; axis < LIBINPUT_TABLET_AXIS_CNT; axis++) { + if (libevdev_has_event_code(device->evdev, + EV_ABS, + axis_to_evcode(axis))) + set_bit(tablet->axis_caps, axis); + } + tablet_mark_all_axes_changed(tablet, device); return 0; diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h index adc3aa4a..cb375771 100644 --- a/src/evdev-tablet.h +++ b/src/evdev-tablet.h @@ -48,6 +48,7 @@ struct tablet_dispatch { unsigned char status; unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_AXIS_CNT)]; double axes[LIBINPUT_TABLET_AXIS_CNT]; + unsigned char axis_caps[NCHARS(LIBINPUT_TABLET_AXIS_CNT)]; /* Only used for tablets that don't report serial numbers */ struct list tool_list; diff --git a/src/libinput-private.h b/src/libinput-private.h index 81875644..369bb8f3 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -108,6 +108,7 @@ struct libinput_tool { struct list link; uint32_t serial; enum libinput_tool_type type; + unsigned char axis_caps[NCHARS(LIBINPUT_TABLET_AXIS_CNT)]; int refcount; void *user_data; }; diff --git a/src/libinput.c b/src/libinput.c index 68187d8c..e52527be 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -599,6 +599,13 @@ libinput_tool_get_serial(struct libinput_tool *tool) return tool->serial; } +LIBINPUT_EXPORT int +libinput_tool_has_axis(struct libinput_tool *tool, + enum libinput_tablet_axis axis) +{ + return bit_is_set(tool->axis_caps, axis); +} + LIBINPUT_EXPORT void libinput_tool_set_user_data(struct libinput_tool *tool, void *user_data) diff --git a/src/libinput.h b/src/libinput.h index 1d4952b0..ed56c0bb 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -1007,6 +1007,19 @@ libinput_tool_get_type(struct libinput_tool *tool); struct libinput_tool * libinput_tool_ref(struct libinput_tool *tool); +/** + * @ingroup event_tablet + * + * Return whether or not a tablet tool supports the specified axis + * + * @param tool The tool to check the axis capabilities of + * @param axis The axis to check for support + * @return Whether or not the axis is supported + */ +int +libinput_tool_has_axis(struct libinput_tool *tool, + enum libinput_tablet_axis axis); + /** * @ingroup event_tablet * diff --git a/test/tablet.c b/test/tablet.c index 3617a8be..e1fb60d2 100644 --- a/test/tablet.c +++ b/test/tablet.c @@ -770,10 +770,86 @@ START_TEST(tools_without_serials) } END_TEST +START_TEST(tool_capabilities) +{ + struct libinput *li = litest_create_context(); + struct litest_device *intuos; + struct litest_device *bamboo; + struct libinput_event *event; + + /* The axis capabilities of a tool can differ depending on the type of + * tablet the tool is being used with */ + bamboo = litest_create_device_with_overrides(LITEST_WACOM_BAMBOO, + NULL, + NULL, + NULL, + NULL); + intuos = litest_create_device_with_overrides(LITEST_WACOM_INTUOS, + NULL, + NULL, + NULL, + NULL); + + litest_event(bamboo, EV_KEY, BTN_TOOL_PEN, 1); + litest_event(bamboo, EV_SYN, SYN_REPORT, 0); + + libinput_dispatch(li); + while ((event = libinput_get_event(li))) { + if (libinput_event_get_type(event) == + LIBINPUT_EVENT_TABLET_PROXIMITY_IN) { + struct libinput_event_tablet *t = + libinput_event_get_tablet_event(event); + struct libinput_tool *tool = + libinput_event_tablet_get_tool(t); + + ck_assert(libinput_tool_has_axis(tool, + LIBINPUT_TABLET_AXIS_PRESSURE)); + ck_assert(libinput_tool_has_axis(tool, + LIBINPUT_TABLET_AXIS_DISTANCE)); + ck_assert(!libinput_tool_has_axis(tool, + LIBINPUT_TABLET_AXIS_TILT_X)); + ck_assert(!libinput_tool_has_axis(tool, + LIBINPUT_TABLET_AXIS_TILT_Y)); + } + + libinput_event_destroy(event); + } + + litest_event(intuos, EV_KEY, BTN_TOOL_PEN, 1); + litest_event(intuos, EV_SYN, SYN_REPORT, 0); + + while ((event = libinput_get_event(li))) { + if (libinput_event_get_type(event) == + LIBINPUT_EVENT_TABLET_PROXIMITY_IN) { + struct libinput_event_tablet *t = + libinput_event_get_tablet_event(event); + struct libinput_tool *tool = + libinput_event_tablet_get_tool(t); + + ck_assert(libinput_tool_has_axis(tool, + LIBINPUT_TABLET_AXIS_PRESSURE)); + ck_assert(libinput_tool_has_axis(tool, + LIBINPUT_TABLET_AXIS_DISTANCE)); + ck_assert(libinput_tool_has_axis(tool, + LIBINPUT_TABLET_AXIS_TILT_X)); + ck_assert(libinput_tool_has_axis(tool, + LIBINPUT_TABLET_AXIS_TILT_Y)); + } + + libinput_event_destroy(event); + } + + litest_delete_device(bamboo); + litest_delete_device(intuos); + libinput_unref(li); +} +END_TEST + int main(int argc, char **argv) { litest_add("tablet:tool", tool_ref, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY); + litest_add_no_device("tablet:tool", tool_capabilities); litest_add("tablet:tool_serial", tool_serial, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY); litest_add("tablet:tool_serial", serial_changes_tool, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY); litest_add("tablet:tool_serial", invalid_serials, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);