From 4a9966b1a47d497ccc9473a24ba56b3d0eef72d2 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Thu, 15 Jun 2017 14:32:28 -0400 Subject: Implement wlr_tablet_tool --- backend/libinput/tablet_tool.c | 154 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 backend/libinput/tablet_tool.c (limited to 'backend/libinput/tablet_tool.c') diff --git a/backend/libinput/tablet_tool.c b/backend/libinput/tablet_tool.c new file mode 100644 index 00000000..276c263c --- /dev/null +++ b/backend/libinput/tablet_tool.c @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include +#include +#include "backend/libinput.h" +#include "common/log.h" +#include "types.h" + +struct wlr_tablet_tool *wlr_libinput_tablet_tool_create( + struct libinput_device *device) { + assert(device); + return wlr_tablet_tool_create(NULL, NULL); +} + +void handle_tablet_tool_axis(struct libinput_event *event, + struct libinput_device *device) { + struct wlr_input_device *dev = + get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, device); + if (!dev) { + wlr_log(L_DEBUG, "Got a tablet tool event for a device with no tablet tools?"); + return; + } + struct libinput_event_tablet_tool *tevent = + libinput_event_get_tablet_tool_event(event); + struct wlr_tablet_tool_axis *wlr_event = + calloc(1, sizeof(struct wlr_tablet_tool_axis)); + wlr_event->time_sec = libinput_event_tablet_tool_get_time(tevent); + wlr_event->time_usec = libinput_event_tablet_tool_get_time_usec(tevent); + libinput_device_get_size(device, &wlr_event->width_mm, &wlr_event->height_mm); + if (libinput_event_tablet_tool_x_has_changed(tevent)) { + wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_X; + wlr_event->x_mm = libinput_event_tablet_tool_get_x(tevent); + } + if (libinput_event_tablet_tool_y_has_changed(tevent)) { + wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_Y; + wlr_event->y_mm = libinput_event_tablet_tool_get_y(tevent); + } + if (libinput_event_tablet_tool_pressure_has_changed(tevent)) { + wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_PRESSURE; + wlr_event->pressure = libinput_event_tablet_tool_get_pressure(tevent); + } + if (libinput_event_tablet_tool_distance_has_changed(tevent)) { + wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_DISTANCE; + wlr_event->distance = libinput_event_tablet_tool_get_distance(tevent); + } + if (libinput_event_tablet_tool_tilt_x_has_changed(tevent)) { + wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_TILT_X; + wlr_event->tilt_x = libinput_event_tablet_tool_get_tilt_x(tevent); + } + if (libinput_event_tablet_tool_tilt_y_has_changed(tevent)) { + wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_TILT_Y; + wlr_event->tilt_y = libinput_event_tablet_tool_get_tilt_y(tevent); + } + if (libinput_event_tablet_tool_rotation_has_changed(tevent)) { + wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_ROTATION; + wlr_event->rotation = libinput_event_tablet_tool_get_rotation(tevent); + } + if (libinput_event_tablet_tool_slider_has_changed(tevent)) { + wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_SLIDER; + wlr_event->slider = libinput_event_tablet_tool_get_slider_position(tevent); + } + if (libinput_event_tablet_tool_wheel_has_changed(tevent)) { + wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_WHEEL; + wlr_event->wheel_delta = libinput_event_tablet_tool_get_wheel_delta(tevent); + } + wl_signal_emit(&dev->tablet_tool->events.axis, wlr_event); +} + +void handle_tablet_tool_proximity(struct libinput_event *event, + struct libinput_device *device) { + struct wlr_input_device *dev = + get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, device); + if (!dev) { + wlr_log(L_DEBUG, "Got a tablet tool event for a device with no tablet tools?"); + return; + } + // Proximity events contain axis information. We update this information + // before we send the proximity event + handle_tablet_tool_axis(event, device); + struct libinput_event_tablet_tool *tevent = + libinput_event_get_tablet_tool_event(event); + struct wlr_tablet_tool_proximity *wlr_event = + calloc(1, sizeof(struct wlr_tablet_tool_proximity)); + wlr_event->time_sec = libinput_event_tablet_tool_get_time(tevent); + wlr_event->time_usec = libinput_event_tablet_tool_get_time_usec(tevent); + switch (libinput_event_tablet_tool_get_proximity_state(tevent)) { + case LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT: + wlr_event->state = WLR_TABLET_TOOL_PROXIMITY_OUT; + break; + case LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN: + wlr_event->state = WLR_TABLET_TOOL_PROXIMITY_IN; + break; + } + wl_signal_emit(&dev->tablet_tool->events.proximity, wlr_event); +} + +void handle_tablet_tool_tip(struct libinput_event *event, + struct libinput_device *device) { + struct wlr_input_device *dev = + get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, device); + if (!dev) { + wlr_log(L_DEBUG, "Got a tablet tool event for a device with no tablet tools?"); + return; + } + // Tip events contain axis information. We update this information + // before we send the proximity event + handle_tablet_tool_axis(event, device); + struct libinput_event_tablet_tool *tevent = + libinput_event_get_tablet_tool_event(event); + struct wlr_tablet_tool_tip *wlr_event = + calloc(1, sizeof(struct wlr_tablet_tool_tip)); + wlr_event->time_sec = libinput_event_tablet_tool_get_time(tevent); + wlr_event->time_usec = libinput_event_tablet_tool_get_time_usec(tevent); + switch (libinput_event_tablet_tool_get_tip_state(tevent)) { + case LIBINPUT_TABLET_TOOL_TIP_UP: + wlr_event->state = WLR_TABLET_TOOL_TIP_UP; + break; + case LIBINPUT_TABLET_TOOL_TIP_DOWN: + wlr_event->state = WLR_TABLET_TOOL_TIP_DOWN; + break; + } + wl_signal_emit(&dev->tablet_tool->events.tip, wlr_event); +} + +void handle_tablet_tool_button(struct libinput_event *event, + struct libinput_device *device) { + struct wlr_input_device *dev = + get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, device); + if (!dev) { + wlr_log(L_DEBUG, "Got a tablet tool event for a device with no tablet tools?"); + return; + } + // Tip events contain axis information. We update this information + // before we send the proximity event + handle_tablet_tool_axis(event, device); + struct libinput_event_tablet_tool *tevent = + libinput_event_get_tablet_tool_event(event); + struct wlr_tablet_tool_button *wlr_event = + calloc(1, sizeof(struct wlr_tablet_tool_button)); + wlr_event->time_sec = libinput_event_tablet_tool_get_time(tevent); + wlr_event->time_usec = libinput_event_tablet_tool_get_time_usec(tevent); + wlr_event->button = libinput_event_tablet_tool_get_button(tevent); + switch (libinput_event_tablet_tool_get_button_state(tevent)) { + case LIBINPUT_BUTTON_STATE_RELEASED: + wlr_event->state = WLR_BUTTON_RELEASED; + break; + case LIBINPUT_BUTTON_STATE_PRESSED: + wlr_event->state = WLR_BUTTON_PRESSED; + break; + } + wl_signal_emit(&dev->tablet_tool->events.button, wlr_event); +} -- cgit v1.2.3 From def3d7c64f68d59c6daec5974afc3ca84fa4bda9 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Thu, 15 Jun 2017 16:15:12 -0400 Subject: Add tablet example --- backend/libinput/tablet_tool.c | 6 +-- example/shared.c | 68 +++++++++++++++++++++++++++++++ example/shared.h | 20 +++++++++ example/tablet.c | 92 +++++++++++++++++++++++++++++++++++++++--- 4 files changed, 175 insertions(+), 11 deletions(-) (limited to 'backend/libinput/tablet_tool.c') diff --git a/backend/libinput/tablet_tool.c b/backend/libinput/tablet_tool.c index 276c263c..e8a3bc7d 100644 --- a/backend/libinput/tablet_tool.c +++ b/backend/libinput/tablet_tool.c @@ -76,9 +76,6 @@ void handle_tablet_tool_proximity(struct libinput_event *event, wlr_log(L_DEBUG, "Got a tablet tool event for a device with no tablet tools?"); return; } - // Proximity events contain axis information. We update this information - // before we send the proximity event - handle_tablet_tool_axis(event, device); struct libinput_event_tablet_tool *tevent = libinput_event_get_tablet_tool_event(event); struct wlr_tablet_tool_proximity *wlr_event = @@ -91,6 +88,7 @@ void handle_tablet_tool_proximity(struct libinput_event *event, break; case LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN: wlr_event->state = WLR_TABLET_TOOL_PROXIMITY_IN; + handle_tablet_tool_axis(event, device); break; } wl_signal_emit(&dev->tablet_tool->events.proximity, wlr_event); @@ -104,8 +102,6 @@ void handle_tablet_tool_tip(struct libinput_event *event, wlr_log(L_DEBUG, "Got a tablet tool event for a device with no tablet tools?"); return; } - // Tip events contain axis information. We update this information - // before we send the proximity event handle_tablet_tool_axis(event, device); struct libinput_event_tablet_tool *tevent = libinput_event_get_tablet_tool_event(event); diff --git a/example/shared.c b/example/shared.c index 2592c924..88f2b05f 100644 --- a/example/shared.c +++ b/example/shared.c @@ -167,6 +167,50 @@ static void touch_add(struct wlr_input_device *device, struct compositor_state * wl_list_insert(&state->touch, &tstate->link); } +static void tablet_tool_axis_notify(struct wl_listener *listener, void *data) { + struct wlr_tablet_tool_axis *event = data; + struct tablet_tool_state *tstate = wl_container_of(listener, tstate, axis); + if (tstate->compositor->tool_axis_cb) { + tstate->compositor->tool_axis_cb(tstate, event); + } +} + +static void tablet_tool_proximity_notify(struct wl_listener *listener, void *data) { + struct wlr_tablet_tool_proximity *event = data; + struct tablet_tool_state *tstate = wl_container_of(listener, tstate, proximity); + if (tstate->compositor->tool_proximity_cb) { + tstate->compositor->tool_proximity_cb(tstate, event->state); + } +} + +static void tablet_tool_button_notify(struct wl_listener *listener, void *data) { + struct wlr_tablet_tool_button *event = data; + struct tablet_tool_state *tstate = wl_container_of(listener, tstate, button); + if (tstate->compositor->tool_button_cb) { + tstate->compositor->tool_button_cb(tstate, event->button, event->state); + } +} + +static void tablet_tool_add(struct wlr_input_device *device, + struct compositor_state *state) { + struct tablet_tool_state *tstate = calloc(sizeof(struct tablet_tool_state), 1); + tstate->device = device; + tstate->compositor = state; + wl_list_init(&tstate->axis.link); + wl_list_init(&tstate->proximity.link); + wl_list_init(&tstate->tip.link); + wl_list_init(&tstate->button.link); + tstate->axis.notify = tablet_tool_axis_notify; + tstate->proximity.notify = tablet_tool_proximity_notify; + //tstate->tip.notify = tablet_tool_tip_notify; + tstate->button.notify = tablet_tool_button_notify; + wl_signal_add(&device->tablet_tool->events.axis, &tstate->axis); + wl_signal_add(&device->tablet_tool->events.proximity, &tstate->proximity); + //wl_signal_add(&device->tablet_tool->events.tip, &tstate->tip); + wl_signal_add(&device->tablet_tool->events.button, &tstate->button); + wl_list_insert(&state->tablet_tools, &tstate->link); +} + static void input_add_notify(struct wl_listener *listener, void *data) { struct wlr_input_device *device = data; struct compositor_state *state = wl_container_of(listener, state, input_add); @@ -180,6 +224,8 @@ static void input_add_notify(struct wl_listener *listener, void *data) { case WLR_INPUT_DEVICE_TOUCH: touch_add(device, state); break; + case WLR_INPUT_DEVICE_TABLET_TOOL: + tablet_tool_add(device, state); default: break; } @@ -236,6 +282,24 @@ static void touch_remove(struct wlr_input_device *device, struct compositor_stat wl_list_remove(&tstate->cancel.link); } +static void tablet_tool_remove(struct wlr_input_device *device, struct compositor_state *state) { + struct tablet_tool_state *tstate = NULL, *_tstate; + wl_list_for_each(_tstate, &state->tablet_tools, link) { + if (_tstate->device == device) { + tstate = _tstate; + break; + } + } + if (!tstate) { + return; + } + wl_list_remove(&tstate->link); + wl_list_remove(&tstate->axis.link); + wl_list_remove(&tstate->proximity.link); + //wl_list_remove(&tstate->tip.link); + wl_list_remove(&tstate->button.link); +} + static void input_remove_notify(struct wl_listener *listener, void *data) { struct wlr_input_device *device = data; struct compositor_state *state = wl_container_of(listener, state, input_add); @@ -249,6 +313,9 @@ static void input_remove_notify(struct wl_listener *listener, void *data) { case WLR_INPUT_DEVICE_TOUCH: touch_remove(device, state); break; + case WLR_INPUT_DEVICE_TABLET_TOOL: + tablet_tool_remove(device, state); + break; default: break; } @@ -323,6 +390,7 @@ void compositor_init(struct compositor_state *state) { wl_list_init(&state->keyboards); wl_list_init(&state->pointers); wl_list_init(&state->touch); + wl_list_init(&state->tablet_tools); wl_list_init(&state->input_add.link); state->input_add.notify = input_add_notify; wl_list_init(&state->input_remove.link); diff --git a/example/shared.h b/example/shared.h index d09bcd0e..df456c91 100644 --- a/example/shared.h +++ b/example/shared.h @@ -50,6 +50,17 @@ struct touch_state { void *data; }; +struct tablet_tool_state { + struct compositor_state *compositor; + struct wlr_input_device *device; + struct wl_listener axis; + struct wl_listener proximity; + struct wl_listener tip; + struct wl_listener button; + struct wl_list link; + void *data; +}; + struct compositor_state { void (*output_add_cb)(struct output_state *s); void (*keyboard_add_cb)(struct keyboard_state *s); @@ -72,6 +83,14 @@ struct compositor_state { double x, double y, double width, double height); void (*touch_up_cb)(struct touch_state *s, int32_t slot); void (*touch_cancel_cb)(struct touch_state *s, int32_t slot); + void (*tool_axis_cb)(struct tablet_tool_state *s, + struct wlr_tablet_tool_axis *event); + void (*tool_proximity_cb)(struct tablet_tool_state *s, + enum wlr_tablet_tool_proximity_state proximity); + void (*tool_tip_cb)(struct tablet_tool_state *s, + enum wlr_tablet_tool_tip_state state); + void (*tool_button_cb)(struct tablet_tool_state *s, + uint32_t button, enum wlr_button_state state); struct wl_display *display; struct wl_event_loop *event_loop; @@ -81,6 +100,7 @@ struct compositor_state { struct wl_list keyboards; struct wl_list pointers; struct wl_list touch; + struct wl_list tablet_tools; struct wl_listener input_add; struct wl_listener input_remove; diff --git a/example/tablet.c b/example/tablet.c index 9a498438..f2497d59 100644 --- a/example/tablet.c +++ b/example/tablet.c @@ -21,6 +21,13 @@ struct sample_state { struct wlr_renderer *renderer; + bool proximity, tap; + double distance; + double pressure; + double x_mm, y_mm; + double width_mm, height_mm; + struct wl_list link; + float tool_color[4]; }; static void handle_output_frame(struct output_state *output, struct timespec *ts) { @@ -28,13 +35,41 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts struct sample_state *sample = state->data; struct wlr_output *wlr_output = output->output; + int32_t width, height; + wlr_output_effective_resolution(wlr_output, &width, &height); + wlr_renderer_begin(sample->renderer, wlr_output); - float matrix[16]; - float color[4] = { 0, 1.0, 0, 1.0 }; - wlr_matrix_scale(&matrix, 128, 128, 1); - wlr_matrix_mul(&wlr_output->transform_matrix, &matrix, &matrix); - wlr_render_colored_ellipse(sample->renderer, &color, &matrix); + float matrix[16], view[16]; + float pad_color[4] = { 0.75, 0.75, 0.75, 1.0 }; + float distance = 0.8f * (1 - sample->distance); + float tool_color[4] = { distance, distance, distance, 1 }; + for (size_t i = 0; i < 4; ++i) { + tool_color[i] *= sample->tool_color[i]; + } + float scale = 4; + + float pad_width = sample->width_mm * scale; + float pad_height = sample->height_mm * scale; + float left = width / 2.0f - pad_width / 2.0f; + float top = height / 2.0f - pad_height / 2.0f; + wlr_matrix_translate(&matrix, left, top, 0); + wlr_matrix_scale(&view, pad_width, pad_height, 1); + wlr_matrix_mul(&matrix, &view, &view); + wlr_matrix_mul(&wlr_output->transform_matrix, &view, &matrix); + wlr_render_colored_quad(sample->renderer, &pad_color, &matrix); + + if (sample->proximity) { + wlr_matrix_translate(&matrix, + sample->x_mm * scale - 8 * (sample->pressure + 1) + left, + sample->y_mm * scale - 8 * (sample->pressure + 1) + top, 0); + wlr_matrix_scale(&view, + 16 * (sample->pressure + 1), + 16 * (sample->pressure + 1), 1); + wlr_matrix_mul(&matrix, &view, &view); + wlr_matrix_mul(&wlr_output->transform_matrix, &view, &matrix); + wlr_render_colored_ellipse(sample->renderer, &tool_color, &matrix); + } wlr_renderer_end(sample->renderer); } @@ -46,13 +81,58 @@ static void handle_keyboard_key(struct keyboard_state *kbstate, } } +static void handle_tool_axis(struct tablet_tool_state *tstate, + struct wlr_tablet_tool_axis *event) { + struct sample_state *sample = tstate->compositor->data; + sample->width_mm = event->width_mm; + sample->height_mm = event->height_mm; + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) { + sample->x_mm = event->x_mm; + } + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { + sample->y_mm = event->y_mm; + } + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE)) { + sample->distance = event->distance; + } + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_PRESSURE)) { + sample->pressure = event->pressure; + } +} + +static void handle_tool_proximity(struct tablet_tool_state *tstate, + enum wlr_tablet_tool_proximity_state state) { + struct sample_state *sample = tstate->compositor->data; + sample->proximity = state == WLR_TABLET_TOOL_PROXIMITY_IN; +} + +static void handle_tool_button(struct tablet_tool_state *tstate, + uint32_t button, enum wlr_button_state state) { + struct sample_state *sample = tstate->compositor->data; + if (state == WLR_BUTTON_RELEASED) { + float default_color[4] = { 1, 1, 1, 1 }; + memcpy(sample->tool_color, default_color, 4); + } else { + for (size_t i = 0; i < 3; ++i) { + if (button % 3 != i) { + sample->tool_color[button % 3] = 0; + } + } + } +} + int main(int argc, char *argv[]) { - struct sample_state state = { 0 }; + struct sample_state state = { + .tool_color = { 1, 1, 1, 1 } + }; struct compositor_state compositor; compositor_init(&compositor); compositor.output_frame_cb = handle_output_frame; compositor.keyboard_key_cb = handle_keyboard_key; + compositor.tool_axis_cb = handle_tool_axis; + compositor.tool_proximity_cb = handle_tool_proximity; + compositor.tool_button_cb = handle_tool_button; state.renderer = wlr_gles3_renderer_init(); -- cgit v1.2.3