Compare commits

...

15 Commits

Author SHA1 Message Date
7e3f96d972 backends: Prepare for virtual devices
Those have no backing libinput_device, and configuration does not
apply to those.

https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-07-26 18:45:26 +02:00
5f91d34f88 clutter/evdev: Implement ClutterVirtualInputDevice::notify_keyval
This is somewhat gross at the moment, because we're after all mimicking
real keyboard events, we can only lookup keycodes that are available
in the current map, and the control of levels is rather limited.

Eventually, we want to implement the text_input protocol, handle these
events separately to MetaWaylandKeyboard, so event->key.keyval is
is guaranteed to be the final result. Until then, this is the farthest
we can get.

https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-07-26 18:45:26 +02:00
d0a708b42c clutter: Add ClutterVirtualInputDevice vmethod to notify keysyms
Evcodes don't cut it when we have something already specifying the
character to be printed, despite the current group/level. This API
allows some more control on the intended output.

https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-07-26 18:45:26 +02:00
d940d5e581 clutter: Make ClutterVirtualInputDevice public
This includes adding documentation and introspection annotations,
and marking the functions as extern.

https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-07-26 18:45:26 +02:00
70f69e5de4 clutter/evdev: Allow specifying the ClutterInputMode of virtual devices
The seat core keyboard/pointer will be "master", the ones created through
ClutterVirtualInputDevice will be "slaves".

https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-07-26 18:45:25 +02:00
c2ce0e6795 ClutterVirtualInputDeviceEvdev: Forward button and key presses
https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-07-26 18:45:25 +02:00
adbd566f83 ClutterSeatEvdev: Keep track of button count
libinput does it for us, but only for physical devices. When we add
virtual devices to the same seat, we need to track button press count
ourself.

https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-07-26 18:45:25 +02:00
f511f65a14 ClutterVirtualInputDeviceEvdev: Forward motion events
https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-07-26 18:45:25 +02:00
0942d68f1a ClutterVirtualInputDeviceEvdev: Create associated ClutterInputDevice
https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-07-26 18:45:25 +02:00
73d5d837db ClutterVirtualInputDeviceEvdev: Construct with a specific seat
We are still single seated, so until we are properly multi seated its
always the main seat.

https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-07-26 18:45:25 +02:00
ea5b691ac6 ClutterVirtualInputDevice: Store the device type
https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-07-26 18:45:25 +02:00
53d1b11386 clutter/evdev: Move keyboard and pointer notification into seat
We notify per seat; so lets move the logic there. Touch and tablets to
follow later.

https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-07-26 18:45:25 +02:00
85e8feca67 ClutterVirtualInputDevice: Keep track of the device manager
https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-07-26 18:45:25 +02:00
fb47374629 ClutterDeviceManagerEvdev: Split out seat into a separate file
Split out ClutterSeatEvdev functionality into a separate file.

https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-07-26 18:45:25 +02:00
9a92d5fe89 clutter: Add virtual input device API
Virtual input devices aim to enable injecting input events as if they
came from hardware events. This is useful for things such as remote
controlling, for example via a remote desktop session.

The API so far only consists of stumps.

https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-07-26 18:45:25 +02:00
19 changed files with 1963 additions and 549 deletions

View File

@ -123,6 +123,7 @@ source_h = \
clutter-transition.h \
clutter-types.h \
clutter-units.h \
clutter-virtual-input-device.h \
clutter-zoom-action.h \
$(NULL)
@ -168,6 +169,7 @@ source_c = \
clutter-image.c \
clutter-input-device.c \
clutter-input-device-tool.c \
clutter-virtual-input-device.c \
clutter-interval.c \
clutter-keyframe-transition.c \
clutter-keysyms-table.c \
@ -418,6 +420,14 @@ x11_source_h_priv += \
x11/clutter-input-device-xi2.h \
$(NULL)
x11_source_c += \
x11/clutter-virtual-input-device-x11.c \
$(NULL)
x11_source_h_priv += \
x11/clutter-virtual-input-device-x11.h \
$(NULL)
backend_source_h += $(x11_source_h)
backend_source_c += $(x11_source_c)
backend_source_h_priv += $(x11_source_h_priv)
@ -458,13 +468,17 @@ backend_source_c += $(glx_source_c)
evdev_c_priv = \
evdev/clutter-device-manager-evdev.c \
evdev/clutter-input-device-evdev.c \
evdev/clutter-seat-evdev.c \
evdev/clutter-virtual-input-device-evdev.c \
evdev/clutter-event-evdev.c \
evdev/clutter-input-device-tool-evdev.c \
$(NULL)
evdev_h_priv = \
evdev/clutter-device-manager-evdev.h \
evdev/clutter-input-device-evdev.h \
evdev/clutter-seat-evdev.h \
evdev/clutter-input-device-tool-evdev.h \
evdev/clutter-virtual-input-device-evdev.h \
$(NULL)
evdev_h = evdev/clutter-evdev.h

View File

@ -47,6 +47,7 @@
#include "clutter-marshal.h"
#include "clutter-private.h"
#include "clutter-stage-private.h"
#include "clutter-virtual-input-device.h"
struct _ClutterDeviceManagerPrivate
{
@ -435,3 +436,25 @@ _clutter_device_manager_get_backend (ClutterDeviceManager *manager)
return manager->priv->backend;
}
/**
* clutter_device_manager_create_virtual_device:
* @device_manager: a #ClutterDeviceManager
* @device_type: the type of the virtual device
*
* Creates a virtual input device.
*
* Returns: (transfer full): a newly created virtual device
**/
ClutterVirtualInputDevice *
clutter_device_manager_create_virtual_device (ClutterDeviceManager *device_manager,
ClutterInputDeviceType device_type)
{
ClutterDeviceManagerClass *manager_class;
g_return_val_if_fail (CLUTTER_IS_DEVICE_MANAGER (device_manager), NULL);
manager_class = CLUTTER_DEVICE_MANAGER_GET_CLASS (device_manager);
return manager_class->create_virtual_device (device_manager,
device_type);
}

View File

@ -83,6 +83,8 @@ struct _ClutterDeviceManagerClass
ClutterInputDevice *device);
void (* select_stage_events) (ClutterDeviceManager *manager,
ClutterStage *stage);
ClutterVirtualInputDevice *(* create_virtual_device) (ClutterDeviceManager *manager,
ClutterInputDeviceType device_type);
/* padding */
gpointer _padding[7];
@ -105,6 +107,10 @@ CLUTTER_AVAILABLE_IN_1_2
ClutterInputDevice * clutter_device_manager_get_core_device (ClutterDeviceManager *device_manager,
ClutterInputDeviceType device_type);
CLUTTER_AVAILABLE_IN_ALL
ClutterVirtualInputDevice *clutter_device_manager_create_virtual_device (ClutterDeviceManager *device_manager,
ClutterInputDeviceType device_type);
G_END_DECLS
#endif /* __CLUTTER_DEVICE_MANAGER_H__ */

View File

@ -95,6 +95,7 @@ typedef struct _ClutterState ClutterState;
typedef struct _ClutterInputDeviceTool ClutterInputDeviceTool;
typedef struct _ClutterInputDevice ClutterInputDevice;
typedef struct _ClutterVirtualInputDevice ClutterVirtualInputDevice;
typedef CoglMatrix ClutterMatrix;

View File

