evdev: Implement tablet events

Tablet proximity, motion and button events are translated into ClutterEvents,
and the device state is updated accordingly.
This commit is contained in:
Carlos Garnacho 2015-01-09 17:38:42 +01:00
parent bc8b3d9f39
commit 7004818508
2 changed files with 282 additions and 12 deletions

View File

@ -53,6 +53,7 @@
#include "clutter-backend-private.h"
#include "clutter-evdev.h"
#include "clutter-stage-private.h"
#include "clutter-input-device-tool-evdev.h"
#include "clutter-device-manager-evdev.h"
@ -450,7 +451,8 @@ new_absolute_motion_event (ClutterInputDevice *input_device,
event = clutter_event_new (CLUTTER_MOTION);
if (manager_evdev->priv->constrain_callback)
if (manager_evdev->priv->constrain_callback &&
clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE)
{
manager_evdev->priv->constrain_callback (seat->core_pointer,
us2ms (time_us),
@ -473,9 +475,16 @@ new_absolute_motion_event (ClutterInputDevice *input_device,
event->motion.x = x;
event->motion.y = y;
event->motion.axes = axes;
clutter_event_set_device (event, seat->core_pointer);
clutter_event_set_source_device (event, input_device);
if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
{
clutter_event_set_device_tool (event, device_evdev->last_tool);
clutter_event_set_device (event, input_device);
}
else
clutter_event_set_device (event, seat->core_pointer);
_clutter_input_device_set_stage (seat->core_pointer, stage);
seat->pointer_x = x;
@ -683,20 +692,26 @@ notify_button (ClutterInputDevice *input_device,
switch (button)
{
case BTN_LEFT:
case BTN_TOUCH:
button_nr = CLUTTER_BUTTON_PRIMARY;
break;
case BTN_RIGHT:
case BTN_STYLUS:
button_nr = CLUTTER_BUTTON_SECONDARY;
break;
case BTN_MIDDLE:
case BTN_STYLUS2:
button_nr = CLUTTER_BUTTON_MIDDLE;
break;
default:
/* For compatibility reasons, all additional buttons go after the old 4-7 scroll ones */
button_nr = button - (BTN_LEFT - 1) + 4;
if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
button_nr = button - BTN_TOOL_PEN + 4;
else
button_nr = button - (BTN_LEFT - 1) + 4;
break;
}
@ -711,25 +726,47 @@ notify_button (ClutterInputDevice *input_device,
else
event = clutter_event_new (CLUTTER_BUTTON_RELEASE);
/* Update the modifiers */
if (state)
seat->button_state |= maskmap[button - BTN_LEFT];
else
seat->button_state &= ~maskmap[button - BTN_LEFT];
if (button_nr < G_N_ELEMENTS (maskmap))
{
/* Update the modifiers */
if (state)
seat->button_state |= maskmap[button_nr - 1];
else
seat->button_state &= ~maskmap[button_nr - 1];
}
_clutter_evdev_event_set_time_usec (event, time_us);
event->button.time = us2ms (time_us);
event->button.stage = CLUTTER_STAGE (stage);
event->button.device = seat->core_pointer;
_clutter_xkb_translate_state (event, seat->xkb, seat->button_state);
event->button.button = button_nr;
event->button.x = seat->pointer_x;
event->button.y = seat->pointer_y;
clutter_event_set_device (event, seat->core_pointer);
if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
{
ClutterPoint point;
clutter_input_device_get_coords (input_device, NULL, &point);
event->button.x = point.x;
event->button.y = point.y;
}
else
{
event->button.x = seat->pointer_x;
event->button.y = seat->pointer_y;
}
clutter_event_set_source_device (event, input_device);
_clutter_evdev_event_set_event_code (event, button);
if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
{
clutter_event_set_device_tool (event, device_evdev->last_tool);
clutter_event_set_device (event, input_device);
}
else
clutter_event_set_device (event, seat->core_pointer);
_clutter_input_device_set_stage (seat->core_pointer, stage);
queue_event (event);
@ -871,6 +908,44 @@ notify_swipe_gesture_event (ClutterInputDevice *input_device,
queue_event (event);
}
static void
notify_proximity (ClutterInputDevice *input_device,
guint64 time_us,
gboolean in)
{
ClutterInputDeviceEvdev *device_evdev;
ClutterSeatEvdev *seat;
ClutterStage *stage;
ClutterEvent *event = NULL;
/* We can drop the event on the floor if no stage has been
* associated with the device yet. */
stage = _clutter_input_device_get_stage (input_device);
if (stage == NULL)
return;
device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device);
seat = _clutter_input_device_evdev_get_seat (device_evdev);
if (in)
event = clutter_event_new (CLUTTER_PROXIMITY_IN);
else
event = clutter_event_new (CLUTTER_PROXIMITY_OUT);
_clutter_evdev_event_set_time_usec (event, time_us);
event->proximity.time = us2ms (time_us);
event->proximity.stage = CLUTTER_STAGE (stage);
event->proximity.device = seat->core_pointer;
clutter_event_set_device_tool (event, device_evdev->last_tool);
clutter_event_set_device (event, seat->core_pointer);
clutter_event_set_source_device (event, input_device);
_clutter_input_device_set_stage (seat->core_pointer, stage);
queue_event (event);
}
static void
dispatch_libinput (ClutterDeviceManagerEvdev *manager_evdev)
{
@ -1433,6 +1508,122 @@ translate_scroll_source (enum libinput_pointer_axis_source source)
}
}
static ClutterInputDeviceToolType
translate_tool_type (struct libinput_tablet_tool *libinput_tool)
{
enum libinput_tablet_tool_type tool;
tool = libinput_tablet_tool_get_type (libinput_tool);
switch (tool)
{
case LIBINPUT_TABLET_TOOL_TYPE_PEN:
return CLUTTER_INPUT_DEVICE_TOOL_PEN;
case LIBINPUT_TABLET_TOOL_TYPE_ERASER:
return CLUTTER_INPUT_DEVICE_TOOL_ERASER;
case LIBINPUT_TABLET_TOOL_TYPE_BRUSH:
return CLUTTER_INPUT_DEVICE_TOOL_BRUSH;
case LIBINPUT_TABLET_TOOL_TYPE_PENCIL:
return CLUTTER_INPUT_DEVICE_TOOL_PENCIL;
case LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH:
return CLUTTER_INPUT_DEVICE_TOOL_AIRBRUSH;
case LIBINPUT_TABLET_TOOL_TYPE_MOUSE:
return CLUTTER_INPUT_DEVICE_TOOL_MOUSE;
case LIBINPUT_TABLET_TOOL_TYPE_LENS:
return CLUTTER_INPUT_DEVICE_TOOL_LENS;
default:
return CLUTTER_INPUT_DEVICE_TOOL_NONE;
}
}
static void
input_device_update_tool (ClutterInputDevice *input_device,
struct libinput_tablet_tool *libinput_tool)
{
ClutterInputDeviceEvdev *evdev_device = CLUTTER_INPUT_DEVICE_EVDEV (input_device);
ClutterInputDeviceTool *tool = NULL;
ClutterInputDeviceToolType tool_type;
guint64 tool_serial;
if (libinput_tool)
{
tool_serial = libinput_tablet_tool_get_serial (libinput_tool);
tool_type = translate_tool_type (libinput_tool);
tool = clutter_input_device_lookup_tool (input_device,
tool_serial, tool_type);
if (!tool)
{
tool = clutter_input_device_tool_evdev_new (libinput_tool,
tool_serial, tool_type);
clutter_input_device_add_tool (input_device, tool);
}
}
evdev_device->last_tool = tool;
}
static gdouble *
translate_tablet_axes (struct libinput_event_tablet_tool *tablet_event)
{
GArray *axes = g_array_new (FALSE, FALSE, sizeof (gdouble));
struct libinput_tablet_tool *libinput_tool;
gdouble value;
libinput_tool = libinput_event_tablet_tool_get_tool (tablet_event);
value = libinput_event_tablet_tool_get_x (tablet_event);
g_array_append_val (axes, value);
value = libinput_event_tablet_tool_get_y (tablet_event);
g_array_append_val (axes, value);
if (libinput_tablet_tool_has_distance (libinput_tool))
{
value = libinput_event_tablet_tool_get_distance (tablet_event);
g_array_append_val (axes, value);
}
if (libinput_tablet_tool_has_pressure (libinput_tool))
{
value = libinput_event_tablet_tool_get_pressure (tablet_event);
g_array_append_val (axes, value);
}
if (libinput_tablet_tool_has_tilt (libinput_tool))
{
value = libinput_event_tablet_tool_get_tilt_x (tablet_event);
g_array_append_val (axes, value);
value = libinput_event_tablet_tool_get_tilt_y (tablet_event);
g_array_append_val (axes, value);
}
if (libinput_tablet_tool_has_rotation (libinput_tool))
{
value = libinput_event_tablet_tool_get_rotation (tablet_event);
g_array_append_val (axes, value);
}
if (libinput_tablet_tool_has_slider (libinput_tool))
{
value = libinput_event_tablet_tool_get_slider_position (tablet_event);
g_array_append_val (axes, value);
}
if (libinput_tablet_tool_has_wheel (libinput_tool))
{
value = libinput_event_tablet_tool_get_wheel_delta (tablet_event);
g_array_append_val (axes, value);
}
if (axes->len == 0)
{
g_array_free (axes, TRUE);
return NULL;
}
else
return (gdouble *) g_array_free (axes, FALSE);
}
static gboolean
process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
struct libinput_event *event)
@ -1812,6 +2003,84 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
time_us, n_fingers, dx, dy);
break;
}
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
{
guint64 time;
double x, y, *axes;
gfloat stage_width, stage_height;
ClutterStage *stage;
struct libinput_event_tablet_tool *tablet_event =
libinput_event_get_tablet_tool_event (event);
device = libinput_device_get_user_data (libinput_device);
stage = _clutter_input_device_get_stage (device);
if (!stage)
break;
axes = translate_tablet_axes (tablet_event);
if (!axes)
break;
stage_width = clutter_actor_get_width (CLUTTER_ACTOR (stage));
stage_height = clutter_actor_get_height (CLUTTER_ACTOR (stage));
time = libinput_event_tablet_tool_get_time_usec (tablet_event);
x = libinput_event_tablet_tool_get_x_transformed (tablet_event, stage_width);
y = libinput_event_tablet_tool_get_y_transformed (tablet_event, stage_height);
notify_absolute_motion (device, time, x, y, axes);
break;
}
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
{
guint64 time;
struct libinput_event_tablet_tool *tablet_event =
libinput_event_get_tablet_tool_event (event);
struct libinput_tablet_tool *libinput_tool = NULL;
enum libinput_tablet_tool_proximity_state state;
state = libinput_event_tablet_tool_get_proximity_state (tablet_event);
time = libinput_event_tablet_tool_get_time_usec (tablet_event);
device = libinput_device_get_user_data (libinput_device);
libinput_tool = libinput_event_tablet_tool_get_tool (tablet_event);
input_device_update_tool (device, libinput_tool);
notify_proximity (device, time, state == LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
break;
}
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
{
guint64 time;
guint32 button_state;
struct libinput_event_tablet_tool *tablet_event =
libinput_event_get_tablet_tool_event (event);
guint tablet_button;
device = libinput_device_get_user_data (libinput_device);
time = libinput_event_tablet_tool_get_time_usec (tablet_event);
tablet_button = libinput_event_tablet_tool_get_button (tablet_event);
button_state = libinput_event_tablet_tool_get_button_state (tablet_event) ==
LIBINPUT_BUTTON_STATE_PRESSED;
notify_button (device, time, tablet_button, button_state);
break;
}
case LIBINPUT_EVENT_TABLET_TOOL_TIP:
{
guint64 time;
guint32 button_state;
struct libinput_event_tablet_tool *tablet_event =
libinput_event_get_tablet_tool_event (event);
device = libinput_device_get_user_data (libinput_device);
time = libinput_event_tablet_tool_get_time_usec (tablet_event);
button_state = libinput_event_tablet_tool_get_tip_state (tablet_event) ==
LIBINPUT_TABLET_TOOL_TIP_DOWN;
notify_button (device, time, BTN_TOUCH, button_state);
break;
}
default:
handled = FALSE;
}

View File

@ -65,6 +65,7 @@ struct _ClutterInputDeviceEvdev
struct libinput_device *libinput_device;
ClutterSeatEvdev *seat;
ClutterInputDeviceTool *last_tool;
};
GType _clutter_input_device_evdev_get_type (void) G_GNUC_CONST;