From 17d201747727157b63aaaa956071f10e35ad9942 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sat, 18 Jul 2015 13:20:48 +0200 Subject: Add a method to set (update) a keymap/layout --- RemoteControlManager.xml | 9 ++ rcm-client-receive.c | 69 +++++++++++++- rcm-server-main.c | 240 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 315 insertions(+), 3 deletions(-) diff --git a/RemoteControlManager.xml b/RemoteControlManager.xml index dc6d4d5..6577dd0 100644 --- a/RemoteControlManager.xml +++ b/RemoteControlManager.xml @@ -14,6 +14,15 @@ + + + + + + + + + diff --git a/rcm-client-receive.c b/rcm-client-receive.c index 4f21f78..9931a08 100644 --- a/rcm-client-receive.c +++ b/rcm-client-receive.c @@ -50,6 +50,7 @@ struct rcbutton { }; struct state { + RCDevice *object; GList *remotes; GList *header_buttons; bool editing; @@ -517,6 +518,65 @@ resize_layout(struct remote *remote, guint16 new_width, guint16 new_height) gtk_widget_show_all(remote->grid); } +static void +update_remote(struct remote *remote) +{ + GVariantBuilder kbuilder; + GVariantBuilder lbuilder; + GList *l; + + g_variant_builder_init(&kbuilder, G_VARIANT_TYPE("aa{sv}")); + for (l = remote->keymap; l; l = l->next) { + struct keymap_entry *ke = l->data; + + g_variant_builder_open(&kbuilder, G_VARIANT_TYPE ("a{sv}")); + + g_variant_builder_add(&kbuilder, "{sv}", "protocol", + g_variant_new_string(ke->protocol)); + + g_variant_builder_add(&kbuilder, "{sv}", "scancode", + g_variant_new_uint64(ke->scancode)); + + g_variant_builder_add(&kbuilder, "{sv}", "keycode", + g_variant_new_string(ke->keycode)); + + g_variant_builder_close(&kbuilder); + } + + g_variant_builder_init(&lbuilder, G_VARIANT_TYPE("aa{sv}")); + for (l = remote->buttons; l; l = l->next) { + struct rcbutton *rcb = l->data; + + g_variant_builder_open(&lbuilder, G_VARIANT_TYPE ("a{sv}")); + + switch (rcb->type) { + case RCBUTTON_TYPE_NORMAL: + g_variant_builder_add(&lbuilder, "{sv}", "type", + g_variant_new_string("button")); + g_variant_builder_add(&lbuilder, "{sv}", "keycode", + g_variant_new_string(rcb->name)); + break; + + case RCBUTTON_TYPE_BLANK: + g_variant_builder_add(&lbuilder, "{sv}", "type", + g_variant_new_string("blank")); + break; + + default: + g_assert_not_reached(); + } + + g_variant_builder_close(&lbuilder); + } + + rcdevice_call_set_keymap_sync(state.object, remote->id, + remote->name, remote->description, + remote->width, remote->height, + g_variant_builder_end(&kbuilder), + g_variant_builder_end(&lbuilder), + NULL, NULL); +} + static void resize_layout_dialog(GtkButton *button, gpointer user_data) { @@ -589,6 +649,8 @@ resize_layout_dialog(GtkButton *button, gpointer user_data) resize_layout(remote, width, height); + update_remote(remote); + out: gtk_widget_destroy(dialog); } @@ -856,13 +918,14 @@ void rcng_client_receive_init_ui(GDBusObject *new_hw) return; gchar **keymap_ids = NULL; - RCDevice *object = RCDEVICE(interface); - rcdevice_call_list_keymaps_sync(object, &keymap_ids, NULL, NULL); + /* FIXME: unref object */ + state.object = RCDEVICE(interface); + rcdevice_call_list_keymaps_sync(state.object, &keymap_ids, NULL, NULL); for (i = 0; keymap_ids[i]; i++) { struct remote *remote; g_print("Fetching keymap: %s\n", keymap_ids[i]); - remote = get_keymap(object, keymap_ids[i]); + remote = get_keymap(state.object, keymap_ids[i]); state.remotes = g_list_prepend(state.remotes, remote); gtk_grid_attach(GTK_GRID(rgrid), remote->widget, i, 1, 1, 1); diff --git a/rcm-server-main.c b/rcm-server-main.c index 2a3266f..266658f 100644 --- a/rcm-server-main.c +++ b/rcm-server-main.c @@ -192,6 +192,245 @@ out: return sd_bus_error_set_errno(error, r); } +static int +method_setkeymap(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; + struct keymap *keymap; + const char *id; + const char *name; + const char *description; + uint16_t cols, rows; + int r; + + dev = find_device_by_path(mgr, sd_bus_message_get_path(m)); + if (!dev) + return sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidDevice", "Sorry, invalid device"); + + r = sd_bus_message_read(m, "sssqq", &id, &name, &description, &cols, &rows); + if (r < 0) { + fprintf(stderr, "Failed to parse parameters: %s\n", strerror(-r)); + goto out; + } + + keymap = find_keymap_by_id(dev, id); + if (!keymap) + return sd_bus_error_set_const(error, "org.gnome.RemoteControlManager.InvalidKeymap", "Sorry, unknown keymap"); + + printf("Asked to update keymap\n"); + printf("\tID : %s\n", id); + printf("\tName: %s\n", name); + printf("\tDesc: %s\n", description); + printf("\tCols: %u\n", cols); + printf("\tRows: %u\n", rows); + + printf("\tKeymap:\n"); + r = sd_bus_message_enter_container(m, 'a', "a{sv}"); + if (r < 0) + goto out; + + while ((r = sd_bus_message_enter_container(m, 'a', "{sv}")) > 0) { + const char *protocol; + uint64_t scancode; + const char *keycode; + + 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) + goto out; + + r = sd_bus_message_peek_type(m, NULL, &contents); + if (r < 0) + goto out; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents); + if (r < 0) + goto out; + + r = sd_bus_message_peek_type(m, &type, &contents); + if (r < 0) + goto out; + + if (!strcmp(name, "protocol")) { + if (type != SD_BUS_TYPE_STRING) { + printf("Invalid type for protocol (%c)\n", type); + r = -EINVAL; + goto out; + } + + r = sd_bus_message_read_basic(m, type, &protocol); + if (r < 0) + goto out; + + } else if (!strcmp(name, "scancode")) { + if (type != SD_BUS_TYPE_UINT64) { + printf("Invalid type for scancode (%c)\n", type); + r = -EINVAL; + goto out; + } + + r = sd_bus_message_read_basic(m, type, &scancode); + if (r < 0) + goto out; + + } else if (!strcmp(name, "keycode")) { + if (type != SD_BUS_TYPE_STRING) { + printf("Invalid type for keycode (%c)\n", type); + r = -EINVAL; + goto out; + } + + r = sd_bus_message_read_basic(m, type, &keycode); + if (r < 0) + goto out; + + } else { + r = sd_bus_message_skip(reply, contents); + if (r < 0) + goto out; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + goto out; + + r = sd_bus_message_exit_container(m); + if (r < 0) + goto out; + } + + if (r < 0) + goto out; + + printf("\t\t%s:%" PRIx64 ":%s\n", protocol, scancode, keycode); + + r = sd_bus_message_exit_container(m); + if (r < 0) + goto out; + } + + if (r < 0) + goto out; + + r = sd_bus_message_exit_container(m); + if (r < 0) + goto out; + + printf("\tLayout:\n"); + r = sd_bus_message_enter_container(m, 'a', "a{sv}"); + if (r < 0) + goto out; + + while ((r = sd_bus_message_enter_container(m, 'a', "{sv}")) > 0) { + bool blank = false; + bool button = false; + const char *keycode = NULL; + + while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { + const char *name; + const char *contents; + const char *button_type; + char type; + + r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &name); + if (r < 0) + goto out; + + r = sd_bus_message_peek_type(m, NULL, &contents); + if (r < 0) + goto out; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents); + if (r < 0) + goto out; + + r = sd_bus_message_peek_type(m, &type, &contents); + if (r < 0) + goto out; + + if (!strcmp(name, "type")) { + if (type != SD_BUS_TYPE_STRING) { + printf("Invalid type for type (%c)\n", type); + r = -EINVAL; + goto out; + } + + r = sd_bus_message_read_basic(m, type, &button_type); + if (r < 0) + goto out; + + if (!strcasecmp(button_type, "button")) + button = true; + else if (!strcasecmp(button_type, "blank")) + blank = true; + else { + printf("Invalid button type: %s\n", button_type); + r = -EINVAL; + goto out; + } + + } else if (!strcmp(name, "keycode")) { + if (type != SD_BUS_TYPE_STRING) { + printf("Invalid type for keycode (%c)\n", type); + r = -EINVAL; + goto out; + } + + r = sd_bus_message_read_basic(m, type, &keycode); + if (r < 0) + goto out; + + } else { + r = sd_bus_message_skip(reply, contents); + if (r < 0) + goto out; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + goto out; + + r = sd_bus_message_exit_container(m); + if (r < 0) + goto out; + } + + if (r < 0) + goto out; + + if ((!blank && !button) || (blank && button) || (button && !keycode)) { + printf("Invalid layout specification\n"); + r = -EINVAL; + goto out; + } + + printf("\t\tButton: %s\n", button ? keycode : "blank"); + + r = sd_bus_message_exit_container(m); + if (r < 0) + goto out; + } + + if (r < 0) + goto out; + + r = sd_bus_message_exit_container(m); + if (r < 0) + goto out; + + /* FIXME: save the result */ + return sd_bus_reply_method_return(m, NULL); + +out: + return sd_bus_error_set_errno(error, r); +} + static const sd_bus_vtable device_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("DriverName", "s", property_get, 0, 0), @@ -199,6 +438,7 @@ static const sd_bus_vtable device_vtable[] = { SD_BUS_PROPERTY("HardwareType", "s", property_get, 0, 0), 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), SD_BUS_SIGNAL("KeyPressed", "s", 0), SD_BUS_SIGNAL("KeyReleased", "s", 0), SD_BUS_VTABLE_END -- cgit v1.2.3