From 906fa5e263945b25f15d8f39a32f95fe52a83d22 Mon Sep 17 00:00:00 2001 From: Perry Werneck Date: Thu, 12 Dec 2019 14:49:20 -0300 Subject: [PATCH] Refactoring accelerator engine to fix issues with accels. --- src/dialogs/settings/accelerator.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- src/terminal/keyboard.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------------------- src/terminal/keyboard/accelerator.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/terminal/keyboard/keyfile.c | 2 +- 4 files changed, 217 insertions(+), 60 deletions(-) diff --git a/src/dialogs/settings/accelerator.c b/src/dialogs/settings/accelerator.c index f4a2475..3b8c019 100644 --- a/src/dialogs/settings/accelerator.c +++ b/src/dialogs/settings/accelerator.c @@ -71,6 +71,12 @@ /*--[ Globals ]--------------------------------------------------------------------------------------*/ + struct KeyMap + { + guint key; + GdkModifierType mods; + }; + static void load(GtkWidget *w, GtkWidget *terminal); static void apply(GtkWidget *w, GtkWidget *terminal); @@ -198,6 +204,8 @@ struct AccelEditInfo int id_mask; }; + + static gboolean check_accel(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, struct AccelEditInfo * info) { static const gint columns[] = { MAIN_MASK, MAIN_VALUE, ALTERNATIVE_MASK, ALTERNATIVE_VALUE }; @@ -370,12 +378,6 @@ static void alternative_edited(GtkCellRendererAccel G_GNUC_UNUSED(*accel), gchar void load(GtkWidget *widget, GtkWidget *terminal) { - struct KeyMap - { - guint key; - GdkModifierType mods; - }; - debug("%s::%s","V3270AcceleratorSettings",__FUNCTION__); GtkListStore * store = GTK_V3270_ACCELERATOR_SETTINGS(widget)->store; @@ -433,8 +435,75 @@ void load(GtkWidget *widget, GtkWidget *terminal) } -void apply(GtkWidget *widget, GtkWidget *terminal) +static gboolean add_accel(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GSList **accelerators) { + static const gint columns[] = { MAIN_MASK, MAIN_VALUE, ALTERNATIVE_MASK, ALTERNATIVE_VALUE }; + size_t ix; + GValue value; + struct KeyMap keymap[2]; + + V3270Accelerator * accel; + + memset(&value,0,sizeof(value)); + gtk_tree_model_get_value(model, iter, ACTION, &value); + accel = (V3270Accelerator *) g_value_get_pointer(&value); + g_value_unset(&value); + + for(ix = 0; ix < 2; ix++) + { + guint key; + GdkModifierType mask; + + memset(&value,0,sizeof(value)); + gtk_tree_model_get_value(model, iter, columns[(ix * 2)], &value); + keymap[ix].mods = (GdkModifierType) g_value_get_int(&value); + g_value_unset(&value); + + memset(&value,0,sizeof(value)); + gtk_tree_model_get_value(model, iter, columns[(ix * 2)+1], &value); + keymap[ix].key = g_value_get_uint(&value); + g_value_unset(&value); + + } + + // Allways create the "main" accelerator to keep the action active. + V3270Accelerator * acc = v3270_accelerator_copy(accel); + acc->key = keymap[0].key; + acc->mods = keymap[0].mods; + *accelerators = g_slist_prepend(*accelerators,acc); + + // The alternative one is created only when set. + if(keymap[1].key) + { + acc = v3270_accelerator_copy(accel); + acc->key = keymap[1].key; + acc->mods = keymap[1].mods; + *accelerators = g_slist_prepend(*accelerators,acc); + } + + return FALSE; +} + +void apply(GtkWidget *s, GtkWidget *t) +{ + v3270 * terminal = GTK_V3270(t); + V3270AcceleratorSettings * settings = GTK_V3270_ACCELERATOR_SETTINGS(s); + debug("%s::%s","V3270AcceleratorSettings",__FUNCTION__); + + // Create a new accelerator table. + GSList * accelerators = NULL; + + gtk_tree_model_foreach(GTK_TREE_MODEL(settings->store), (GtkTreeModelForeachFunc) add_accel, &accelerators); + + // Replace the accelerator table. + if(terminal->accelerators) + g_slist_free_full(terminal->accelerators,g_free); + + terminal->accelerators = accelerators; + + // And sort it. + v3270_accelerator_map_sort(terminal); + } diff --git a/src/terminal/keyboard.c b/src/terminal/keyboard.c index 904b1f0..e39a652 100644 --- a/src/terminal/keyboard.c +++ b/src/terminal/keyboard.c @@ -56,43 +56,6 @@ #define GDK_NUMLOCK_MASK GDK_MOD2_MASK #endif -/*--[ Globals ]--------------------------------------------------------------------------------------*/ - - /* - static struct _keycode - { - guint keyval; - GdkModifierType state; - int (*exec)(H3270 *session); - } keycode[] = - { - { GDK_Left, 0, lib3270_cursor_left }, // OK - { GDK_Up, 0, lib3270_cursor_up }, // OK - { GDK_Right, 0, lib3270_cursor_right }, // OK - { GDK_Down, 0, lib3270_cursor_down }, // OK - { GDK_Tab, 0, lib3270_nextfield }, // OK - { GDK_ISO_Left_Tab, GDK_SHIFT_MASK, lib3270_previousfield }, // OK - { GDK_KP_Left, 0, lib3270_cursor_left }, - { GDK_KP_Up, 0, lib3270_cursor_up }, - { GDK_KP_Right, 0, lib3270_cursor_right }, - { GDK_KP_Down, 0, lib3270_cursor_down }, - - { GDK_3270_PrintScreen, 0, lib3270_print_all }, - { GDK_P, GDK_CONTROL_MASK, lib3270_print_all }, - - { GDK_Sys_Req, 0, lib3270_sysreq }, - - { GDK_Print, GDK_CONTROL_MASK, lib3270_print_all }, - { GDK_Print, GDK_SHIFT_MASK, lib3270_sysreq }, - - -//#ifdef WIN32 -// { GDK_Pause, 0, NULL }, -//#endif - - }; - */ - /*--[ Implement ]------------------------------------------------------------------------------------*/ #define keyval_is_alt() (event->keyval == GDK_Alt_L || event->keyval == GDK_Meta_L || event->keyval == GDK_ISO_Level3_Shift) @@ -121,11 +84,65 @@ } - static gboolean check_keypress(v3270 *widget, GdkEventKey *event) + static gboolean check_keypress(v3270 *widget, const GdkEventKey *event) { -// int f; - GdkModifierType state = event->state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_ALT_MASK); - gboolean handled = FALSE; + GdkKeymap * keymap = gdk_keymap_get_for_display(gtk_widget_get_display(GTK_WIDGET(widget))); + + // From gtk_accelerator_name at https://gitlab.gnome.org/GNOME/gtk/blob/master/gtk/gtkaccelgroup.c + // Side steps issue from https://mail.gnome.org/archives/gtk-app-devel-list/2007-August/msg00053.html + guint keyval = gdk_keyval_to_lower(event->keyval); + + // Add virtual modifiers to event state. + GdkModifierType state = event->state & ~GDK_RELEASE_MASK; + gdk_keymap_add_virtual_modifiers(keymap,&state); + + // Check if the application can handle the key. + gboolean handled = FALSE; + g_signal_emit( + GTK_WIDGET(widget), + v3270_widget_signal[V3270_SIGNAL_KEYPRESS], + 0, + keyval, + state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_ALT_MASK), // FIXME: Remove the reset flags after the main application update. + &handled + ); + + debug("Keyboard action was %s (keyval=%08x state=%08x)",handled ? "Handled" : "Not handled",event->keyval,event->state); + if(handled) + return TRUE; + + // + // Check for accelerator. + // + const V3270Accelerator * accel = v3270_get_accelerator(GTK_WIDGET(widget), keyval, state); + if(accel) + { + debug("%s will fire",__FUNCTION__); + v3270_accelerator_activate(accel,GTK_WIDGET(widget)); + return TRUE; + } + + // Check PFKeys + if(keyval >= GDK_F1 && keyval <= GDK_F12 && !(state & (GDK_CONTROL_MASK|GDK_ALT_MASK))) + { + int pfcode = (keyval - GDK_F1) + ((state & GDK_SHIFT_MASK) ? 13 : 1); + + debug("%s: PF%d will fire",__FUNCTION__,pfcode); + + if(pfcode > 0 && pfcode < 25) + { + lib3270_pfkey(widget->host,pfcode); + return TRUE; + } + else + { + g_warning("Invalid PFCode %d",pfcode); + } + } + + /* + gboolean handled = FALSE; + const V3270Accelerator * accel; #ifdef WIN32 // FIXME (perry#1#): Find a better way! @@ -133,35 +150,46 @@ event->keyval = GDK_Pause; // Windows sets in left/right control - else if(state & GDK_CONTROL_MASK && (event->keyval == GDK_Control_R || event->keyval == GDK_Control_L)) - state &= ~GDK_CONTROL_MASK; + else if(event->state & GDK_CONTROL_MASK && (event->keyval == GDK_Control_R || event->keyval == GDK_Control_L)) + event->state &= ~GDK_CONTROL_MASK; #endif - g_signal_emit(GTK_WIDGET(widget), v3270_widget_signal[V3270_SIGNAL_KEYPRESS], 0, event->keyval, state, &handled); + g_signal_emit( + GTK_WIDGET(widget), + v3270_widget_signal[V3270_SIGNAL_KEYPRESS], + 0, + event->keyval, + event->state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_ALT_MASK), + &handled + ); debug("Keyboard action was %s",handled ? "Handled" : "Not handled"); if(handled) return TRUE; #ifdef DEBUG { - g_autofree gchar * keyname = gtk_accelerator_name(event->keyval, state); + g_autofree gchar * keyname = gtk_accelerator_name(event->keyval, event->state); debug("Keyname: %s",keyname); } #endif // DEBUG // Check accelerator table. - const V3270Accelerator * acel = v3270_get_accelerator(GTK_WIDGET(widget), event->keyval, state); - if(acel) + accel = v3270_get_accelerator(GTK_WIDGET(widget), event->keyval, event->state); + + if(!accel) + accel = v3270_get_accelerator(GTK_WIDGET(widget), event->keyval, event->state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_ALT_MASK)); + + if(accel) { debug("%s will fire",__FUNCTION__); - v3270_accelerator_activate(acel,GTK_WIDGET(widget)); + v3270_accelerator_activate(accel,GTK_WIDGET(widget)); return TRUE; } // Check PFKeys - if(event->keyval >= GDK_F1 && event->keyval <= GDK_F12 && !(state & (GDK_CONTROL_MASK|GDK_ALT_MASK))) + if(event->keyval >= GDK_F1 && event->keyval <= GDK_F12 && !(event->state & (GDK_CONTROL_MASK|GDK_ALT_MASK))) { - int pfcode = (event->keyval - GDK_F1) + ((state & GDK_SHIFT_MASK) ? 13 : 1); + int pfcode = (event->keyval - GDK_F1) + ((event->state & GDK_SHIFT_MASK) ? 13 : 1); if(pfcode > 0 && pfcode < 25) { @@ -169,6 +197,7 @@ return TRUE; } } + */ return FALSE; } diff --git a/src/terminal/keyboard/accelerator.c b/src/terminal/keyboard/accelerator.c index 8868f1a..b1c690c 100644 --- a/src/terminal/keyboard/accelerator.c +++ b/src/terminal/keyboard/accelerator.c @@ -56,9 +56,41 @@ } - gboolean v3270_accelerator_compare(const V3270Accelerator * accell, const guint keyval, const GdkModifierType mods) + gboolean v3270_accelerator_compare(const V3270Accelerator * accel, const guint keyval, const GdkModifierType mods) { - return accell->key == keyval && accell->mods == mods; + // Problems: + + debug("%s: keys: %08x %08x",__FUNCTION__,accel->key,keyval); + + // It's the same key? + if(accel->key != keyval) + { + g_autofree gchar * acckey = gtk_accelerator_name(accel->key,accel->mods); + g_autofree gchar * qkey = gtk_accelerator_name(keyval,mods); + debug("%s: Rejected by key %08x %08x (%s %s)",__FUNCTION__,accel->key,keyval,acckey,qkey); + return FALSE; + } + + // The same key and same mods, Found it! + if(accel->mods == mods) + return TRUE; + +#ifdef DEBUG + { + g_autofree gchar * acckey = gtk_accelerator_name(accel->key,accel->mods); + g_autofree gchar * qkey = gtk_accelerator_name(keyval,mods); + debug("%s: accel=%s (%0u/%08x) query=%s (%u/%08x) xor=%08x and=%08x",__FUNCTION__,acckey,accel->key,accel->mods,qkey,keyval,mods,(accel->mods^mods),(accel->mods & mods)); + } +#endif // DEBUG + + // All of the required mods is "ON"? + if(accel->mods != (mods & accel->mods)) + { + debug("%s: Rejected %08x %08x",__FUNCTION__,accel->mods,(mods & accel->mods)); + return FALSE; + } + + return TRUE; } void v3270_accelerator_activate(const V3270Accelerator * acel, GtkWidget *terminal) @@ -80,6 +112,33 @@ return (V3270Accelerator *) ix->data; } +#ifdef DEBUG + { + g_autofree gchar * keyname = gtk_accelerator_name(keyval,state); + debug("%s: Can't find accelerator for %s",__FUNCTION__,keyname); + debug("Keyval: %d (%s) State: %04x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + keyval, + gdk_keyval_name(keyval), + state, + state & GDK_SHIFT_MASK ? " GDK_SHIFT_MASK" : "", + state & GDK_LOCK_MASK ? " GDK_LOCK_MASK" : "", + state & GDK_CONTROL_MASK ? " GDK_CONTROL_MASK" : "", + state & GDK_MOD1_MASK ? " GDK_MOD1_MASK" : "", + state & GDK_MOD2_MASK ? " GDK_MOD2_MASK" : "", + state & GDK_MOD3_MASK ? " GDK_MOD3_MASK" : "", + state & GDK_MOD4_MASK ? " GDK_MOD4_MASK" : "", + state & GDK_MOD5_MASK ? " GDK_MOD5_MASK" : "", + state & GDK_BUTTON1_MASK ? " GDK_BUTTON1_MASK" : "", + state & GDK_BUTTON2_MASK ? " GDK_BUTTON2_MASK" : "", + state & GDK_BUTTON3_MASK ? " GDK_BUTTON3_MASK" : "", + state & GDK_BUTTON4_MASK ? " GDK_BUTTON4_MASK" : "", + state & GDK_BUTTON5_MASK ? " GDK_BUTTON5_MASK" : "", + state & GDK_RELEASE_MASK ? " GDK_RELEASE_MASK" : "", + state & GDK_MODIFIER_MASK ? " GDK_MODIFIER_MASK" : "" + ); + + } +#endif // DEBUG return NULL; } diff --git a/src/terminal/keyboard/keyfile.c b/src/terminal/keyboard/keyfile.c index 3d036b6..46b28fe 100644 --- a/src/terminal/keyboard/keyfile.c +++ b/src/terminal/keyboard/keyfile.c @@ -95,7 +95,7 @@ { V3270Accelerator * accel = NULL; - // Find accelerator by name + // Remove accelerator by name { GSList * ix = terminal->accelerators; -- libgit2 0.21.2