@ -0,0 +1,222 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2016 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Jonas Ådahl <jadahl@gmail.com>
*/
#ifdef HAVE_CONFIG_H
#include "clutter-build-config.h"
#endif
#include <glib-object.h>
#include "clutter-virtual-input-device.h"
#include "clutter-device-manager.h"
#include "clutter-private.h"
#include "clutter-enum-types.h"
enum
{
PROP_0,
PROP_DEVICE_MANAGER,
PROP_DEVICE_TYPE,
PROP_LAST
};
static GParamSpec *obj_props[PROP_LAST];
typedef struct _ClutterVirtualInputDevicePrivate
{
ClutterDeviceManager *manager;
ClutterInputDeviceType device_type;
} ClutterVirtualInputDevicePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (ClutterVirtualInputDevice,
clutter_virtual_input_device,
G_TYPE_OBJECT)
void
clutter_virtual_input_device_notify_relative_motion (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
double dx,
double dy)
{
ClutterVirtualInputDeviceClass *klass =
CLUTTER_VIRTUAL_INPUT_DEVICE_GET_CLASS (virtual_device);
klass->notify_relative_motion (virtual_device, time_us, dx, dy);
}
void
clutter_virtual_input_device_notify_absolute_motion (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
double x,
double y)
{
ClutterVirtualInputDeviceClass *klass =
CLUTTER_VIRTUAL_INPUT_DEVICE_GET_CLASS (virtual_device);
klass->notify_absolute_motion (virtual_device, time_us, x, y);
}
void
clutter_virtual_input_device_notify_button (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t button,
ClutterButtonState button_state)
{
ClutterVirtualInputDeviceClass *klass =
CLUTTER_VIRTUAL_INPUT_DEVICE_GET_CLASS (virtual_device);
klass->notify_button (virtual_device, time_us, button, button_state);
}
void
clutter_virtual_input_device_notify_key (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t key,
ClutterKeyState key_state)
{
ClutterVirtualInputDeviceClass *klass =
CLUTTER_VIRTUAL_INPUT_DEVICE_GET_CLASS (virtual_device);
klass->notify_key (virtual_device, time_us, key, key_state);
}
void
clutter_virtual_input_device_notify_keyval (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t keyval,
ClutterKeyState key_state)
{
ClutterVirtualInputDeviceClass *klass =
CLUTTER_VIRTUAL_INPUT_DEVICE_GET_CLASS (virtual_device);
klass->notify_keyval (virtual_device, time_us, keyval, key_state);
}
/**
* clutter_virtual_input_device_get_manager:
* @virtual_device: a virtual device
*
* Gets the device manager of this virtual device.
*
* Returns: (transfer none): The #ClutterDeviceManager of this virtual device
**/
ClutterDeviceManager *
clutter_virtual_input_device_get_manager (ClutterVirtualInputDevice *virtual_device)
{
ClutterVirtualInputDevicePrivate *priv =
clutter_virtual_input_device_get_instance_private (virtual_device);
return priv->manager;
}
int
clutter_virtual_input_device_get_device_type (ClutterVirtualInputDevice *virtual_device)
{
ClutterVirtualInputDevicePrivate *priv =
clutter_virtual_input_device_get_instance_private (virtual_device);
return priv->device_type;
}
static void
clutter_virtual_input_device_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterVirtualInputDevice *virtual_device =
CLUTTER_VIRTUAL_INPUT_DEVICE (object);
ClutterVirtualInputDevicePrivate *priv =
clutter_virtual_input_device_get_instance_private (virtual_device);
switch (prop_id)
{
case PROP_DEVICE_MANAGER:
g_value_set_object (value, priv->manager);
break;
case PROP_DEVICE_TYPE:
g_value_set_enum (value, priv->device_type);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clutter_virtual_input_device_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterVirtualInputDevice *virtual_device =
CLUTTER_VIRTUAL_INPUT_DEVICE (object);
ClutterVirtualInputDevicePrivate *priv =
clutter_virtual_input_device_get_instance_private (virtual_device);
switch (prop_id)
{
case PROP_DEVICE_MANAGER:
priv->manager = g_value_get_object (value);
break;
case PROP_DEVICE_TYPE:
priv->device_type = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clutter_virtual_input_device_init (ClutterVirtualInputDevice *virtual_device)
{
}
static void
clutter_virtual_input_device_class_init (ClutterVirtualInputDeviceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = clutter_virtual_input_device_get_property;
object_class->set_property = clutter_virtual_input_device_set_property;
obj_props[PROP_DEVICE_MANAGER] =
g_param_spec_object ("device-manager",
P_("Device Manager"),
P_("The device manager instance"),
CLUTTER_TYPE_DEVICE_MANAGER,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
obj_props[PROP_DEVICE_TYPE] =
g_param_spec_enum ("device-type",
P_("Device type"),
P_("Device type"),
CLUTTER_TYPE_INPUT_DEVICE_TYPE,
CLUTTER_POINTER_DEVICE,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, PROP_LAST, obj_props);
}

View File

@ -0,0 +1,116 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2016 Red Hat inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Jonas Ådahl <jadahl@gmail.com>
*/
#ifndef __CLUTTER_VIRTUAL_INPUT_DEVICE_H__
#define __CLUTTER_VIRTUAL_INPUT_DEVICE_H__
#include <glib-object.h>
#include <stdint.h>
#include "clutter-device-manager.h"
#define CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE (clutter_virtual_input_device_get_type ())
CLUTTER_AVAILABLE_IN_ALL
G_DECLARE_DERIVABLE_TYPE (ClutterVirtualInputDevice,
clutter_virtual_input_device,
CLUTTER, VIRTUAL_INPUT_DEVICE,
GObject)
typedef enum _ClutterButtonState
{
CLUTTER_BUTTON_STATE_RELEASED,
CLUTTER_BUTTON_STATE_PRESSED
} ClutterButtonState;
typedef enum _ClutterKeyState
{
CLUTTER_KEY_STATE_RELEASED,
CLUTTER_KEY_STATE_PRESSED
} ClutterKeyState;
struct _ClutterVirtualInputDeviceClass
{
GObjectClass parent_class;
void (*notify_relative_motion) (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
double dx,
double dy);
void (*notify_absolute_motion) (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
double x,
double y);
void (*notify_button) (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t button,
ClutterButtonState button_state);
void (*notify_key) (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t key,
ClutterKeyState key_state);
void (*notify_keyval) (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t keyval,
ClutterKeyState key_state);
};
CLUTTER_AVAILABLE_IN_ALL
void clutter_virtual_input_device_notify_relative_motion (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
double dx,
double dy);
CLUTTER_AVAILABLE_IN_ALL
void clutter_virtual_input_device_notify_absolute_motion (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
double x,
double y);
CLUTTER_AVAILABLE_IN_ALL
void clutter_virtual_input_device_notify_button (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t button,
ClutterButtonState button_state);
CLUTTER_AVAILABLE_IN_ALL
void clutter_virtual_input_device_notify_key (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t key,
ClutterKeyState key_state);
CLUTTER_AVAILABLE_IN_ALL
void clutter_virtual_input_device_notify_keyval (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t keyval,
ClutterKeyState key_state);
CLUTTER_AVAILABLE_IN_ALL
ClutterDeviceManager * clutter_virtual_input_device_get_manager (ClutterVirtualInputDevice *virtual_device);
int clutter_virtual_input_device_get_device_type (ClutterVirtualInputDevice *virtual_device);
#endif /* __CLUTTER_VIRTUAL_INPUT_DEVICE_H__ */

View File

@ -107,6 +107,7 @@
#include "clutter-transition.h"
#include "clutter-units.h"
#include "clutter-version.h"
#include "clutter-virtual-input-device.h"
#include "clutter-zoom-action.h"
#include "clutter-deprecated.h"

View File

@ -46,6 +46,8 @@
#include "clutter-device-manager-private.h"
#include "clutter-event-private.h"
#include "clutter-input-device-evdev.h"
#include "clutter-seat-evdev.h"
#include "clutter-virtual-input-device-evdev.h"
#include "clutter-main.h"
#include "clutter-private.h"
#include "clutter-stage-manager.h"
@ -59,12 +61,6 @@
#define DISCRETE_SCROLL_STEP 10.0
#define AUTOREPEAT_VALUE 2
/* Try to keep the pointer inside the stage. Hopefully no one is using
* this backend with stages smaller than this. */
#define INITIAL_POINTER_X 16
#define INITIAL_POINTER_Y 16
/*
* Clutter makes the assumption that two core devices have ID's 2 and 3 (core
@ -76,50 +72,8 @@
*/
#define INITIAL_DEVICE_ID 2
typedef struct _ClutterTouchState ClutterTouchState;
typedef struct _ClutterEventFilter ClutterEventFilter;
struct _ClutterTouchState
{
guint32 id;
ClutterPoint coords;
};
struct _ClutterSeatEvdev
{
struct libinput_seat *libinput_seat;
ClutterDeviceManagerEvdev *manager_evdev;
GSList *devices;
ClutterInputDevice *core_pointer;
ClutterInputDevice *core_keyboard;
GHashTable *touches;
struct xkb_state *xkb;
xkb_led_index_t caps_lock_led;
xkb_led_index_t num_lock_led;
xkb_led_index_t scroll_lock_led;
uint32_t button_state;
/* keyboard repeat */
gboolean repeat;
guint32 repeat_delay;
guint32 repeat_interval;
guint32 repeat_key;
guint32 repeat_count;
guint32 repeat_timer;
ClutterInputDevice *repeat_device;
gfloat pointer_x;
gfloat pointer_y;
/* Emulation of discrete scroll events out of smooth ones */
gfloat accum_scroll_dx;
gfloat accum_scroll_dy;
};
struct _ClutterEventFilter
{
ClutterEvdevFilterFunc func;
@ -198,24 +152,6 @@ static const char *option_xkb_layout = "us";
static const char *option_xkb_variant = "";
static const char *option_xkb_options = "";
static inline guint64
us (guint64 us)
{
return us;
}
static inline guint64
ms2us (guint64 ms)
{
return us (ms * 1000);
}
static inline guint32
us2ms (guint64 us)
{
return (guint32) (us / 1000);
}
static void
clutter_device_manager_evdev_copy_event_data (ClutterEventExtender *event_extender,
const ClutterEvent *src,
@ -299,134 +235,34 @@ queue_event (ClutterEvent *event)
_clutter_event_push (event, FALSE);
}
static void
clear_repeat_timer (ClutterSeatEvdev *seat)
void
_clutter_device_manager_evdev_constrain_pointer (ClutterDeviceManagerEvdev *manager_evdev,
ClutterInputDevice *core_pointer,
uint64_t time_us,
float x,
float y,
float *new_x,
float *new_y)
{
if (seat->repeat_timer)
if (manager_evdev->priv->constrain_callback)
{
g_source_remove (seat->repeat_timer);
seat->repeat_timer = 0;
g_clear_object (&seat->repeat_device);
}
}
static gboolean
keyboard_repeat (gpointer data);
static void
clutter_seat_evdev_sync_leds (ClutterSeatEvdev *seat);
static void
notify_key_device (ClutterInputDevice *input_device,
guint64 time_us,
guint32 key,
guint32 state,
gboolean update_keys)
{
ClutterInputDeviceEvdev *device_evdev =
CLUTTER_INPUT_DEVICE_EVDEV (input_device);
ClutterSeatEvdev *seat = _clutter_input_device_evdev_get_seat (device_evdev);
ClutterStage *stage;
ClutterEvent *event = NULL;
enum xkb_state_component changed_state;
/* 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)
{
clear_repeat_timer (seat);
return;
}
event = _clutter_key_event_new_from_evdev (input_device,
seat->core_keyboard,
stage,
seat->xkb,
seat->button_state,
us2ms (time_us), key, state);
_clutter_evdev_event_set_event_code (event, key);
/* We must be careful and not pass multiple releases to xkb, otherwise it gets
confused and locks the modifiers */
if (state != AUTOREPEAT_VALUE)
{
changed_state = xkb_state_update_key (seat->xkb,
event->key.hardware_keycode,
state ? XKB_KEY_DOWN : XKB_KEY_UP);
manager_evdev->priv->constrain_callback (core_pointer,
us2ms (time_us),
x, y,
new_x, new_y,
manager_evdev->priv->constrain_data);
}
else
{
changed_state = 0;
clutter_event_set_flags (event, CLUTTER_EVENT_FLAG_SYNTHETIC);
}
ClutterActor *stage = CLUTTER_ACTOR (manager_evdev->priv->stage);
float stage_width = clutter_actor_get_width (stage);
float stage_height = clutter_actor_get_height (stage);
queue_event (event);
if (update_keys && (changed_state & XKB_STATE_LEDS))
clutter_seat_evdev_sync_leds (seat);
if (state == 0 || /* key release */
!seat->repeat ||
!xkb_keymap_key_repeats (xkb_state_get_keymap (seat->xkb), event->key.hardware_keycode))
{
clear_repeat_timer (seat);
return;
}
if (state == 1) /* key press */
seat->repeat_count = 0;
seat->repeat_count += 1;
seat->repeat_key = key;
switch (seat->repeat_count)
{
case 1:
case 2:
{
guint32 interval;
clear_repeat_timer (seat);
seat->repeat_device = g_object_ref (input_device);
if (seat->repeat_count == 1)
interval = seat->repeat_delay;
else
interval = seat->repeat_interval;
seat->repeat_timer =
clutter_threads_add_timeout_full (CLUTTER_PRIORITY_EVENTS,
interval,
keyboard_repeat,
seat,
NULL);
return;
}
default:
return;
x = CLAMP (x, 0.f, stage_width - 1);
y = CLAMP (y, 0.f, stage_height - 1);
}
}
static gboolean
keyboard_repeat (gpointer data)
{
ClutterSeatEvdev *seat = data;
GSource *source;
guint32 time_ms;
g_return_val_if_fail (seat->repeat_device != NULL, G_SOURCE_REMOVE);
source = g_main_context_find_source_by_id (NULL, seat->repeat_timer);
time_ms = g_source_get_time (source) / 1000;
notify_key_device (seat->repeat_device,
ms2us (time_ms),
seat->repeat_key,
AUTOREPEAT_VALUE,
FALSE);
return G_SOURCE_CONTINUE;
}
static ClutterEvent *
new_absolute_motion_event (ClutterInputDevice *input_device,
@ -511,45 +347,6 @@ notify_absolute_motion (ClutterInputDevice *input_device,
queue_event (event);
}
static void
notify_relative_motion (ClutterInputDevice *input_device,
struct libinput_event_pointer *pointer_event)
{
guint64 time_us;
double dx;
double dy;
double dx_unaccel;
double dy_unaccel;
gfloat new_x, new_y;
ClutterInputDeviceEvdev *device_evdev;
ClutterSeatEvdev *seat;
ClutterEvent *event;
/* We can drop the event on the floor if no stage has been
* associated with the device yet. */
if (!_clutter_input_device_get_stage (input_device))
return;
device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (input_device);
seat = _clutter_input_device_evdev_get_seat (device_evdev);
dx = libinput_event_pointer_get_dx (pointer_event);
dy = libinput_event_pointer_get_dy (pointer_event);
new_x = seat->pointer_x + dx;
new_y = seat->pointer_y + dy;
time_us = libinput_event_pointer_get_time_usec (pointer_event);
event = new_absolute_motion_event (input_device, time_us, new_x, new_y, NULL);
dx_unaccel = libinput_event_pointer_get_dx_unaccelerated (pointer_event);
dy_unaccel = libinput_event_pointer_get_dy_unaccelerated (pointer_event);
_clutter_evdev_event_set_relative_motion (event,
dx, dy,
dx_unaccel, dy_unaccel);
queue_event (event);
}
static void
notify_relative_tool_motion (ClutterInputDevice *input_device,
guint64 time_us,
@ -682,118 +479,6 @@ notify_scroll (ClutterInputDevice *input_device,
queue_event (event);
}
static void
notify_button (ClutterInputDevice *input_device,
guint64 time_us,
guint32 button,
guint32 state)
{
ClutterInputDeviceEvdev *device_evdev;
ClutterSeatEvdev *seat;
ClutterStage *stage;
ClutterEvent *event = NULL;
gint button_nr;
static gint maskmap[8] =
{
CLUTTER_BUTTON1_MASK, CLUTTER_BUTTON3_MASK, CLUTTER_BUTTON2_MASK,
CLUTTER_BUTTON4_MASK, CLUTTER_BUTTON5_MASK, 0, 0, 0
};
/* 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);
/* The evdev button numbers don't map sequentially to clutter button
* numbers (the right and middle mouse buttons are in the opposite
* order) so we'll map them directly with a switch statement */
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 */
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;
}
if (button_nr < 1 || button_nr > 12)
{
g_warning ("Unhandled button event 0x%x", button);
return;
}
if (state)
event = clutter_event_new (CLUTTER_BUTTON_PRESS);
else
event = clutter_event_new (CLUTTER_BUTTON_RELEASE);
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);
_clutter_xkb_translate_state (event, seat->xkb, seat->button_state);
event->button.button = button_nr;
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);
}
static void
notify_touch_event (ClutterInputDevice *input_device,
ClutterEventType evtype,
@ -1205,128 +890,6 @@ clutter_event_source_free (ClutterEventSource *source)
g_source_unref (g_source);
}
static void
clutter_touch_state_free (ClutterTouchState *touch_state)
{
g_slice_free (ClutterTouchState, touch_state);
}
static void
clutter_seat_evdev_set_libinput_seat (ClutterSeatEvdev *seat,
struct libinput_seat *libinput_seat)
{
g_assert (seat->libinput_seat == NULL);
libinput_seat_ref (libinput_seat);
libinput_seat_set_user_data (libinput_seat, seat);
seat->libinput_seat = libinput_seat;
}
static ClutterSeatEvdev *
clutter_seat_evdev_new (ClutterDeviceManagerEvdev *manager_evdev)
{
ClutterDeviceManager *manager = CLUTTER_DEVICE_MANAGER (manager_evdev);
ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv;
ClutterSeatEvdev *seat;
ClutterInputDevice *device;
struct xkb_context *ctx;
struct xkb_rule_names names;
struct xkb_keymap *keymap;
seat = g_new0 (ClutterSeatEvdev, 1);
if (!seat)
return NULL;
device = _clutter_input_device_evdev_new_virtual (
manager, seat, CLUTTER_POINTER_DEVICE);
_clutter_input_device_set_stage (device, priv->stage);
seat->pointer_x = INITIAL_POINTER_X;
seat->pointer_y = INITIAL_POINTER_Y;
_clutter_input_device_set_coords (device, NULL,
seat->pointer_x, seat->pointer_y,
NULL);
_clutter_device_manager_add_device (manager, device);
seat->core_pointer = device;
device = _clutter_input_device_evdev_new_virtual (
manager, seat, CLUTTER_KEYBOARD_DEVICE);
_clutter_input_device_set_stage (device, priv->stage);
_clutter_device_manager_add_device (manager, device);
seat->core_keyboard = device;
seat->touches = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) clutter_touch_state_free);
ctx = xkb_context_new(0);
g_assert (ctx);
names.rules = "evdev";
names.model = "pc105";
names.layout = option_xkb_layout;
names.variant = option_xkb_variant;
names.options = option_xkb_options;
keymap = xkb_keymap_new_from_names (ctx, &names, 0);
xkb_context_unref(ctx);
if (keymap)
{
seat->xkb = xkb_state_new (keymap);
seat->caps_lock_led =
xkb_keymap_led_get_index (keymap, XKB_LED_NAME_CAPS);
seat->num_lock_led =
xkb_keymap_led_get_index (keymap, XKB_LED_NAME_NUM);
seat->scroll_lock_led =
xkb_keymap_led_get_index (keymap, XKB_LED_NAME_SCROLL);
priv->keymap = keymap;
}
seat->repeat = TRUE;
seat->repeat_delay = 250; /* ms */
seat->repeat_interval = 33; /* ms */
priv->seats = g_slist_append (priv->seats, seat);
return seat;
}
static void
clutter_seat_evdev_free (ClutterSeatEvdev *seat)
{
GSList *iter;
for (iter = seat->devices; iter; iter = g_slist_next (iter))
{
ClutterInputDevice *device = iter->data;
g_object_unref (device);
}
g_slist_free (seat->devices);
g_hash_table_unref (seat->touches);
xkb_state_unref (seat->xkb);
clear_repeat_timer (seat);
if (seat->libinput_seat)
libinput_seat_unref (seat->libinput_seat);
g_free (seat);
}
static void
clutter_seat_evdev_set_stage (ClutterSeatEvdev *seat, ClutterStage *stage)
{
GSList *l;
for (l = seat->devices; l; l = l->next)
{
ClutterInputDevice *device = l->data;
_clutter_input_device_set_stage (device, stage);
}
}
static void
evdev_add_device (ClutterDeviceManagerEvdev *manager_evdev,
struct libinput_device *libinput_device)
@ -1346,11 +909,16 @@ evdev_add_device (ClutterDeviceManagerEvdev *manager_evdev,
* which are located on the main seat. Make whatever seat comes first the
* main seat. */
if (priv->main_seat->libinput_seat == NULL)
seat = priv->main_seat;
{
seat = priv->main_seat;
}
else
seat = clutter_seat_evdev_new (manager_evdev);
{
seat = clutter_seat_evdev_new (manager_evdev);
}
clutter_seat_evdev_set_libinput_seat (seat, libinput_seat);
priv->seats = g_slist_append (priv->seats, seat);
}
device = _clutter_input_device_evdev_new (manager, seat, libinput_device);
@ -1429,7 +997,7 @@ clutter_device_manager_evdev_remove_device (ClutterDeviceManager *manager,
priv->devices = g_slist_remove (priv->devices, device);
if (seat->repeat_timer && seat->repeat_device == device)
clear_repeat_timer (seat);
clutter_seat_evdev_clear_repeat_timer (seat);
g_object_unref (device);
}
@ -1494,32 +1062,6 @@ clutter_device_manager_evdev_get_device (ClutterDeviceManager *manager,
return NULL;
}
static void
clutter_seat_evdev_sync_leds (ClutterSeatEvdev *seat)
{
GSList *iter;
ClutterInputDeviceEvdev *device_evdev;
int caps_lock, num_lock, scroll_lock;
enum libinput_led leds = 0;
caps_lock = xkb_state_led_index_is_active (seat->xkb, seat->caps_lock_led);
num_lock = xkb_state_led_index_is_active (seat->xkb, seat->num_lock_led);
scroll_lock = xkb_state_led_index_is_active (seat->xkb, seat->scroll_lock_led);
if (caps_lock)
leds |= LIBINPUT_LED_CAPS_LOCK;
if (num_lock)
leds |= LIBINPUT_LED_NUM_LOCK;
if (scroll_lock)
leds |= LIBINPUT_LED_SCROLL_LOCK;
for (iter = seat->devices; iter; iter = iter->next)
{
device_evdev = iter->data;
_clutter_input_device_evdev_update_leds (device_evdev, leds);
}
}
static void
flush_event_queue (void)
{
@ -1568,45 +1110,6 @@ process_base_event (ClutterDeviceManagerEvdev *manager_evdev,
return handled;
}
static ClutterTouchState *
_device_seat_add_touch (ClutterInputDevice *input_device,
guint32 id)
{
ClutterInputDeviceEvdev *device_evdev =
CLUTTER_INPUT_DEVICE_EVDEV (input_device);
ClutterSeatEvdev *seat = _clutter_input_device_evdev_get_seat (device_evdev);
ClutterTouchState *touch;
touch = g_slice_new0 (ClutterTouchState);
touch->id = id;
g_hash_table_insert (seat->touches, GUINT_TO_POINTER (id), touch);
return touch;
}
static void
_device_seat_remove_touch (ClutterInputDevice *input_device,
guint32 id)
{
ClutterInputDeviceEvdev *device_evdev =
CLUTTER_INPUT_DEVICE_EVDEV (input_device);
ClutterSeatEvdev *seat = _clutter_input_device_evdev_get_seat (device_evdev);
g_hash_table_remove (seat->touches, GUINT_TO_POINTER (id));
}
static ClutterTouchState *
_device_seat_get_touch (ClutterInputDevice *input_device,
guint32 id)
{
ClutterInputDeviceEvdev *device_evdev =
CLUTTER_INPUT_DEVICE_EVDEV (input_device);
ClutterSeatEvdev *seat = _clutter_input_device_evdev_get_seat (device_evdev);
return g_hash_table_lookup (seat->touches, GUINT_TO_POINTER (id));
}
static void
check_notify_discrete_scroll (ClutterDeviceManagerEvdev *manager_evdev,
ClutterInputDevice *device,
@ -1773,6 +1276,14 @@ translate_tablet_axes (struct libinput_event_tablet_tool *tablet_event)
return (gdouble *) g_array_free (axes, FALSE);
}
static ClutterSeatEvdev *
seat_from_device (ClutterInputDevice *device)
{
ClutterInputDeviceEvdev *device_evdev = CLUTTER_INPUT_DEVICE_EVDEV (device);
return _clutter_input_device_evdev_get_seat (device_evdev);
}
static gboolean
process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
struct libinput_event *event)
@ -1789,8 +1300,8 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
guint64 time_us;
struct libinput_event_keyboard *key_event =
libinput_event_get_keyboard_event (event);
device = libinput_device_get_user_data (libinput_device);
device = libinput_device_get_user_data (libinput_device);
time_us = libinput_event_keyboard_get_time_usec (key_event);
key = libinput_event_keyboard_get_key (key_event);
key_state = libinput_event_keyboard_get_key_state (key_event) ==
@ -1805,18 +1316,35 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
seat_key_count != 0))
break;
notify_key_device (device, time_us, key, key_state, TRUE);
clutter_seat_evdev_notify_key (seat_from_device (device),
device,
time_us, key, key_state, TRUE);
break;
}
case LIBINPUT_EVENT_POINTER_MOTION:
{
struct libinput_event_pointer *motion_event =
struct libinput_event_pointer *pointer_event =
libinput_event_get_pointer_event (event);
device = libinput_device_get_user_data (libinput_device);
uint64_t time_us;
double dx;
double dy;
double dx_unaccel;
double dy_unaccel;
notify_relative_motion (device, motion_event);
device = libinput_device_get_user_data (libinput_device);
time_us = libinput_event_pointer_get_time_usec (pointer_event);
dx = libinput_event_pointer_get_dx (pointer_event);
dy = libinput_event_pointer_get_dy (pointer_event);
dx_unaccel = libinput_event_pointer_get_dx_unaccelerated (pointer_event);
dy_unaccel = libinput_event_pointer_get_dy_unaccelerated (pointer_event);
clutter_seat_evdev_notify_relative_motion (seat_from_device (device),
device,
time_us,
dx, dy,
dx_unaccel, dy_unaccel);
break;
}
@ -1843,7 +1371,12 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
stage_width);
y = libinput_event_pointer_get_absolute_y_transformed (motion_event,
stage_height);
notify_absolute_motion (device, time_us, x, y, NULL);
clutter_seat_evdev_notify_absolute_motion (seat_from_device (device),
device,
time_us,
x, y,
NULL);
break;
}
@ -1870,8 +1403,8 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
seat_button_count != 0))
break;
notify_button (device, time_us, button, button_state);
clutter_seat_evdev_notify_button (seat_from_device (device), device,
time_us, button, button_state);
break;
}
@ -1966,11 +1499,14 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
guint64 time_us;
double x, y;
gfloat stage_width, stage_height;
ClutterSeatEvdev *seat;
ClutterStage *stage;
ClutterTouchState *touch_state;
struct libinput_event_touch *touch_event =
libinput_event_get_touch_event (event);
device = libinput_device_get_user_data (libinput_device);
seat = _clutter_input_device_evdev_get_seat (CLUTTER_INPUT_DEVICE_EVDEV (device));
stage = _clutter_input_device_get_stage (device);
if (stage == NULL)
@ -1986,7 +1522,7 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
y = libinput_event_touch_get_y_transformed (touch_event,
stage_height);
touch_state = _device_seat_add_touch (device, slot);
touch_state = clutter_seat_evdev_add_touch (seat, slot);
touch_state->coords.x = x;
touch_state->coords.y = y;
@ -1999,18 +1535,21 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
{
gint32 slot;
guint64 time_us;
ClutterSeatEvdev *seat;
ClutterTouchState *touch_state;
struct libinput_event_touch *touch_event =
libinput_event_get_touch_event (event);
device = libinput_device_get_user_data (libinput_device);
seat = _clutter_input_device_evdev_get_seat (CLUTTER_INPUT_DEVICE_EVDEV (device));
slot = libinput_event_touch_get_slot (touch_event);
time_us = libinput_event_touch_get_time_usec (touch_event);
touch_state = _device_seat_get_touch (device, slot);
touch_state = clutter_seat_evdev_get_touch (seat, slot);
notify_touch_event (device, CLUTTER_TOUCH_END, time_us, slot,
touch_state->coords.x, touch_state->coords.y);
_device_seat_remove_touch (device, slot);
clutter_seat_evdev_remove_touch (seat, slot);
break;
}
@ -2021,11 +1560,14 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
guint64 time_us;
double x, y;
gfloat stage_width, stage_height;
ClutterSeatEvdev *seat;
ClutterStage *stage;
ClutterTouchState *touch_state;
struct libinput_event_touch *touch_event =
libinput_event_get_touch_event (event);
device = libinput_device_get_user_data (libinput_device);
seat = _clutter_input_device_evdev_get_seat (CLUTTER_INPUT_DEVICE_EVDEV (device));
stage = _clutter_input_device_get_stage (device);
if (stage == NULL)
@ -2041,7 +1583,7 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
y = libinput_event_touch_get_y_transformed (touch_event,
stage_height);
touch_state = _device_seat_get_touch (device, slot);
touch_state = clutter_seat_evdev_get_touch (seat, slot);
touch_state->coords.x = x;
touch_state->coords.y = y;
@ -2215,34 +1757,38 @@ process_device_event (ClutterDeviceManagerEvdev *manager_evdev,
}
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
{
guint64 time;
guint64 time_us;
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);
time_us = 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);
clutter_seat_evdev_notify_button (seat_from_device (device), device,
time_us, tablet_button, button_state);
break;
}
case LIBINPUT_EVENT_TABLET_TOOL_TIP:
{
guint64 time;
guint64 time_us;
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);
time_us = 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);
clutter_seat_evdev_notify_button (seat_from_device (device), device,
time_us, BTN_TOUCH, button_state);
break;
}
case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
@ -2413,6 +1959,21 @@ static const struct libinput_interface libinput_interface = {
close_restricted
};
static ClutterVirtualInputDevice *
clutter_device_manager_evdev_create_virtual_device (ClutterDeviceManager *manager,
ClutterInputDeviceType device_type)
{
ClutterDeviceManagerEvdev *manager_evdev =
CLUTTER_DEVICE_MANAGER_EVDEV (manager);
ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv;
return g_object_new (CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE_EVDEV,
"device-manager", manager,
"seat", priv->main_seat,
"device-type", device_type,
NULL);
}
/*
* GObject implementation
*/
@ -2424,6 +1985,8 @@ clutter_device_manager_evdev_constructed (GObject *gobject)
ClutterDeviceManagerEvdevPrivate *priv;
ClutterEventSource *source;
struct udev *udev;
struct xkb_context *ctx;
struct xkb_rule_names names;
udev = udev_new ();
if (G_UNLIKELY (udev == NULL))
@ -2454,6 +2017,17 @@ clutter_device_manager_evdev_constructed (GObject *gobject)
udev_unref (udev);
names.rules = "evdev";
names.model = "pc105";
names.layout = option_xkb_layout;
names.variant = option_xkb_variant;
names.options = option_xkb_options;
ctx = xkb_context_new (0);
g_assert (ctx);
priv->keymap = xkb_keymap_new_from_names (ctx, &names, 0);
xkb_context_unref (ctx);
priv->main_seat = clutter_seat_evdev_new (manager_evdev);
dispatch_libinput (manager_evdev);
@ -2539,6 +2113,7 @@ clutter_device_manager_evdev_class_init (ClutterDeviceManagerEvdevClass *klass)
manager_class->get_devices = clutter_device_manager_evdev_get_devices;
manager_class->get_core_device = clutter_device_manager_evdev_get_core_device;
manager_class->get_device = clutter_device_manager_evdev_get_device;
manager_class->create_virtual_device = clutter_device_manager_evdev_create_virtual_device;
}
static void
@ -2684,6 +2259,22 @@ _clutter_device_manager_evdev_release_device_id (ClutterDeviceManagerEvdev *mana
compare_ids);
}
struct xkb_keymap *
_clutter_device_manager_evdev_get_keymap (ClutterDeviceManagerEvdev *manager_evdev)
{
ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv;
return priv->keymap;
}
ClutterStage *
_clutter_device_manager_evdev_get_stage (ClutterDeviceManagerEvdev *manager_evdev)
{
ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv;
return priv->stage;
}
/**
* clutter_evdev_release_devices:
*

View File

@ -24,6 +24,7 @@
#ifndef __CLUTTER_DEVICE_MANAGER_EVDEV_H__
#define __CLUTTER_DEVICE_MANAGER_EVDEV_H__
#include <clutter/clutter-backend.h>
#include <clutter/clutter-device-manager.h>
G_BEGIN_DECLS
@ -39,6 +40,8 @@ typedef struct _ClutterDeviceManagerEvdev ClutterDeviceManagerEvdev;
typedef struct _ClutterDeviceManagerEvdevClass ClutterDeviceManagerEvdevClass;
typedef struct _ClutterDeviceManagerEvdevPrivate ClutterDeviceManagerEvdevPrivate;
typedef struct _ClutterSeatEvdev ClutterSeatEvdev;
struct _ClutterDeviceManagerEvdev
{
ClutterDeviceManager parent_instance;
@ -61,6 +64,36 @@ gint _clutter_device_manager_evdev_acquire_device_id (ClutterDeviceManagerEvdev
void _clutter_device_manager_evdev_release_device_id (ClutterDeviceManagerEvdev *manager_evdev,
ClutterInputDevice *device);
struct xkb_keymap * _clutter_device_manager_evdev_get_keymap (ClutterDeviceManagerEvdev *manager_evdev);
ClutterStage * _clutter_device_manager_evdev_get_stage (ClutterDeviceManagerEvdev *manager_evdev);
void _clutter_device_manager_evdev_constrain_pointer (ClutterDeviceManagerEvdev *manager_evdev,
ClutterInputDevice *core_pointer,
uint64_t time_us,
float x,
float y,
float *new_x,
float *new_y);
static inline guint64
us (guint64 us)
{
return us;
}
static inline guint64
ms2us (guint64 ms)
{
return us (ms * 1000);
}
static inline guint32
us2ms (guint64 us)
{
return (guint32) (us / 1000);
}
G_END_DECLS
#endif /* __CLUTTER_DEVICE_MANAGER_EVDEV_H__ */

