evdev: implement setting leds

When the leds are changed in the keyboard state, propagate the
change to the actual devices.

https://bugzilla.gnome.org/show_bug.cgi?id=706494
This commit is contained in:
Giovanni Campagna 2013-09-06 16:56:55 +02:00
parent cd1749a2a5
commit d882366d11
3 changed files with 84 additions and 76 deletions

View File

@ -84,6 +84,9 @@ struct _ClutterDeviceManagerEvdevPrivate
GArray *keys; GArray *keys;
struct xkb_state *xkb; /* XKB state object */ struct xkb_state *xkb; /* XKB state object */
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; uint32_t button_state;
}; };
@ -189,6 +192,30 @@ remove_key (GArray *keys,
} }
} }
static void
sync_leds (ClutterDeviceManagerEvdev *manager_evdev)
{
ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv;
GSList *iter;
int caps_lock, num_lock, scroll_lock;
caps_lock = xkb_state_led_index_is_active (priv->xkb, priv->caps_lock_led);
num_lock = xkb_state_led_index_is_active (priv->xkb, priv->num_lock_led);
scroll_lock = xkb_state_led_index_is_active (priv->xkb, priv->scroll_lock_led);
for (iter = priv->event_sources; iter; iter = iter->next)
{
ClutterEventSource *source = iter->data;
if (libevdev_has_event_type (source->dev, EV_LED))
libevdev_kernel_set_led_values (source->dev,
LED_CAPSL, caps_lock == 1 ? LIBEVDEV_LED_ON : LIBEVDEV_LED_OFF,
LED_NUML, num_lock == 1 ? LIBEVDEV_LED_ON : LIBEVDEV_LED_OFF,
LED_SCROLLL, scroll_lock == 1 ? LIBEVDEV_LED_ON : LIBEVDEV_LED_OFF,
-1);
}
}
static void static void
notify_key_device (ClutterInputDevice *input_device, notify_key_device (ClutterInputDevice *input_device,
guint32 time_, guint32 time_,
@ -199,6 +226,7 @@ notify_key_device (ClutterInputDevice *input_device,
ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManagerEvdev *manager_evdev;
ClutterStage *stage; ClutterStage *stage;
ClutterEvent *event = NULL; ClutterEvent *event = NULL;
enum xkb_state_component changed_state;
/* We can drop the event on the floor if no stage has been /* We can drop the event on the floor if no stage has been
* associated with the device yet. */ * associated with the device yet. */
@ -208,11 +236,7 @@ notify_key_device (ClutterInputDevice *input_device,
manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (input_device->device_manager); manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (input_device->device_manager);
/* if we have keyboard state, use it to generate the event */ event = _clutter_key_event_new_from_evdev (input_device,
if (manager_evdev->priv->xkb)
{
event =
_clutter_key_event_new_from_evdev (input_device,
manager_evdev->priv->core_keyboard, manager_evdev->priv->core_keyboard,
stage, stage,
manager_evdev->priv->xkb, manager_evdev->priv->xkb,
@ -223,7 +247,7 @@ notify_key_device (ClutterInputDevice *input_device,
confused and locks the modifiers */ confused and locks the modifiers */
if (state != AUTOREPEAT_VALUE) if (state != AUTOREPEAT_VALUE)
{ {
xkb_state_update_key (manager_evdev->priv->xkb, event->key.hardware_keycode, state ? XKB_KEY_DOWN : XKB_KEY_UP); changed_state = xkb_state_update_key (manager_evdev->priv->xkb, event->key.hardware_keycode, state ? XKB_KEY_DOWN : XKB_KEY_UP);
if (update_keys) if (update_keys)
{ {
@ -233,9 +257,13 @@ notify_key_device (ClutterInputDevice *input_device,
remove_key (manager_evdev->priv->keys, event->key.hardware_keycode); remove_key (manager_evdev->priv->keys, event->key.hardware_keycode);
} }
} }
else
changed_state = 0;
queue_event (event); queue_event (event);
}
if (update_keys && (changed_state & XKB_STATE_LEDS))
sync_leds (manager_evdev);
} }
static void static void
@ -649,7 +677,7 @@ clutter_event_source_new (ClutterInputDeviceEvdev *input_device)
if (open_callback) if (open_callback)
{ {
error = NULL; error = NULL;
fd = open_callback (node_path, O_RDONLY | O_NONBLOCK, open_callback_data, &error); fd = open_callback (node_path, O_RDWR | O_NONBLOCK, open_callback_data, &error);
if (fd < 0) if (fd < 0)
{ {
@ -660,7 +688,7 @@ clutter_event_source_new (ClutterInputDeviceEvdev *input_device)
} }
else else
{ {
fd = open (node_path, O_RDONLY | O_NONBLOCK); fd = open (node_path, O_RDWR | O_NONBLOCK);
if (fd < 0) if (fd < 0)
{ {
g_warning ("Could not open device %s: %s", node_path, strerror (errno)); g_warning ("Could not open device %s: %s", node_path, strerror (errno));
@ -1016,6 +1044,9 @@ clutter_device_manager_evdev_constructed (GObject *gobject)
ClutterDeviceManagerEvdev *manager_evdev; ClutterDeviceManagerEvdev *manager_evdev;
ClutterDeviceManagerEvdevPrivate *priv; ClutterDeviceManagerEvdevPrivate *priv;
ClutterInputDevice *device; ClutterInputDevice *device;
struct xkb_context *ctx;
struct xkb_keymap *keymap;
struct xkb_rule_names names;
manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (gobject); manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (gobject);
priv = manager_evdev->priv; priv = manager_evdev->priv;
@ -1045,10 +1076,28 @@ clutter_device_manager_evdev_constructed (GObject *gobject)
priv->core_keyboard = device; priv->core_keyboard = device;
priv->keys = g_array_new (FALSE, FALSE, sizeof (guint32)); priv->keys = g_array_new (FALSE, FALSE, sizeof (guint32));
priv->xkb = _clutter_xkb_state_new (NULL,
option_xkb_layout, ctx = xkb_context_new(0);
option_xkb_variant, g_assert (ctx);
option_xkb_options);
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)
{
priv->xkb = xkb_state_new (keymap);
priv->caps_lock_led = xkb_keymap_led_get_index (keymap, XKB_LED_NAME_CAPS);
priv->num_lock_led = xkb_keymap_led_get_index (keymap, XKB_LED_NAME_NUM);
priv->scroll_lock_led = xkb_keymap_led_get_index (keymap, XKB_LED_NAME_SCROLL);
xkb_keymap_unref (keymap);
}
priv->udev_client = g_udev_client_new (subsystems); priv->udev_client = g_udev_client_new (subsystems);
@ -1450,8 +1499,14 @@ clutter_evdev_set_keyboard_map (ClutterDeviceManager *evdev,
xkb_state_unref (priv->xkb); xkb_state_unref (priv->xkb);
priv->xkb = xkb_state_new (keymap); priv->xkb = xkb_state_new (keymap);
priv->caps_lock_led = xkb_keymap_led_get_index (keymap, XKB_LED_NAME_CAPS);
priv->num_lock_led = xkb_keymap_led_get_index (keymap, XKB_LED_NAME_NUM);
priv->scroll_lock_led = xkb_keymap_led_get_index (keymap, XKB_LED_NAME_SCROLL);
for (i = 0; i < priv->keys->len; i++) for (i = 0; i < priv->keys->len; i++)
xkb_state_update_key (priv->xkb, g_array_index (priv->keys, guint32, i), XKB_KEY_DOWN); xkb_state_update_key (priv->xkb, g_array_index (priv->keys, guint32, i), XKB_KEY_DOWN);
sync_leds (manager_evdev);
} }
/** /**

View File

@ -99,49 +99,6 @@ _clutter_key_event_new_from_evdev (ClutterInputDevice *device,
return event; return event;
} }
/*
* _clutter_xkb_state_new:
*
* Create a new xkbcommon keymap and state object.
*
* FIXME: We need a way to override the layout here, a fixed or runtime
* detected layout is provided by the backend calling _clutter_xkb_state_new();
*/
struct xkb_state *
_clutter_xkb_state_new (const gchar *model,
const gchar *layout,
const gchar *variant,
const gchar *options)
{
struct xkb_context *ctx;
struct xkb_keymap *keymap;
struct xkb_state *state;
struct xkb_rule_names names;
ctx = xkb_context_new(0);
if (!ctx)
return NULL;
names.rules = "evdev";
if (model)
names.model = model;
else
names.model = "pc105";
names.layout = layout;
names.variant = variant;
names.options = options;
keymap = xkb_map_new_from_names(ctx, &names, 0);
xkb_context_unref(ctx);
if (!keymap)
return NULL;
state = xkb_state_new(keymap);
xkb_map_unref(keymap);
return state;
}
void void
_clutter_xkb_translate_state (ClutterEvent *event, _clutter_xkb_translate_state (ClutterEvent *event,
struct xkb_state *state, struct xkb_state *state,

View File

@ -39,10 +39,6 @@ ClutterEvent * _clutter_key_event_new_from_evdev (ClutterInputDevice *device,
uint32_t _time, uint32_t _time,
uint32_t key, uint32_t key,
uint32_t state); uint32_t state);
struct xkb_state * _clutter_xkb_state_new (const gchar *model,
const gchar *layout,
const gchar *variant,
const gchar *options);
void _clutter_xkb_translate_state (ClutterEvent *event, void _clutter_xkb_translate_state (ClutterEvent *event,
struct xkb_state *xkb_state, struct xkb_state *xkb_state,
uint32_t button_state); uint32_t button_state);