summaryrefslogtreecommitdiff
path: root/rcm-server-main.c
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2015-08-19 20:56:38 +0200
committerDavid Härdeman <david@hardeman.nu>2015-08-19 20:56:38 +0200
commit09c3b53ad8795e050b72277968fd50591bbb3a7f (patch)
treed83bcf26ec55ce585de3a86dd95bd17fe9861e4a /rcm-server-main.c
parentf3f7d5445e6f64a7c946f6e0144452952f0809e8 (diff)
Add support for editing in-kernel keymap
Diffstat (limited to 'rcm-server-main.c')
-rw-r--r--rcm-server-main.c390
1 files changed, 262 insertions, 128 deletions
diff --git a/rcm-server-main.c b/rcm-server-main.c
index 4d23f89..d4b41fe 100644
--- a/rcm-server-main.c
+++ b/rcm-server-main.c
@@ -61,6 +61,261 @@ property_get(sd_bus *bus, const char *path, const char *interface,
return -EINVAL;
}
+static int
+sdbus_get_psk_triplet(sd_bus_message *m, unsigned *ret_protocol,
+ uint64_t *ret_scancode, struct linux_input_keycode **ret_keycode)
+{
+ const char *protocol = NULL;
+ unsigned protocol_numeric;
+ uint64_t scancode;
+ bool scancode_found = false;
+ struct linux_input_keycode *lik = NULL;
+ const char *keycode = NULL;
+ unsigned i;
+ int r;
+
+ r = sd_bus_message_enter_container(m, 'a', "{sv}");
+ if (r < 1)
+ return r;
+
+ while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
+ const char *name;
+ const char *contents;
+ char type;
+
+ r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_peek_type(m, NULL, &contents);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_peek_type(m, &type, &contents);
+ if (r < 0)
+ return r;
+
+ if (!strcmp(name, "protocol")) {
+ if (type != SD_BUS_TYPE_STRING) {
+ printf("Invalid type for protocol (%c)\n", type);
+ return -EINVAL;
+ }
+
+ if (protocol) {
+ printf("Protocol specified more than once\n");
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_read_basic(m, type, &protocol);
+ if (r < 0)
+ return r;
+
+ for (i = 0; rc_protocols[i]; i++) {
+ if (!strcmp(rc_protocols[i], protocol))
+ break;
+ }
+
+ if (!rc_protocols[i]) {
+ printf("Invalid protocol name (%s)\n", protocol);
+ return -EINVAL;
+ }
+
+ protocol_numeric = i;
+
+ } else if (!strcmp(name, "scancode")) {
+ if (type != SD_BUS_TYPE_UINT64) {
+ printf("Invalid type for scancode (%c)\n", type);
+ return -EINVAL;
+ }
+
+ if (scancode_found) {
+ printf("Scancode specified more than once\n");
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_read_basic(m, type, &scancode);
+ if (r < 0)
+ return r;
+
+ scancode_found = true;
+
+ } else if (!strcmp(name, "keycode")) {
+ if (type != SD_BUS_TYPE_STRING) {
+ printf("Invalid type for keycode (%c)\n", type);
+ return -EINVAL;
+ }
+
+ if (keycode) {
+ printf("Keycode specified more than once\n");
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_read_basic(m, type, &keycode);
+ if (r < 0)
+ return r;
+
+ if (strcmp(keycode, "KEY_RESERVED")) {
+ lik = get_linux_keycode_by_name(keycode);
+ if (!lik) {
+ printf("Invalid keycode name (%s)\n", keycode);
+ return -EINVAL;
+ }
+ }
+
+ } else {
+ r = sd_bus_message_skip(m, contents);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ return r;
+ }
+
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ return r;
+
+ if (!protocol) {
+ printf("Protocol missing\n");
+ return -EINVAL;
+ }
+
+ if (!scancode_found) {
+ printf("Scancode missing\n");
+ return -EINVAL;
+ }
+
+ if (!keycode) {
+ printf("Keycode missing\n");
+ return -EINVAL;
+ }
+
+ *ret_protocol = protocol_numeric;
+ *ret_scancode = scancode;
+ *ret_keycode = lik;
+ return 1;
+}
+
+static int
+method_getkernelmappings(sd_bus_message *m, void *userdata, sd_bus_error *error)
+{
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ struct manager *mgr = userdata;
+ struct device *dev;
+ unsigned protocol_numeric;
+ uint64_t scancode;
+ struct linux_input_keycode *lik;
+ unsigned i = 0;
+ int r;
+
+ dev = find_device_by_path(mgr, sd_bus_message_get_path(m));
+ if (!dev) {
+ sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device");
+ return -EINVAL;
+ }
+
+ if (dev->evdev_fd < 0) {
+ sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.EvdevError", "Evdev device not available");
+ r = -EINVAL;
+ goto out;
+ }
+
+ r = sd_bus_message_new_method_return(m, &reply);
+ if (r < 0)
+ goto out;
+
+ r = sd_bus_message_open_container(reply, 'a', "a{sv}");
+ if (r < 0)
+ goto out;
+
+ while ((r = evdev_get_mapping(dev, i, &protocol_numeric, &scancode, &lik)) > 0) {
+ r = sd_bus_message_append(reply, "a{sv}", 3,
+ "protocol", "s", rc_protocols[protocol_numeric],
+ "scancode", "t", scancode,
+ "keycode", "s", lik->name);
+ if (r < 0)
+ goto out;
+
+ i++;
+ }
+
+ if (r < 0)
+ goto out;
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ goto out;
+
+ r = sd_bus_send(NULL, reply, NULL);
+ if (r < 0)
+ goto out;
+
+ return 1;
+
+out:
+ return sd_bus_error_set_errno(error, r);
+}
+
+static int
+method_setkernelmappings(sd_bus_message *m, void *userdata, sd_bus_error *error)
+{
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ struct manager *mgr = userdata;
+ struct device *dev;
+ unsigned protocol;
+ uint64_t scancode;
+ struct linux_input_keycode *keycode;
+ int r;
+
+ dev = find_device_by_path(mgr, sd_bus_message_get_path(m));
+ if (!dev) {
+ sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device");
+ r = -EINVAL;
+ goto out;
+ }
+
+ if (dev->evdev_fd < 0) {
+ sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.EvdevError", "Evdev device not available");
+ r = -EINVAL;
+ goto out;
+ }
+
+ r = sd_bus_message_enter_container(m, 'a', "a{sv}");
+ if (r < 0)
+ goto out;
+
+ while ((r = sdbus_get_psk_triplet(m, &protocol, &scancode, &keycode)) > 0) {
+ printf("%s kernel mapping %s:0x%08lx:%s\n",
+ keycode ? "Setting" : "Unsetting", rc_protocols[protocol],
+ scancode, keycode ? keycode->name : "<na>");
+ evdev_set_mapping(dev, protocol, scancode, keycode);
+ }
+
+ if (r < 0)
+ goto out;
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ goto out;
+
+ return sd_bus_reply_method_return(m, NULL);
+
+out:
+ return sd_bus_error_set_errno(error, r);
+}
static int
method_listkeymaps(sd_bus_message *m, void *userdata, sd_bus_error *error)
@@ -212,6 +467,9 @@ method_setkeymap_parse_dbus_msg(sd_bus_message *m, struct keymap *keymap,
const char *id;
const char *name;
const char *description;
+ unsigned protocol;
+ uint64_t scancode;
+ struct linux_input_keycode *lik;
uint16_t cols, rows;
unsigned keycode_count = 0;
unsigned layout_count = 0;
@@ -268,145 +526,19 @@ method_setkeymap_parse_dbus_msg(sd_bus_message *m, struct keymap *keymap,
if (r < 0)
return r;
- while ((r = sd_bus_message_enter_container(m, 'a', "{sv}")) > 0) {
- const char *protocol = NULL;
- unsigned protocol_numeric;
- uint64_t scancode;
- bool scancode_found = false;
- struct linux_input_keycode *lik = NULL;
- const char *keycode;
- unsigned i;
-
- while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
- const char *name;
- const char *contents;
- char type;
-
- r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name);
- if (r < 0)
- return r;
-
- r = sd_bus_message_peek_type(m, NULL, &contents);
- if (r < 0)
- return r;
-
- r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
- if (r < 0)
- return r;
-
- r = sd_bus_message_peek_type(m, &type, &contents);
- if (r < 0)
- return r;
-
- if (!strcmp(name, "protocol")) {
- if (type != SD_BUS_TYPE_STRING) {
- printf("Invalid type for protocol (%c)\n", type);
- return -EINVAL;
- }
-
- if (protocol) {
- printf("Protocol specified more than once\n");
- return -EINVAL;
- }
-
- r = sd_bus_message_read_basic(m, type, &protocol);
- if (r < 0)
- return r;
-
- for (i = 0; rc_protocols[i]; i++) {
- if (!strcmp(rc_protocols[i], protocol))
- break;
- }
-
- if (!rc_protocols[i]) {
- printf("Invalid protocol name (%s)\n", protocol);
- return -EINVAL;
- }
-
- protocol_numeric = i;
-
- } else if (!strcmp(name, "scancode")) {
- if (type != SD_BUS_TYPE_UINT64) {
- printf("Invalid type for scancode (%c)\n", type);
- return -EINVAL;
- }
-
- if (scancode_found) {
- printf("Scancode specified more than once\n");
- return -EINVAL;
- }
-
- r = sd_bus_message_read_basic(m, type, &scancode);
- if (r < 0)
- return r;
-
- scancode_found = true;
-
- } else if (!strcmp(name, "keycode")) {
- if (type != SD_BUS_TYPE_STRING) {
- printf("Invalid type for keycode (%c)\n", type);
- return -EINVAL;
- }
-
- if (lik) {
- printf("Keycode specified more than once\n");
- return -EINVAL;
- }
-
- r = sd_bus_message_read_basic(m, type, &keycode);
- if (r < 0)
- return r;
-
- lik = get_linux_keycode_by_name(keycode);
- if (!lik) {
- printf("Invalid keycode name (%s)\n", keycode);
- return -EINVAL;
- }
-
- } else {
- r = sd_bus_message_skip(m, contents);
- if (r < 0)
- return r;
- }
-
- r = sd_bus_message_exit_container(m);
- if (r < 0)
- return r;
-
- r = sd_bus_message_exit_container(m);
- if (r < 0)
- return r;
- }
-
- if (r < 0)
- return r;
-
- if (!protocol) {
- printf("Keycode entry without protocol\n");
- return -EINVAL;
- }
-
- if (!scancode_found) {
- printf("Keycode entry without scancode\n");
- return -EINVAL;
- }
-
+ while ((r = sdbus_get_psk_triplet(m, &protocol, &scancode, &lik)) > 0) {
if (!lik) {
printf("Keycode entry without keycode\n");
return -EINVAL;
}
if (keymap) {
- keymap->keycodes[keycode_count].protocol = protocol_numeric;
+ keymap->keycodes[keycode_count].protocol = protocol;
keymap->keycodes[keycode_count].scancode = scancode;
keymap->keycodes[keycode_count].lik = lik;
}
keycode_count++;
-
- r = sd_bus_message_exit_container(m);
- if (r < 0)
- return r;
}
if (r < 0)
@@ -709,6 +841,8 @@ static const sd_bus_vtable device_vtable[] = {
SD_BUS_PROPERTY("KernelKeymapName", "s", property_get, 0, 0),
SD_BUS_PROPERTY("HardwareType", "s", property_get, 0, 0),
SD_BUS_PROPERTY("Error", "s", property_get, 0, 0),
+ SD_BUS_METHOD("GetKernelMappings", NULL, "aa{sv}", method_getkernelmappings, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetKernelMappings", "aa{sv}", NULL, method_setkernelmappings, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ListKeymaps", NULL, "as", method_listkeymaps, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetKeymap", "s", "ssqqaa{sv}aa{sv}", method_getkeymap, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetKeymap", "sssqqaa{sv}aa{sv}", NULL, method_setkeymap, SD_BUS_VTABLE_UNPRIVILEGED),