View File

@ -196,7 +196,8 @@ _clutter_input_device_evdev_new (ClutterDeviceManager *manager,
ClutterInputDevice *
_clutter_input_device_evdev_new_virtual (ClutterDeviceManager *manager,
ClutterSeatEvdev *seat,
ClutterInputDeviceType type)
ClutterInputDeviceType type,
ClutterInputMode mode)
{
ClutterInputDeviceEvdev *device;
ClutterDeviceManagerEvdev *manager_evdev;
@ -223,7 +224,7 @@ _clutter_input_device_evdev_new_virtual (ClutterDeviceManager *manager,
"name", name,
"device-manager", manager,
"device-type", type,
"device-mode", CLUTTER_INPUT_MODE_MASTER,
"device-mode", mode,
"enabled", TRUE,
NULL);

View File

@ -29,7 +29,8 @@
#include <glib-object.h>
#include <libinput.h>
#include <clutter/clutter-input-device.h>
#include "clutter/clutter-device-manager-private.h"
#include "evdev/clutter-seat-evdev.h"
G_BEGIN_DECLS
@ -56,7 +57,6 @@ G_BEGIN_DECLS
CLUTTER_TYPE_INPUT_DEVICE_EVDEV, ClutterInputDeviceEvdevClass))
typedef struct _ClutterInputDeviceEvdev ClutterInputDeviceEvdev;
typedef struct _ClutterSeatEvdev ClutterSeatEvdev;
typedef struct _ClutterEventEvdev ClutterEventEvdev;
struct _ClutterInputDeviceEvdev
@ -76,7 +76,8 @@ ClutterInputDevice * _clutter_input_device_evdev_new (ClutterDe
ClutterInputDevice * _clutter_input_device_evdev_new_virtual (ClutterDeviceManager *manager,
ClutterSeatEvdev *seat,
ClutterInputDeviceType type);
ClutterInputDeviceType type,
ClutterInputMode mode);
ClutterSeatEvdev * _clutter_input_device_evdev_get_seat (ClutterInputDeviceEvdev *device);

