diff options
Diffstat (limited to 'src/remmina_key_chooser.c')
-rw-r--r-- | src/remmina_key_chooser.c | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/src/remmina_key_chooser.c b/src/remmina_key_chooser.c new file mode 100644 index 0000000..69a87c7 --- /dev/null +++ b/src/remmina_key_chooser.c @@ -0,0 +1,146 @@ +/* + * Remmina - The GTK+ Remote Desktop Client + * Copyright (C) 2009-2010 Vic Lee + * Copyright (C) 2014-2015 Antenore Gatta, Fabio Castelli, Giovanni Panozzo + * Copyright (C) 2016-2023 Antenore Gatta, Giovanni Panozzo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the + * OpenSSL library under certain conditions as described in each + * individual source file, and distribute linked combinations + * including the two. + * You must obey the GNU General Public License in all respects + * for all of the code used other than OpenSSL. * If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. * If you + * do not wish to do so, delete this exception statement from your + * version. * If you delete this exception statement from all source + * files in the program, then also delete it here. + * + */ + +#include <glib/gi18n.h> +#include "remmina_key_chooser.h" +#include "remmina_public.h" +#include "remmina/remmina_trace_calls.h" + +/* Handle key-presses on the GtkEventBox */ +static gboolean remmina_key_chooser_dialog_on_key_press(GtkWidget *widget, GdkEventKey *event, RemminaKeyChooserArguments *arguments) +{ + TRACE_CALL(__func__); + if (!arguments->use_modifiers || !event->is_modifier) { + arguments->state = event->state; + arguments->keyval = gdk_keyval_to_lower(event->keyval); + gtk_dialog_response(GTK_DIALOG(gtk_widget_get_toplevel(widget)), + event->keyval == GDK_KEY_Escape ? GTK_RESPONSE_CANCEL : GTK_RESPONSE_OK); + } + return TRUE; +} + +/* User option to use key modifiers when selecting keyboard shortcuts */ +void remmina_key_chooser_dialog_set_option_modifier(GtkWidget *widget, gboolean state, RemminaKeyChooserArguments *arguments) +{ + TRACE_CALL(__func__); + gtk_switch_set_state(GTK_SWITCH(widget), state); + arguments->use_modifiers = state; +} + +/* Show a key chooser dialog and return the keyval for the selected key */ +RemminaKeyChooserArguments* remmina_key_chooser_new(GtkWindow *parent_window, gboolean use_modifiers) +{ + TRACE_CALL(__func__); + GtkBuilder *builder = remmina_public_gtk_builder_new_from_resource ("/org/remmina/Remmina/src/../data/ui/remmina_key_chooser.glade"); + GtkDialog *dialog; + RemminaKeyChooserArguments *arguments; + arguments = g_new0(RemminaKeyChooserArguments, 1); + arguments->state = 0; + arguments->use_modifiers = use_modifiers; + + /* Setup the dialog */ + dialog = GTK_DIALOG(gtk_builder_get_object(builder, "KeyChooserDialog")); + gtk_window_set_transient_for(GTK_WINDOW(dialog), parent_window); + + /* Connect the key modifier switch signal */ + g_signal_connect(gtk_builder_get_object(builder, "switch_option_key_modifier"), "state-set", + G_CALLBACK(remmina_key_chooser_dialog_set_option_modifier), arguments); + + /* Connect the GtkEventBox signal */ + g_signal_connect(gtk_builder_get_object(builder, "eventbox_key_chooser"), "key-press-event", + G_CALLBACK(remmina_key_chooser_dialog_on_key_press), arguments); + + /* Show the dialog and destroy it after the use */ + arguments->response = gtk_dialog_run(dialog); + gtk_widget_destroy(GTK_WIDGET(dialog)); + /* The delete button set the keyval 0 */ + if (arguments->response == GTK_RESPONSE_REJECT) + arguments->keyval = 0; + return arguments; +} + +/* Get the uppercase character value of a keyval */ +gchar* remmina_key_chooser_get_value(guint keyval, guint state) +{ + TRACE_CALL(__func__); + + if (!keyval) + return g_strdup(KEY_CHOOSER_NONE); + + return g_strdup_printf("%s%s%s%s%s%s%s", + (state & GDK_SHIFT_MASK) ? KEY_MODIFIER_SHIFT : "", + (state & GDK_CONTROL_MASK) ? KEY_MODIFIER_CTRL : "", + (state & GDK_MOD1_MASK) ? KEY_MODIFIER_ALT : "", + (state & GDK_SUPER_MASK) ? KEY_MODIFIER_SUPER : "", + (state & GDK_HYPER_MASK) ? KEY_MODIFIER_HYPER : "", + (state & GDK_META_MASK) ? KEY_MODIFIER_META : "", + gdk_keyval_name(gdk_keyval_to_upper(keyval))); +} + +/* Get the keyval of a (lowercase) character value */ +guint remmina_key_chooser_get_keyval(const gchar *value) +{ + TRACE_CALL(__func__); + gchar *patterns[] = + { + KEY_MODIFIER_SHIFT, + KEY_MODIFIER_CTRL, + KEY_MODIFIER_ALT, + KEY_MODIFIER_SUPER, + KEY_MODIFIER_HYPER, + KEY_MODIFIER_META, + NULL + }; + gint i; + gchar *tmpvalue; + gchar *newvalue; + guint keyval; + + if (g_strcmp0(value, KEY_CHOOSER_NONE) == 0) + return 0; + + /* Remove any modifier text before to get the keyval */ + newvalue = g_strdup(value); + for (i = 0; i < g_strv_length(patterns); i++) { + tmpvalue = remmina_public_str_replace(newvalue, patterns[i], ""); + g_free(newvalue); + newvalue = g_strdup(tmpvalue); + g_free(tmpvalue); + } + keyval = gdk_keyval_to_lower(gdk_keyval_from_name(newvalue)); + g_free(newvalue); + return keyval; +} |