#include #include #include #include #include #include "generated.h" #include "shared.h" #include "rcm-client-main.h" #include "rcm-client-advanced.h" struct state { GList *header_buttons; }; static struct state state; static GVariant * encode_nec(uint32_t scancode_raw) { GVariantBuilder *builder; GVariant *r; unsigned i; uint32_t scancode; scancode = ((((scancode_raw >> 24) & 0xff) << 0) | (((scancode_raw >> 16) & 0xff) << 8) | (((scancode_raw >> 8) & 0xff) << 16) | (((scancode_raw >> 0) & 0xff) << 24)); builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY); g_variant_builder_add(builder, "u", 9000); g_variant_builder_add(builder, "u", 4500); for (i = 0; i < 32; i++) { g_variant_builder_add(builder, "u", 560); if (scancode & 0x1) g_variant_builder_add(builder, "u", 3 * 560); else g_variant_builder_add(builder, "u", 1 * 560); scancode >>= 1; } g_variant_builder_add(builder, "u", 560); r = g_variant_builder_end(builder); g_variant_builder_unref(builder); return r; } void advanced_receive_event(const gchar *event) { GtkTextView *textview = GTK_TEXT_VIEW(get_object("advanced_receive_textview")); GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview); GtkTextIter iter; gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert(buffer, &iter, event, -1); } static void advanced_receive_clear_cb(GtkButton *button, gpointer user_data) { GtkTextView *textview = GTK_TEXT_VIEW(get_object("advanced_receive_textview")); GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview); GtkTextIter si, ei; gtk_text_buffer_get_start_iter(buffer, &si); gtk_text_buffer_get_end_iter(buffer, &ei); gtk_text_buffer_delete(buffer, &si, &ei); } static void advanced_transmit_cb(GtkButton *button, gpointer user_data) { RCDevice *object = user_data; GtkComboBoxText *protocolw; GtkEntry *scancodew; gchar *protocol; const gchar *scancode; uint64_t sc; GError *error = NULL; gboolean r; protocolw = GTK_COMBO_BOX_TEXT(get_object("advanced_transmit_protocol")); scancodew = GTK_ENTRY(get_object("advanced_transmit_scancode")); protocol = gtk_combo_box_text_get_active_text(protocolw); scancode = gtk_entry_get_text(scancodew); printf("Asked to transmit: protocol %s scancode %s\n", protocol, scancode); g_free(protocol); if (!strcmp(protocol, "NEC")) { printf("Unsupported protocol: %s\n", protocol); return; } r = strtoull_strict(scancode, &sc); if (r < 0 || sc > UINT32_MAX) { printf("Invalid scancode: %s\n", scancode); return; } if (!rcdevice_call_transmit_sync(object, encode_nec(sc), NULL, &error)) { printf("rcdevice_call_transmit_sync failed: %s\n", error ? error->message : "no error reported"); g_error_free(error); } } static void local_create_header_button(const gchar *tooltip, const gchar *icon_name, gboolean end, GCallback callback, gpointer user_data) { GtkHeaderBar *header = GTK_HEADER_BAR(get_object("advanced_headerbar")); GtkWidget *button; button = create_header_button(header, tooltip, icon_name, end, callback, user_data); state.header_buttons = g_list_prepend(state.header_buttons, button); } static void remove_header_buttons(void) { GList *l; for (l = state.header_buttons; l; l = l->next) gtk_widget_destroy(l->data); g_list_free(state.header_buttons); state.header_buttons = NULL; } static void advanced_show_main_cb(GtkButton *button, gpointer user_data) { GtkStack *stack; remove_header_buttons(); stack = GTK_STACK(get_object("advanced_stack")); gtk_stack_set_visible_child_name(stack, "advanced_main_page"); } static void advanced_show_receive_cb(GtkButton *button, gpointer user_data) { RCDevice *object = user_data; GtkStack *stack; stack = GTK_STACK(get_object("advanced_stack")); gtk_stack_set_visible_child_name(stack, "advanced_receive_page"); g_signal_replace_id("advanced_receive_clear", "clicked", G_CALLBACK(advanced_receive_clear_cb), object); local_create_header_button("Return to advanced menu", "go-previous-symbolic", false, G_CALLBACK(advanced_show_main_cb), NULL); } static void advanced_show_transmit_cb(GtkButton *button, gpointer user_data) { RCDevice *object = user_data; GtkStack *stack; stack = GTK_STACK(get_object("advanced_stack")); gtk_stack_set_visible_child_name(stack, "advanced_transmit_page"); g_signal_replace_id("advanced_transmit_button", "clicked", G_CALLBACK(advanced_transmit_cb), object); local_create_header_button("Return to advanced menu", "go-previous-symbolic", false, G_CALLBACK(advanced_show_main_cb), NULL); } static void advanced_show_keymap_cb(GtkButton *button, gpointer user_data); static void advanced_keymap_remove_cb(GtkButton *button, gpointer user_data) { RCDevice *object = user_data; GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; gchar *protocol; guint64 scancode; gchar *keycode; GVariantBuilder builder; selection = GTK_TREE_SELECTION(get_object("advanced_keymap_treeselection")); if (!gtk_tree_selection_get_selected(selection, &model, &iter)) return; gtk_tree_model_get(model, &iter, 0, &protocol, 1, &scancode, 2, &keycode, -1); printf("Row to be deleted: %s:%lux:%s\n", protocol, scancode, keycode); g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); g_variant_builder_open(&builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add(&builder, "{sv}", "protocol", g_variant_new_string(protocol)); g_variant_builder_add(&builder, "{sv}", "scancode", g_variant_new_uint64(scancode)); g_variant_builder_add(&builder, "{sv}", "keycode", g_variant_new_string("KEY_RESERVED")); g_variant_builder_close(&builder); if (!rcdevice_call_set_kernel_mappings_sync(object, g_variant_builder_end(&builder), NULL, NULL)) return; advanced_show_keymap_cb(NULL, object); } static void advanced_keymap_row_selected_cb(GtkTreeSelection *selection, gpointer user_data) { GtkTreeModel *model; GtkTreeIter iter; GtkWidget *remove; remove = GTK_WIDGET(get_object("advanced_keymap_remove")); if (gtk_tree_selection_get_selected(selection, &model, &iter)) { g_signal_replace(remove, "clicked", G_CALLBACK(advanced_keymap_remove_cb), user_data); gtk_widget_set_sensitive(remove, true); } else gtk_widget_set_sensitive(remove, false); } static void advanced_keymap_add_cb(GtkButton *button, gpointer user_data) { RCDevice *object = user_data; GtkWidget *dialog; gchar *protocol; const char *scanstr; guint64 scancode; gchar *keycode; GVariantBuilder builder; int r; dialog = GTK_WIDGET(get_object("advanced_add")); gtk_widget_show_all(dialog); r = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_hide(dialog); if (r != 1) return; scanstr = gtk_entry_get_text(GTK_ENTRY(get_object("advanced_add_scancode"))); r = strtoull_strict(scanstr, &scancode); if (r < 0) return; protocol = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(get_object("advanced_add_protocol"))); keycode = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(get_object("advanced_add_keycode"))); g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); g_variant_builder_open(&builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add(&builder, "{sv}", "protocol", g_variant_new_string(protocol)); g_variant_builder_add(&builder, "{sv}", "scancode", g_variant_new_uint64(scancode)); g_variant_builder_add(&builder, "{sv}", "keycode", g_variant_new_string(keycode)); g_variant_builder_close(&builder); g_free(protocol); g_free(keycode); if (!rcdevice_call_set_kernel_mappings_sync(object, g_variant_builder_end(&builder), NULL, NULL)) return; advanced_show_keymap_cb(NULL, object); } static void advanced_show_keymap_cb(GtkButton *button, gpointer user_data) { RCDevice *object = user_data; GtkListStore *store; GVariant *keymap_entries = NULL; GtkStack *stack; g_signal_replace_id("advanced_keymap_treeselection", "changed", G_CALLBACK(advanced_keymap_row_selected_cb), object); g_signal_replace_id("advanced_keymap_add", "clicked", G_CALLBACK(advanced_keymap_add_cb), object); g_signal_replace_id("advanced_keymap_refresh", "clicked", G_CALLBACK(advanced_show_keymap_cb), object); store = GTK_LIST_STORE(get_object("advanced_keymap_liststore")); gtk_list_store_clear(store); rcdevice_call_get_kernel_mappings_sync(object, &keymap_entries, NULL, NULL); g_assert(g_variant_is_of_type(keymap_entries, G_VARIANT_TYPE("aa{sv}"))); GVariantIter iter; gsize n_items; GVariant *item; n_items = g_variant_iter_init(&iter, keymap_entries); g_print("Keymap items: %zu\n", n_items); while (g_variant_iter_loop (&iter, "@a{sv}", &item)) { gchar *protocol; guint64 scancode; gchar *keycode; GtkTreeIter iter; g_variant_lookup(item, "protocol", "s", &protocol); g_variant_lookup(item, "scancode", "t", &scancode); g_variant_lookup(item, "keycode", "s", &keycode); gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, 0, protocol, 1, scancode, 2, keycode, -1); } g_variant_unref(keymap_entries); stack = GTK_STACK(get_object("advanced_stack")); gtk_stack_set_visible_child_name(stack, "advanced_keymap_page"); remove_header_buttons(); local_create_header_button("Return to advanced menu", "go-previous-symbolic", false, G_CALLBACK(advanced_show_main_cb), NULL); } static void render_cell_as_hexadecimal(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer user_data) { guint64 val; gchar *text; gtk_tree_model_get(tree_model, iter, 1, &val, -1); if (val > UINT32_MAX) text = g_strdup_printf("0x%016" PRIX64, val); else text = g_strdup_printf("0x%08" PRIX64, val); g_object_set(cell, "text", text, NULL); g_free (text); } void advanced_init_ui(RCDevice *object) { GtkWidget *title; gchar *titlestr; GtkWidget *dialog; title = GTK_WIDGET(get_object("advanced_main_title_label")); titlestr = g_markup_printf_escaped("Advanced Actions\nFor device %s", rcdevice_get_sys_name(object)); gtk_label_set_markup(GTK_LABEL(title), titlestr); g_free(titlestr); g_signal_replace_id("advanced_main_transmit", "clicked", G_CALLBACK(advanced_show_transmit_cb), object); g_signal_replace_id("advanced_main_receive", "clicked", G_CALLBACK(advanced_show_receive_cb), object); g_signal_replace_id("advanced_main_keymap", "clicked", G_CALLBACK(advanced_show_keymap_cb), object); gtk_tree_view_column_set_cell_data_func(GTK_TREE_VIEW_COLUMN(get_object("advanced_keymap_treecol_scancode")), GTK_CELL_RENDERER(get_object("advanced_keymap_treecell_scancode")), render_cell_as_hexadecimal, NULL, NULL); cbox_add_all_protocols(GTK_COMBO_BOX_TEXT(get_object("advanced_transmit_protocol"))); cbox_add_all_protocols(GTK_COMBO_BOX_TEXT(get_object("advanced_add_protocol"))); cbox_add_all_keycodes(GTK_COMBO_BOX_TEXT(get_object("advanced_add_keycode"))); dialog = GTK_WIDGET(get_object("advanced")); g_signal_replace_swapped(dialog, "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), dialog); advanced_show_main_cb(NULL, NULL); gtk_widget_show(dialog); }