View File

@ -0,0 +1,590 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010 Intel Corp.
* Copyright (C) 2014 Jonas Ådahl
* Copyright (C) 2016 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Damien Lespiau <damien.lespiau@intel.com>
* Author: Jonas Ådahl <jadahl@gmail.com>
*/
#include "clutter-build-config.h"
#include "clutter-seat-evdev.h"
#include <linux/input.h>
#include "clutter-event-private.h"
#include "clutter-input-device-evdev.h"
#include "clutter-main.h"
/* Try to keep the pointer inside the stage. Hopefully no one is using
* this backend with stages smaller than this. */
#define INITIAL_POINTER_X 16
#define INITIAL_POINTER_Y 16
#define AUTOREPEAT_VALUE 2
void
clutter_seat_evdev_set_libinput_seat (ClutterSeatEvdev *seat,
struct libinput_seat *libinput_seat)
{
g_assert (seat->libinput_seat == NULL);
libinput_seat_ref (libinput_seat);
libinput_seat_set_user_data (libinput_seat, seat);
seat->libinput_seat = libinput_seat;
}
void
clutter_seat_evdev_sync_leds (ClutterSeatEvdev *seat)
{
GSList *iter;
ClutterInputDeviceEvdev *device_evdev;
int caps_lock, num_lock, scroll_lock;
enum libinput_led leds = 0;
caps_lock = xkb_state_led_index_is_active (seat->xkb, seat->caps_lock_led);
num_lock = xkb_state_led_index_is_active (seat->xkb, seat->num_lock_led);
scroll_lock = xkb_state_led_index_is_active (seat->xkb, seat->scroll_lock_led);
if (caps_lock)
leds |= LIBINPUT_LED_CAPS_LOCK;
if (num_lock)
leds |= LIBINPUT_LED_NUM_LOCK;
if (scroll_lock)
leds |= LIBINPUT_LED_SCROLL_LOCK;
for (iter = seat->devices; iter; iter = iter->next)
{
device_evdev = iter->data;
_clutter_input_device_evdev_update_leds (device_evdev, leds);
}
}
static void
clutter_touch_state_free (ClutterTouchState *touch_state)
{
g_slice_free (ClutterTouchState, touch_state);
}
ClutterTouchState *
clutter_seat_evdev_add_touch (ClutterSeatEvdev *seat,
guint32 id)
{
ClutterTouchState *touch;
touch = g_slice_new0 (ClutterTouchState);
touch->id = id;
g_hash_table_insert (seat->touches, GUINT_TO_POINTER (id), touch);
return touch;
}
void
clutter_seat_evdev_remove_touch (ClutterSeatEvdev *seat,
guint32 id)
{
g_hash_table_remove (seat->touches, GUINT_TO_POINTER (id));
}
ClutterTouchState *
clutter_seat_evdev_get_touch (ClutterSeatEvdev *seat,
guint32 id)
{
return g_hash_table_lookup (seat->touches, GUINT_TO_POINTER (id));
}
ClutterSeatEvdev *
clutter_seat_evdev_new (ClutterDeviceManagerEvdev *manager_evdev)
{
ClutterDeviceManager *manager = CLUTTER_DEVICE_MANAGER (manager_evdev);
ClutterSeatEvdev *seat;
ClutterInputDevice *device;
ClutterStage *stage;
struct xkb_keymap *keymap;
seat = g_new0 (ClutterSeatEvdev, 1);
if (!seat)
return NULL;
seat->manager_evdev = manager_evdev;
device = _clutter_input_device_evdev_new_virtual (
manager, seat, CLUTTER_POINTER_DEVICE,
CLUTTER_INPUT_MODE_MASTER);
stage = _clutter_device_manager_evdev_get_stage (manager_evdev);
_clutter_input_device_set_stage (device, stage);
seat->pointer_x = INITIAL_POINTER_X;
seat->pointer_y = INITIAL_POINTER_Y;
_clutter_input_device_set_coords (device, NULL,
seat->pointer_x, seat->pointer_y,
NULL);
_clutter_device_manager_add_device (manager, device);
seat->core_pointer = device;
device = _clutter_input_device_evdev_new_virtual (
manager, seat, CLUTTER_KEYBOARD_DEVICE,
CLUTTER_INPUT_MODE_MASTER);
_clutter_input_device_set_stage (device, stage);
_clutter_device_manager_add_device (manager, device);
seat->core_keyboard = device;
seat->touches = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) clutter_touch_state_free);
seat->repeat = TRUE;
seat->repeat_delay = 250; /* ms */
seat->repeat_interval = 33; /* ms */
keymap = _clutter_device_manager_evdev_get_keymap (manager_evdev);
if (keymap)
{
seat->xkb = xkb_state_new (keymap);
seat->caps_lock_led =
xkb_keymap_led_get_index (keymap, XKB_LED_NAME_CAPS);
seat->num_lock_led =
xkb_keymap_led_get_index (keymap, XKB_LED_NAME_NUM);
seat->scroll_lock_led =
xkb_keymap_led_get_index (keymap, XKB_LED_NAME_SCROLL);
}
return seat;
}
void
clutter_seat_evdev_clear_repeat_timer (ClutterSeatEvdev *seat)
{
if (seat->repeat_timer)
{
g_source_remove (seat->repeat_timer);
seat->repeat_timer = 0;
g_clear_object (&seat->repeat_device);
}
}
static gboolean
keyboard_repeat (gpointer data)
{
ClutterSeatEvdev *seat = data;
GSource *source;
guint32 time_ms;
g_return_val_if_fail (seat->repeat_device != NULL, G_SOURCE_REMOVE);
source = g_main_context_find_source_by_id (NULL, seat->repeat_timer);
time_ms = g_source_get_time (source) / 1000;
clutter_seat_evdev_notify_key (seat,
seat->repeat_device,
ms2us (time_ms),
seat->repeat_key,
AUTOREPEAT_VALUE,
FALSE);
return G_SOURCE_CONTINUE;
}
static void
queue_event (ClutterEvent *event)
{
_clutter_event_push (event, FALSE);
}
static int
update_button_count (ClutterSeatEvdev *seat,
uint32_t button,
uint32_t state)
{
if (state)
{
return ++seat->button_count[button];
}
else
{
/* Handle cases where we newer saw the initial pressed event. */
if (seat->button_count[button] == 0)
return 0;
return --seat->button_count[button];
}
}
void
clutter_seat_evdev_notify_key (ClutterSeatEvdev *seat,
ClutterInputDevice *device,
uint64_t time_us,
uint32_t key,
uint32_t state,
gboolean update_keys)
{
ClutterStage *stage;
ClutterEvent *event = NULL;
enum xkb_state_component changed_state;
if (state != AUTOREPEAT_VALUE)
{
/* Drop any repeated button press (for example from virtual devices. */
int count = update_button_count (seat, key, state);
if (state && count > 1)
return;
if (!state && count != 0)
return;
}
/* We can drop the event on the floor if no stage has been
* associated with the device yet. */
stage = _clutter_input_device_get_stage (device);
if (stage == NULL)
{
clutter_seat_evdev_clear_repeat_timer (seat);
return;
}
event = _clutter_key_event_new_from_evdev (device,
seat->core_keyboard,
stage,
seat->xkb,
seat->button_state,
us2ms (time_us), key, state);
_clutter_evdev_event_set_event_code (event, key);
/* We must be careful and not pass multiple releases to xkb, otherwise it gets
confused and locks the modifiers */
if (state != AUTOREPEAT_VALUE)
{
changed_state = xkb_state_update_key (seat->xkb,
event->key.hardware_keycode,
state ? XKB_KEY_DOWN : XKB_KEY_UP);
}
else
{
changed_state = 0;
clutter_event_set_flags (event, CLUTTER_EVENT_FLAG_SYNTHETIC);
}
queue_event (event);
if (update_keys && (changed_state & XKB_STATE_LEDS))
clutter_seat_evdev_sync_leds (seat);
if (state == 0 || /* key release */
!seat->repeat ||
!xkb_keymap_key_repeats (xkb_state_get_keymap (seat->xkb),
event->key.hardware_keycode))
{
clutter_seat_evdev_clear_repeat_timer (seat);
return;
}
if (state == 1) /* key press */
seat->repeat_count = 0;
seat->repeat_count += 1;
seat->repeat_key = key;
switch (seat->repeat_count)
{
case 1:
case 2:
{
guint32 interval;
clutter_seat_evdev_clear_repeat_timer (seat);
seat->repeat_device = g_object_ref (device);
if (seat->repeat_count == 1)
interval = seat->repeat_delay;
else
interval = seat->repeat_interval;
seat->repeat_timer =
clutter_threads_add_timeout_full (CLUTTER_PRIORITY_EVENTS,
interval,
keyboard_repeat,
seat,
NULL);
return;
}
default:
return;
}
}
static ClutterEvent *
new_absolute_motion_event (ClutterSeatEvdev *seat,
ClutterInputDevice *input_device,
guint64 time_us,
gfloat x,
gfloat y,
gdouble *axes)
{
ClutterStage *stage = _clutter_input_device_get_stage (input_device);
ClutterEvent *event;
event = clutter_event_new (CLUTTER_MOTION);
if (clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE)
_clutter_device_manager_evdev_constrain_pointer (seat->manager_evdev,
seat->core_pointer,
time_us,
seat->pointer_x,
seat->pointer_y,
&x, &y);
_clutter_evdev_event_set_time_usec (event, time_us);
event->motion.time = us2ms (time_us);
event->motion.stage = stage;
event->motion.device = seat->core_pointer;
_clutter_xkb_translate_state (event, seat->xkb, seat->button_state);
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)
{
ClutterInputDeviceEvdev *device_evdev =
CLUTTER_INPUT_DEVICE_EVDEV (input_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);
if (clutter_input_device_get_device_type (input_device) != CLUTTER_TABLET_DEVICE)
{
seat->pointer_x = x;
seat->pointer_y = y;
}
return event;
}
void
clutter_seat_evdev_notify_relative_motion (ClutterSeatEvdev *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
float dx,
float dy,
float dx_unaccel,
float dy_unaccel)
{
gfloat new_x, new_y;
ClutterEvent *event;
/* We can drop the event on the floor if no stage has been
* associated with the device yet. */
if (!_clutter_input_device_get_stage (input_device))
return;
new_x = seat->pointer_x + dx;
new_y = seat->pointer_y + dy;
event = new_absolute_motion_event (seat, input_device,
time_us, new_x, new_y, NULL);
_clutter_evdev_event_set_relative_motion (event,
dx, dy,
dx_unaccel, dy_unaccel);
queue_event (event);
}
void clutter_seat_evdev_notify_absolute_motion (ClutterSeatEvdev *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
float x,
float y,
double *axes)
{
ClutterEvent *event;
event = new_absolute_motion_event (seat, input_device, time_us, x, x, axes);
queue_event (event);
}
void
clutter_seat_evdev_notify_button (ClutterSeatEvdev *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
uint32_t button,
uint32_t state)
{
ClutterStage *stage;
ClutterEvent *event = NULL;
gint button_nr;
static gint maskmap[8] =
{
CLUTTER_BUTTON1_MASK, CLUTTER_BUTTON3_MASK, CLUTTER_BUTTON2_MASK,
CLUTTER_BUTTON4_MASK, CLUTTER_BUTTON5_MASK, 0, 0, 0
};
int button_count;
/* Drop any repeated button press (for example from virtual devices. */
button_count = update_button_count (seat, button, state);
if (state && button_count > 1)
return;
if (!state && button_count != 0)
return;
/* 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;
/* The evdev button numbers don't map sequentially to clutter button
* numbers (the right and middle mouse buttons are in the opposite
* order) so we'll map them directly with a switch statement */
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 */
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;
}
if (button_nr < 1 || button_nr > 12)
{
g_warning ("Unhandled button event 0x%x", button);
return;
}
if (state)
event = clutter_event_new (CLUTTER_BUTTON_PRESS);
else
event = clutter_event_new (CLUTTER_BUTTON_RELEASE);
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);
_clutter_xkb_translate_state (event, seat->xkb, seat->button_state);
event->button.button = button_nr;
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_device (event, seat->core_pointer);
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)
{
ClutterInputDeviceEvdev *device_evdev =
CLUTTER_INPUT_DEVICE_EVDEV (input_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);
}
void
clutter_seat_evdev_free (ClutterSeatEvdev *seat)
{
GSList *iter;
for (iter = seat->devices; iter; iter = g_slist_next (iter))
{
ClutterInputDevice *device = iter->data;
g_object_unref (device);
}
g_slist_free (seat->devices);
g_hash_table_unref (seat->touches);
xkb_state_unref (seat->xkb);
clutter_seat_evdev_clear_repeat_timer (seat);
if (seat->libinput_seat)
libinput_seat_unref (seat->libinput_seat);
g_free (seat);
}
void
clutter_seat_evdev_set_stage (ClutterSeatEvdev *seat,
ClutterStage *stage)
{
GSList *l;
_clutter_input_device_set_stage (seat->core_pointer, stage);
_clutter_input_device_set_stage (seat->core_keyboard, stage);
for (l = seat->devices; l; l = l->next)
{
ClutterInputDevice *device = l->data;
_clutter_input_device_set_stage (device, stage);
}
}

