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;
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;
};
@ -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
notify_key_device (ClutterInputDevice *input_device,
guint32 time_,
@ -199,6 +226,7 @@ notify_key_device (ClutterInputDevice *input_device,
ClutterDeviceManagerEvdev *manager_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. */
@ -208,34 +236,34 @@ notify_key_device (ClutterInputDevice *input_device,
manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (input_device->device_manager);
/* if we have keyboard state, use it to generate the event */
if (manager_evdev->priv->xkb)
event = _clutter_key_event_new_from_evdev (input_device,
manager_evdev->priv->core_keyboard,
stage,
manager_evdev->priv->xkb,
manager_evdev->priv->button_state,
time_, key, state);
/* We must be careful and not pass multiple releases to xkb, otherwise it gets
confused and locks the modifiers */
if (state != AUTOREPEAT_VALUE)
{
event =
_clutter_key_event_new_from_evdev (input_device,
manager_evdev->priv->core_keyboard,
stage,
manager_evdev->priv->xkb,
manager_evdev->priv->button_state,
time_, key, state);
changed_state = xkb_state_update_key (manager_evdev->priv->xkb, event->key.hardware_keycode, state ? XKB_KEY_DOWN : XKB_KEY_UP);
/* We must be careful and not pass multiple releases to xkb, otherwise it gets
confused and locks the modifiers */
if (state != AUTOREPEAT_VALUE)
if (update_keys)
{
xkb_state_update_key (manager_evdev->priv->xkb, event->key.hardware_keycode, state ? XKB_KEY_DOWN : XKB_KEY_UP);
if (update_keys)
{
if (state)
add_key (manager_evdev->priv->keys, event->key.hardware_keycode);
else
remove_key (manager_evdev->priv->keys, event->key.hardware_keycode);
}
if (state)
add_key (manager_evdev->priv->keys, event->key.hardware_keycode);
else
remove_key (manager_evdev->priv->keys, event->key.hardware_keycode);
}
queue_event (event);
}
else
changed_state = 0;
queue_event (event);
if (update_keys && (changed_state & XKB_STATE_LEDS))
sync_leds (manager_evdev);
}
static void
@ -649,7 +677,7 @@ clutter_event_source_new (ClutterInputDeviceEvdev *input_device)
if (open_callback)
{
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)
{
@ -660,7 +688,7 @@ clutter_event_source_new (ClutterInputDeviceEvdev *input_device)
}
else
{
fd = open (node_path, O_RDONLY | O_NONBLOCK);
fd = open (node_path, O_RDWR | O_NONBLOCK);
if (fd < 0)
{
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;
ClutterDeviceManagerEvdevPrivate *priv;
ClutterInputDevice *device;
struct xkb_context *ctx;
struct xkb_keymap *keymap;
struct xkb_rule_names names;
manager_evdev = CLUTTER_DEVICE_MANAGER_EVDEV (gobject);
priv = manager_evdev->priv;
@ -1045,10 +1076,28 @@ clutter_device_manager_evdev_constructed (GObject *gobject)
priv->core_keyboard = device;
priv->keys = g_array_new (FALSE, FALSE, sizeof (guint32));
priv->xkb = _clutter_xkb_state_new (NULL,
option_xkb_layout,
option_xkb_variant,
option_xkb_options);
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)
{
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);
@ -1450,8 +1499,14 @@ clutter_evdev_set_keyboard_map (ClutterDeviceManager *evdev,
xkb_state_unref (priv->xkb);
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++)
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;
}
/*
* _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
_clutter_xkb_translate_state (ClutterEvent *event,
struct xkb_state *state,

View File

@ -39,10 +39,6 @@ ClutterEvent * _clutter_key_event_new_from_evdev (ClutterInputDevice *device,
uint32_t _time,
uint32_t key,
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,
struct xkb_state *xkb_state,
uint32_t button_state);