[clutter/wip/evdev-tablet-support: 86/88] evdev: Implement tablet events



commit f404c6f56dbdd2f685e3c7e8b6ddb4ba776fcfb2
Author: Carlos Garnacho <carlosg gnome org>
Date:   Fri Jan 9 17:38:42 2015 +0100

    evdev: Implement tablet events
    
    Tablet proximity, motion and button events are translated into ClutterEvents,
    and the device state is updated accordingly.

 clutter/evdev/clutter-device-manager-evdev.c |  247 ++++++++++++++++++++++++--
 clutter/evdev/clutter-input-device-evdev.h   |    1 +
 2 files changed, 236 insertions(+), 12 deletions(-)
---
diff --git a/clutter/evdev/clutter-device-manager-evdev.c b/clutter/evdev/clutter-device-manager-evdev.c
index f18cb32..69e7d3c 100644
--- a/clutter/evdev/clutter-device-manager-evdev.c
+++ b/clutter/evdev/clutter-device-manager-evdev.c
@@ -376,7 +376,8 @@ notify_absolute_motion (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,
                                                time_, &x, &y,
@@ -395,9 +396,16 @@ notify_absolute_motion (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;
@@ -507,23 +515,29 @@ 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:
-      button_nr = button - BTN_MOUSE + 1;
+      if (clutter_input_device_get_device_type (input_device) == CLUTTER_TABLET_DEVICE)
+        button_nr = button - BTN_TOOL_PEN + 4;
+      else
+        button_nr = button - BTN_MOUSE + 1;
       break;
     }
 
-  if (G_UNLIKELY (button_nr < 1 || button_nr > 8))
+  if (G_UNLIKELY (button_nr < 1 || button_nr > 11))
     {
       g_warning ("Unhandled button event 0x%x", button);
       return;
@@ -534,22 +548,45 @@ 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];
+    }
 
   event->button.time = time_;
   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);
 
+  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);
@@ -599,6 +636,42 @@ notify_touch_event (ClutterInputDevice *input_device,
 }
 
 static void