View File

@ -0,0 +1,132 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010 Intel Corp.
* Copyright (C) 2014 Jonas Ådahl
* Copyright (C) 2016 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Damien Lespiau <damien.lespiau@intel.com>
* Author: Jonas Ådahl <jadahl@gmail.com>
*/
#ifndef __CLUTTER_SEAT_EVDEV_H__
#define __CLUTTER_SEAT_EVDEV_H__
#include <libinput.h>
#include <linux/input.h>
#include "clutter-input-device.h"
#include "clutter-device-manager-evdev.h"
#include "clutter-xkb-utils.h"
typedef struct _ClutterTouchState ClutterTouchState;
struct _ClutterTouchState
{
guint32 id;
ClutterPoint coords;
};
struct _ClutterSeatEvdev
{
struct libinput_seat *libinput_seat;
ClutterDeviceManagerEvdev *manager_evdev;
GSList *devices;
ClutterInputDevice *core_pointer;
ClutterInputDevice *core_keyboard;
GHashTable *touches;
struct xkb_state *xkb;
xkb_led_index_t caps_lock_led;
xkb_led_index_t num_lock_led;
xkb_led_index_t scroll_lock_led;
uint32_t button_state;
int button_count[KEY_CNT];
/* keyboard repeat */
gboolean repeat;
guint32 repeat_delay;
guint32 repeat_interval;
guint32 repeat_key;
guint32 repeat_count;
guint32 repeat_timer;
ClutterInputDevice *repeat_device;
gfloat pointer_x;
gfloat pointer_y;
/* Emulation of discrete scroll events out of smooth ones */
gfloat accum_scroll_dx;
gfloat accum_scroll_dy;
};
void clutter_seat_evdev_notify_key (ClutterSeatEvdev *seat,
ClutterInputDevice *device,
uint64_t time_us,
uint32_t key,
uint32_t state,
gboolean update_keys);
void clutter_seat_evdev_notify_relative_motion (ClutterSeatEvdev *seat_evdev,
ClutterInputDevice *input_device,
uint64_t time_us,
float dx,
float dy,
float dx_unaccel,
float dy_unaccel);
void clutter_seat_evdev_notify_absolute_motion (ClutterSeatEvdev *seat_evdev,
ClutterInputDevice *input_device,
uint64_t time_us,
float x,
float y,
double *axes);
void clutter_seat_evdev_notify_button (ClutterSeatEvdev *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
uint32_t button,
uint32_t state);
void clutter_seat_evdev_set_libinput_seat (ClutterSeatEvdev *seat,
struct libinput_seat *libinput_seat);
void clutter_seat_evdev_sync_leds (ClutterSeatEvdev *seat);
ClutterTouchState * clutter_seat_evdev_add_touch (ClutterSeatEvdev *seat,
guint32 id);
void clutter_seat_evdev_remove_touch (ClutterSeatEvdev *seat,
guint32 id);
ClutterTouchState * clutter_seat_evdev_get_touch (ClutterSeatEvdev *seat,
guint32 id);
void clutter_seat_evdev_set_stage (ClutterSeatEvdev *seat,
ClutterStage *stage);
void clutter_seat_evdev_clear_repeat_timer (ClutterSeatEvdev *seat);
ClutterSeatEvdev * clutter_seat_evdev_new (ClutterDeviceManagerEvdev *manager_evdev);
void clutter_seat_evdev_free (ClutterSeatEvdev *seat);
#endif /* __CLUTTER_SEAT_EVDEV_H__ */

View File

@ -0,0 +1,497 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2016 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Jonas Ådahl <jadahl@gmail.com>
*/
#ifdef HAVE_CONFIG_H
#include "clutter-build-config.h"
#endif
#include <glib-object.h>
#include <linux/input.h>
#include "clutter-private.h"
#include "clutter-virtual-input-device.h"
#include "evdev/clutter-input-device-evdev.h"
#include "evdev/clutter-seat-evdev.h"
#include "evdev/clutter-virtual-input-device-evdev.h"
enum
{
PROP_0,
PROP_SEAT,
PROP_LAST
};
static GParamSpec *obj_props[PROP_LAST];
struct _ClutterVirtualInputDeviceEvdev
{
ClutterVirtualInputDevice parent;
ClutterInputDevice *device;
ClutterSeatEvdev *seat;
int button_count[KEY_CNT];
};
G_DEFINE_TYPE (ClutterVirtualInputDeviceEvdev,
clutter_virtual_input_device_evdev,
CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE)
typedef enum _EvdevButtonType
{
EVDEV_BUTTON_TYPE_NONE,
EVDEV_BUTTON_TYPE_KEY,
EVDEV_BUTTON_TYPE_BUTTON,
} EvdevButtonType;
static int
update_button_count (ClutterVirtualInputDeviceEvdev *virtual_evdev,
uint32_t button,
uint32_t state)
{
if (state)
{
return ++virtual_evdev->button_count[button];
}
else
{
/* Handle cases where we newer saw the initial pressed event. */
if (virtual_evdev->button_count[button] == 0)
return 0;
return --virtual_evdev->button_count[button];
}
}
static EvdevButtonType
get_button_type (uint16_t code)
{
switch (code)
{
case BTN_TOOL_PEN:
case BTN_TOOL_RUBBER:
case BTN_TOOL_BRUSH:
case BTN_TOOL_PENCIL:
case BTN_TOOL_AIRBRUSH:
case BTN_TOOL_MOUSE:
case BTN_TOOL_LENS:
case BTN_TOOL_QUINTTAP:
case BTN_TOOL_DOUBLETAP:
case BTN_TOOL_TRIPLETAP:
case BTN_TOOL_QUADTAP:
case BTN_TOOL_FINGER:
case BTN_TOUCH:
return EVDEV_BUTTON_TYPE_NONE;
}
if (code >= KEY_ESC && code <= KEY_MICMUTE)
return EVDEV_BUTTON_TYPE_KEY;
if (code >= BTN_MISC && code <= BTN_GEAR_UP)
return EVDEV_BUTTON_TYPE_BUTTON;
if (code >= KEY_OK && code <= KEY_LIGHTS_TOGGLE)
return EVDEV_BUTTON_TYPE_KEY;
if (code >= BTN_DPAD_UP && code <= BTN_DPAD_RIGHT)
return EVDEV_BUTTON_TYPE_BUTTON;
if (code >= KEY_ALS_TOGGLE && code <= KEY_KBDINPUTASSIST_CANCEL)
return EVDEV_BUTTON_TYPE_KEY;
if (code >= BTN_TRIGGER_HAPPY && code <= BTN_TRIGGER_HAPPY40)
return EVDEV_BUTTON_TYPE_BUTTON;
return EVDEV_BUTTON_TYPE_NONE;
}
static void
release_pressed_buttons (ClutterVirtualInputDevice *virtual_device)
{
ClutterVirtualInputDeviceEvdev *virtual_evdev =
CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
int code;
uint64_t time_us;
time_us = g_get_monotonic_time ();
for (code = 0; code < G_N_ELEMENTS (virtual_evdev->button_count); code++)
{
switch (get_button_type (code))
{
case EVDEV_BUTTON_TYPE_KEY:
clutter_virtual_input_device_notify_key (virtual_device,
time_us,
code,
CLUTTER_KEY_STATE_RELEASED);
break;
case EVDEV_BUTTON_TYPE_BUTTON:
clutter_virtual_input_device_notify_button (virtual_device,
time_us,
code,
CLUTTER_BUTTON_STATE_RELEASED);
break;
case EVDEV_BUTTON_TYPE_NONE:
g_assert_not_reached ();
}
}
}
static void
clutter_virtual_input_device_evdev_notify_relative_motion (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
double dx,
double dy)
{
ClutterVirtualInputDeviceEvdev *virtual_evdev =
CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
clutter_seat_evdev_notify_relative_motion (virtual_evdev->seat,
virtual_evdev->device,
time_us,
dx, dy,
dx, dy);
}
static void
clutter_virtual_input_device_evdev_notify_absolute_motion (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
double x,
double y)
{
ClutterVirtualInputDeviceEvdev *virtual_evdev =
CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
clutter_seat_evdev_notify_absolute_motion (virtual_evdev->seat,
virtual_evdev->device,
time_us,
x, y,
NULL);
}
static void
clutter_virtual_input_device_evdev_notify_button (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t button,
ClutterButtonState button_state)
{
ClutterVirtualInputDeviceEvdev *virtual_evdev =
CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
int button_count;
if (get_button_type (button) != EVDEV_BUTTON_TYPE_BUTTON)
{
g_warning ("Unknown/invalid virtual device button 0x%x pressed",
button);
return;
}
button_count = update_button_count (virtual_evdev, button, button_state);
if (button_count > 1)
{
g_warning ("Received multiple virtual 0x%x button presses (ignoring)",
button);
return;
}
clutter_seat_evdev_notify_button (virtual_evdev->seat,
virtual_evdev->device,
time_us,
button,
button_state);
}
static void
clutter_virtual_input_device_evdev_notify_key (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t key,
ClutterKeyState key_state)
{
ClutterVirtualInputDeviceEvdev *virtual_evdev =
CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
int key_count;
if (get_button_type (key) != EVDEV_BUTTON_TYPE_KEY)
{
g_warning ("Unknown/invalid virtual device key 0x%x pressed\n", key);
return;
}
key_count = update_button_count (virtual_evdev, key, key_state);
if (key_count > 1)
{
g_warning ("Received multiple virtual 0x%x key presses (ignoring)",
key);
return;
}
clutter_seat_evdev_notify_key (virtual_evdev->seat,
virtual_evdev->device,
time_us,
key,
key_state,
TRUE);
}
static gboolean
pick_keycode_for_keyval_in_current_group (ClutterVirtualInputDevice *virtual_device,
guint keyval,
guint *keycode_out,
guint *level_out)
{
ClutterVirtualInputDeviceEvdev *virtual_evdev =
CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
ClutterDeviceManager *manager;
struct xkb_keymap *xkb_keymap;
struct xkb_state *state;
guint keycode, layout;
xkb_keycode_t min_keycode, max_keycode;
manager = clutter_virtual_input_device_get_manager (virtual_device);
xkb_keymap = _clutter_device_manager_evdev_get_keymap (CLUTTER_DEVICE_MANAGER_EVDEV (manager));
state = virtual_evdev->seat->xkb;
layout = xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE);
min_keycode = xkb_keymap_min_keycode (xkb_keymap);
max_keycode = xkb_keymap_max_keycode (xkb_keymap);
for (keycode = min_keycode; keycode < max_keycode; keycode++)
{
gint num_levels, level;
num_levels = xkb_keymap_num_levels_for_key (xkb_keymap, keycode, layout);
for (level = 0; level < num_levels; level++)
{
const xkb_keysym_t *syms;
gint num_syms, sym;
num_syms = xkb_keymap_key_get_syms_by_level (xkb_keymap, keycode, layout, level, &syms);
for (sym = 0; sym < num_syms; sym++)
{
if (syms[sym] == keyval)
{
*keycode_out = keycode;
if (level_out)
*level_out = level;
return TRUE;
}
}
}
}
return FALSE;
}
static void
apply_level_modifiers (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t level,
uint32_t key_state)
{
ClutterVirtualInputDeviceEvdev *virtual_evdev =
CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
guint keysym, keycode, evcode;
if (level == 0)
return;
if (level == 1)
{
keysym = XKB_KEY_Shift_L;
}
else if (level == 2)
{
keysym = XKB_KEY_ISO_Level3_Shift;
}
else
{
g_warning ("Unhandled level: %d\n", level);
return;
}
if (!pick_keycode_for_keyval_in_current_group (virtual_device, keysym,
&keycode, NULL))
return;
clutter_input_device_keycode_to_evdev (virtual_evdev->device,
keycode, &evcode);
clutter_seat_evdev_notify_key (virtual_evdev->seat,
virtual_evdev->device,
time_us,
evcode,
key_state,
TRUE);
}
static void
clutter_virtual_input_device_evdev_notify_keyval (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t keyval,
ClutterKeyState key_state)
{
ClutterVirtualInputDeviceEvdev *virtual_evdev =
CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (virtual_device);
int key_count;
guint keycode = 0, level = 0, evcode = 0;
if (!pick_keycode_for_keyval_in_current_group (virtual_device,
keyval, &keycode, &level))
{
g_warning ("No keycode found for keyval %x in current group", keyval);
return;
}
clutter_input_device_keycode_to_evdev (virtual_evdev->device,
keycode, &evcode);
if (get_button_type (evcode) != EVDEV_BUTTON_TYPE_KEY)
{
g_warning ("Unknown/invalid virtual device key 0x%x pressed\n", evcode);
return;
}
key_count = update_button_count (virtual_evdev, evcode, key_state);
if (key_count > 1)
{
g_warning ("Received multiple virtual 0x%x key presses (ignoring)",
keycode);
return;
}
if (key_state)
apply_level_modifiers (virtual_device, time_us, level, key_state);
clutter_seat_evdev_notify_key (virtual_evdev->seat,
virtual_evdev->device,
time_us,
evcode,
key_state,
TRUE);
if (!key_state)
apply_level_modifiers (virtual_device, time_us, level, key_state);
}
static void
clutter_virtual_input_device_evdev_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterVirtualInputDeviceEvdev *virtual_evdev =
CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (object);
switch (prop_id)
{
case PROP_SEAT:
g_value_set_pointer (value, virtual_evdev->seat);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clutter_virtual_input_device_evdev_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterVirtualInputDeviceEvdev *virtual_evdev =
CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (object);
switch (prop_id)
{
case PROP_SEAT:
virtual_evdev->seat = g_value_get_pointer (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clutter_virtual_input_device_evdev_constructed (GObject *object)
{
ClutterVirtualInputDevice *virtual_device =
CLUTTER_VIRTUAL_INPUT_DEVICE (object);
ClutterVirtualInputDeviceEvdev *virtual_evdev =
CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (object);
ClutterDeviceManager *manager;
ClutterInputDeviceType device_type;
ClutterStage *stage;
manager = clutter_virtual_input_device_get_manager (virtual_device);
device_type = clutter_virtual_input_device_get_device_type (virtual_device);
virtual_evdev->device =
_clutter_input_device_evdev_new_virtual (manager,
virtual_evdev->seat,
device_type,
CLUTTER_INPUT_MODE_SLAVE);
stage = _clutter_device_manager_evdev_get_stage (CLUTTER_DEVICE_MANAGER_EVDEV (manager));
_clutter_input_device_set_stage (virtual_evdev->device, stage);
}
static void
clutter_virtual_input_device_evdev_finalize (GObject *object)
{
ClutterVirtualInputDevice *virtual_device =
CLUTTER_VIRTUAL_INPUT_DEVICE (object);
ClutterVirtualInputDeviceEvdev *virtual_evdev =
CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV (object);
GObjectClass *object_class;
release_pressed_buttons (virtual_device);
g_clear_object (&virtual_evdev->device);
object_class =
G_OBJECT_CLASS (clutter_virtual_input_device_evdev_parent_class);
object_class->finalize (object);
}
static void
clutter_virtual_input_device_evdev_init (ClutterVirtualInputDeviceEvdev *virtual_device_evdev)
{
}
static void
clutter_virtual_input_device_evdev_class_init (ClutterVirtualInputDeviceEvdevClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterVirtualInputDeviceClass *virtual_input_device_class =
CLUTTER_VIRTUAL_INPUT_DEVICE_CLASS (klass);
object_class->get_property = clutter_virtual_input_device_evdev_get_property;
object_class->set_property = clutter_virtual_input_device_evdev_set_property;
object_class->constructed = clutter_virtual_input_device_evdev_constructed;
object_class->finalize = clutter_virtual_input_device_evdev_finalize;
virtual_input_device_class->notify_relative_motion = clutter_virtual_input_device_evdev_notify_relative_motion;
virtual_input_device_class->notify_absolute_motion = clutter_virtual_input_device_evdev_notify_absolute_motion;
virtual_input_device_class->notify_button = clutter_virtual_input_device_evdev_notify_button;
virtual_input_device_class->notify_key = clutter_virtual_input_device_evdev_notify_key;
virtual_input_device_class->notify_keyval = clutter_virtual_input_device_evdev_notify_keyval;
obj_props[PROP_SEAT] = g_param_spec_pointer ("seat",
P_("ClutterSeatEvdev"),
P_("ClutterSeatEvdev"),
CLUTTER_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, PROP_LAST, obj_props);
}

View File

@ -0,0 +1,35 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2016 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Jonas Ådahl <jadahl@gmail.com>
*/
#ifndef __CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV_H__
#define __CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV_H__
#include "clutter-virtual-input-device.h"
#define CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE_EVDEV (clutter_virtual_input_device_evdev_get_type ())
G_DECLARE_FINAL_TYPE (ClutterVirtualInputDeviceEvdev,
clutter_virtual_input_device_evdev,
CLUTTER, VIRTUAL_INPUT_DEVICE_EVDEV,
ClutterVirtualInputDevice)
#endif /* __CLUTTER_VIRTUAL_INPUT_DEVICE_EVDEV_H__ */

View File

@ -28,6 +28,7 @@
#include "clutter-backend-x11.h"
#include "clutter-input-device-core-x11.h"
#include "clutter-stage-x11.h"
#include "clutter-virtual-input-device-x11.h"
#include "clutter-backend.h"
#include "clutter-debug.h"
@ -480,6 +481,13 @@ clutter_device_manager_x11_get_device (ClutterDeviceManager *manager,
GINT_TO_POINTER (id));
}
static ClutterVirtualInputDevice *
clutter_device_manager_x11_create_virtual_device (ClutterDeviceManager *device_manager,
ClutterInputDeviceType device_type)
{
return g_object_new (CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE_X11, NULL);
}
static void
clutter_device_manager_x11_set_property (GObject *gobject,
guint prop_id,
@ -526,6 +534,7 @@ clutter_device_manager_x11_class_init (ClutterDeviceManagerX11Class *klass)
manager_class->get_devices = clutter_device_manager_x11_get_devices;
manager_class->get_core_device = clutter_device_manager_x11_get_core_device;
manager_class->get_device = clutter_device_manager_x11_get_device;
manager_class->create_virtual_device = clutter_device_manager_x11_create_virtual_device;
}
static void

View File

@ -0,0 +1,89 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2016 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Jonas Ådahl <jadahl@gmail.com>
*/
#ifdef HAVE_CONFIG_H
#include "clutter-build-config.h"
#endif
#include <glib-object.h>
#include "clutter-virtual-input-device.h"
#include "x11/clutter-virtual-input-device-x11.h"
struct _ClutterVirtualInputDeviceX11
{
ClutterVirtualInputDevice parent;
};
G_DEFINE_TYPE (ClutterVirtualInputDeviceX11,
clutter_virtual_input_device_x11,
CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE)
static void
clutter_virtual_input_device_x11_notify_relative_motion (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
double dx,
double dy)
{
}
static void
clutter_virtual_input_device_x11_notify_absolute_motion (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
double x,
double y)
{
}
static void
clutter_virtual_input_device_x11_notify_button (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t button,
ClutterButtonState button_state)
{
}
static void
clutter_virtual_input_device_x11_notify_key (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t key,
ClutterKeyState key_state)
{
}
static void
clutter_virtual_input_device_x11_init (ClutterVirtualInputDeviceX11 *virtual_device_x11)
{
}
static void
clutter_virtual_input_device_x11_class_init (ClutterVirtualInputDeviceX11Class *klass)
{
ClutterVirtualInputDeviceClass *virtual_input_device_class =
CLUTTER_VIRTUAL_INPUT_DEVICE_CLASS (klass);
virtual_input_device_class->notify_relative_motion = clutter_virtual_input_device_x11_notify_relative_motion;
virtual_input_device_class->notify_absolute_motion = clutter_virtual_input_device_x11_notify_absolute_motion;
virtual_input_device_class->notify_button = clutter_virtual_input_device_x11_notify_button;
virtual_input_device_class->notify_key = clutter_virtual_input_device_x11_notify_key;
}

View File

@ -0,0 +1,35 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2016 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Jonas Ådahl <jadahl@gmail.com>
*/
#ifndef __CLUTTER_VIRTUAL_INPUT_DEVICE_X11_H__
#define __CLUTTER_VIRTUAL_INPUT_DEVICE_X11_H__
#include "clutter-virtual-input-device.h"
#define CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE_X11 (clutter_virtual_input_device_x11_get_type ())
G_DECLARE_FINAL_TYPE (ClutterVirtualInputDeviceX11,
clutter_virtual_input_device_x11,
CLUTTER, VIRTUAL_INPUT_DEVICE_X11,
ClutterVirtualInputDevice)
#endif /* __CLUTTER_VIRTUAL_INPUT_DEVICE_X11_H__ */

View File

@ -54,6 +54,8 @@ meta_input_settings_native_set_send_events (MetaInputSettings *settings,
}
libinput_device = clutter_evdev_input_device_get_libinput_device (device);
if (!libinput_device)
return;
libinput_device_config_send_events_set_mode (libinput_device, libinput_mode);
}
@ -65,6 +67,8 @@ meta_input_settings_native_set_matrix (MetaInputSettings *settings,
struct libinput_device *libinput_device;
libinput_device = clutter_evdev_input_device_get_libinput_device (device);
if (!libinput_device)
return;
if (libinput_device_config_calibration_has_matrix (libinput_device) > 0)
libinput_device_config_calibration_set_matrix (libinput_device, matrix);
@ -78,6 +82,8 @@ meta_input_settings_native_set_speed (MetaInputSettings *settings,
struct libinput_device *libinput_device;
libinput_device = clutter_evdev_input_device_get_libinput_device (device);
if (!libinput_device)
return;
libinput_device_config_accel_set_speed (libinput_device,
CLAMP (speed, -1, 1));
}
@ -90,6 +96,8 @@ meta_input_settings_native_set_left_handed (MetaInputSettings *settings,
struct libinput_device *libinput_device;
libinput_device = clutter_evdev_input_device_get_libinput_device (device);
if (!libinput_device)
return;
if (libinput_device_config_left_handed_is_available (libinput_device))
libinput_device_config_left_handed_set (libinput_device, enabled);
@ -103,6 +111,8 @@ meta_input_settings_native_set_tap_enabled (MetaInputSettings *settings,
struct libinput_device *libinput_device;
libinput_device = clutter_evdev_input_device_get_libinput_device (device);
if (!libinput_device)
return;
if (libinput_device_config_tap_get_finger_count (libinput_device) > 0)
libinput_device_config_tap_set_enabled (libinput_device,
@ -119,6 +129,8 @@ meta_input_settings_native_set_invert_scroll (MetaInputSettings *settings,
struct libinput_device *libinput_device;
libinput_device = clutter_evdev_input_device_get_libinput_device (device);
if (!libinput_device)
return;
if (libinput_device_config_scroll_has_natural_scroll (libinput_device))
libinput_device_config_scroll_set_natural_scroll_enabled (libinput_device,
@ -163,6 +175,8 @@ meta_input_settings_native_set_edge_scroll (MetaInputSettings *settin
enum libinput_config_scroll_method supported;
libinput_device = clutter_evdev_input_device_get_libinput_device (device);
if (!libinput_device)
return;
supported = libinput_device_config_scroll_get_methods (libinput_device);
if (supported & LIBINPUT_CONFIG_SCROLL_2FG)
@ -190,6 +204,8 @@ meta_input_settings_native_set_scroll_button (MetaInputSettings *settings,
struct libinput_device *libinput_device;
libinput_device = clutter_evdev_input_device_get_libinput_device (device);
if (!libinput_device)
return;
if (!device_set_scroll_method (libinput_device,
LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN))
@ -207,6 +223,8 @@ meta_input_settings_native_set_click_method (MetaInputSettings *settin
struct libinput_device *libinput_device;
libinput_device = clutter_evdev_input_device_get_libinput_device (device);
if (!libinput_device)
return;
switch (mode)
{