+notify_proximity (ClutterInputDevice *input_device,
+                  guint32             time_,
+                  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)
+    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);
+
+  event->proximity.time = time_;
+  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)
 {
   ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv;
@@ -1110,6 +1183,93 @@ _device_seat_get_touch (ClutterInputDevice *input_device,
   return g_hash_table_lookup (seat->touches, GUINT_TO_POINTER (id));
 }
 
+static ClutterInputDeviceToolType
+translate_tool_type (struct libinput_tool *libinput_tool)
+{
+  enum libinput_tool_type tool;
+
+  tool = libinput_tool_get_type (libinput_tool);
+
+  switch (tool)
+    {
+    case LIBINPUT_TOOL_PEN:
+      return CLUTTER_INPUT_DEVICE_TOOL_PEN;
+    case LIBINPUT_TOOL_ERASER:
+      return CLUTTER_INPUT_DEVICE_TOOL_ERASER;
+    case LIBINPUT_TOOL_BRUSH:
+      return CLUTTER_INPUT_DEVICE_TOOL_BRUSH;
+    case LIBINPUT_TOOL_PENCIL:
+      return CLUTTER_INPUT_DEVICE_TOOL_PENCIL;
+    case LIBINPUT_TOOL_AIRBRUSH:
+      return CLUTTER_INPUT_DEVICE_TOOL_AIRBRUSH;
+    case LIBINPUT_TOOL_FINGER:
+      return CLUTTER_INPUT_DEVICE_TOOL_FINGER;
+    case LIBINPUT_TOOL_MOUSE:
+      return CLUTTER_INPUT_DEVICE_TOOL_MOUSE;
+    case LIBINPUT_TOOL_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_tool *libinput_tool)
+{
+  ClutterInputDeviceEvdev *evdev_device = CLUTTER_INPUT_DEVICE_EVDEV (input_device);
+  ClutterInputDeviceTool *tool = NULL;
+  ClutterInputDeviceToolType tool_type;
+  guint tool_serial;
+
+  if (libinput_tool)
+    {
+      tool_serial = libinput_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_new (tool_serial, tool_type,
+                                                 libinput_tool_ref (libinput_tool),
+                                                 (GDestroyNotify) libinput_tool_unref);
+          _clutter_input_device_add_tool (input_device, tool);
+        }
+    }
+
+  evdev_device->last_tool = tool;
+}
+
+static gdouble *
+translate_tablet_axes (struct libinput_event_tablet *tablet_event)
+{
+  GArray *axes = g_array_new (FALSE, FALSE, sizeof (gdouble));
+  struct libinput_tool *libinput_tool;
+  guint i;
+
+  libinput_tool = libinput_event_tablet_get_tool (tablet_event);
+
+  for (i = LIBINPUT_TABLET_AXIS_X; i <= LIBINPUT_TABLET_AXIS_TILT_Y; i++)
+    {
+      gdouble value;
+
+      if (!libinput_tool_has_axis (libinput_tool, i))
+        continue;
+
+      value = libinput_event_tablet_get_axis_value (tablet_event, i);
+      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)
@@ -1374,6 +1534,69 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
 
         break;
       }
+    case LIBINPUT_EVENT_TABLET_AXIS:
+      {
+        guint32 time;
+        double x, y, *axes;
+        gfloat stage_width, stage_height;
+        ClutterStage *stage;
+        struct libinput_event_tablet *tablet_event =
+          libinput_event_get_tablet_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_get_time (tablet_event);
+        x = libinput_event_tablet_get_x_transformed (tablet_event, stage_width);
+        y = libinput_event_tablet_get_y_transformed (tablet_event, stage_height);
+
+        notify_absolute_motion (device, time, x, y, axes);
+        break;
+      }
+    case LIBINPUT_EVENT_TABLET_PROXIMITY:
+      {
+        guint32 time;
+        struct libinput_event_tablet *tablet_event =
+          libinput_event_get_tablet_event (event);
+        struct libinput_tool *libinput_tool = NULL;
+        enum libinput_tool_proximity_state state;
+
+        state = libinput_event_tablet_get_proximity_state (tablet_event);
+        time = libinput_event_tablet_get_time (tablet_event);
+        device = libinput_device_get_user_data (libinput_device);
+
+        if (state == LIBINPUT_TOOL_PROXIMITY_IN)
+          libinput_tool = libinput_event_tablet_get_tool (tablet_event);
+
+        input_device_update_tool (device, libinput_tool);
+        notify_proximity (device, time, (libinput_tool != NULL));
+        break;
+      }
+    case LIBINPUT_EVENT_TABLET_BUTTON:
+      {
+        guint32 time, button_state;
+        struct libinput_event_tablet *tablet_event =
+          libinput_event_get_tablet_event (event);
+        guint tablet_button;
+
+        device = libinput_device_get_user_data (libinput_device);
+        time = libinput_event_tablet_get_time (tablet_event);
+        tablet_button = libinput_event_tablet_get_button (tablet_event);
+
+        button_state = libinput_event_tablet_get_button_state (tablet_event) ==
+                       LIBINPUT_BUTTON_STATE_PRESSED;
+        notify_button (device, time, tablet_button, button_state);
+        break;
+      }
     default:
       handled = FALSE;
     }
diff --git a/clutter/evdev/clutter-input-device-evdev.h b/clutter/evdev/clutter-input-device-evdev.h
index 06f3d86..3caefc2 100644
--- a/clutter/evdev/clutter-input-device-evdev.h
+++ b/clutter/evdev/clutter-input-device-evdev.h
@@ -64,6 +64,7 @@ struct _ClutterInputDeviceEvdev
 
   struct libinput_device *libinput_device;
   ClutterSeatEvdev *seat;
+  ClutterInputDeviceTool *last_tool;
 };
 
 GType                     _clutter_input_device_evdev_get_type        (void) G_GNUC_CONST;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]