Commit 906fa5e263945b25f15d8f39a32f95fe52a83d22

Authored by Perry Werneck
1 parent 43282365
Exists in master and in 1 other branch develop

Refactoring accelerator engine to fix issues with <alt><shift><control>

accels.
src/dialogs/settings/accelerator.c
... ... @@ -71,6 +71,12 @@
71 71  
72 72 /*--[ Globals ]--------------------------------------------------------------------------------------*/
73 73  
  74 + struct KeyMap
  75 + {
  76 + guint key;
  77 + GdkModifierType mods;
  78 + };
  79 +
74 80 static void load(GtkWidget *w, GtkWidget *terminal);
75 81 static void apply(GtkWidget *w, GtkWidget *terminal);
76 82  
... ... @@ -198,6 +204,8 @@ struct AccelEditInfo
198 204 int id_mask;
199 205 };
200 206  
  207 +
  208 +
201 209 static gboolean check_accel(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, struct AccelEditInfo * info)
202 210 {
203 211 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
370 378  
371 379 void load(GtkWidget *widget, GtkWidget *terminal)
372 380 {
373   - struct KeyMap
374   - {
375   - guint key;
376   - GdkModifierType mods;
377   - };
378   -
379 381 debug("%s::%s","V3270AcceleratorSettings",__FUNCTION__);
380 382  
381 383 GtkListStore * store = GTK_V3270_ACCELERATOR_SETTINGS(widget)->store;
... ... @@ -433,8 +435,75 @@ void load(GtkWidget *widget, GtkWidget *terminal)
433 435  
434 436 }
435 437  
436   -void apply(GtkWidget *widget, GtkWidget *terminal)
  438 +static gboolean add_accel(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GSList **accelerators)
437 439 {
  440 + static const gint columns[] = { MAIN_MASK, MAIN_VALUE, ALTERNATIVE_MASK, ALTERNATIVE_VALUE };
  441 + size_t ix;
  442 + GValue value;
  443 + struct KeyMap keymap[2];
  444 +
  445 + V3270Accelerator * accel;
  446 +
  447 + memset(&value,0,sizeof(value));
  448 + gtk_tree_model_get_value(model, iter, ACTION, &value);
  449 + accel = (V3270Accelerator *) g_value_get_pointer(&value);
  450 + g_value_unset(&value);
  451 +
  452 + for(ix = 0; ix < 2; ix++)
  453 + {
  454 + guint key;
  455 + GdkModifierType mask;
  456 +
  457 + memset(&value,0,sizeof(value));
  458 + gtk_tree_model_get_value(model, iter, columns[(ix * 2)], &value);
  459 + keymap[ix].mods = (GdkModifierType) g_value_get_int(&value);
  460 + g_value_unset(&value);
  461 +
  462 + memset(&value,0,sizeof(value));
  463 + gtk_tree_model_get_value(model, iter, columns[(ix * 2)+1], &value);
  464 + keymap[ix].key = g_value_get_uint(&value);
  465 + g_value_unset(&value);
  466 +
  467 + }
  468 +
  469 + // Allways create the "main" accelerator to keep the action active.
  470 + V3270Accelerator * acc = v3270_accelerator_copy(accel);
  471 + acc->key = keymap[0].key;
  472 + acc->mods = keymap[0].mods;
  473 + *accelerators = g_slist_prepend(*accelerators,acc);
  474 +
  475 + // The alternative one is created only when set.
  476 + if(keymap[1].key)
  477 + {
  478 + acc = v3270_accelerator_copy(accel);
  479 + acc->key = keymap[1].key;
  480 + acc->mods = keymap[1].mods;
  481 + *accelerators = g_slist_prepend(*accelerators,acc);
  482 + }
  483 +
  484 + return FALSE;
  485 +}
  486 +
  487 +void apply(GtkWidget *s, GtkWidget *t)
  488 +{
  489 + v3270 * terminal = GTK_V3270(t);
  490 + V3270AcceleratorSettings * settings = GTK_V3270_ACCELERATOR_SETTINGS(s);
  491 +
438 492 debug("%s::%s","V3270AcceleratorSettings",__FUNCTION__);
  493 +
  494 + // Create a new accelerator table.
  495 + GSList * accelerators = NULL;
  496 +
  497 + gtk_tree_model_foreach(GTK_TREE_MODEL(settings->store), (GtkTreeModelForeachFunc) add_accel, &accelerators);
  498 +
  499 + // Replace the accelerator table.
  500 + if(terminal->accelerators)
  501 + g_slist_free_full(terminal->accelerators,g_free);
  502 +
  503 + terminal->accelerators = accelerators;
  504 +
  505 + // And sort it.
  506 + v3270_accelerator_map_sort(terminal);
  507 +
439 508 }
440 509  
... ...
src/terminal/keyboard.c
... ... @@ -56,43 +56,6 @@
56 56 #define GDK_NUMLOCK_MASK GDK_MOD2_MASK
57 57 #endif
58 58  
59   -/*--[ Globals ]--------------------------------------------------------------------------------------*/
60   -
61   - /*
62   - static struct _keycode
63   - {
64   - guint keyval;
65   - GdkModifierType state;
66   - int (*exec)(H3270 *session);
67   - } keycode[] =
68   - {
69   - { GDK_Left, 0, lib3270_cursor_left }, // OK
70   - { GDK_Up, 0, lib3270_cursor_up }, // OK
71   - { GDK_Right, 0, lib3270_cursor_right }, // OK
72   - { GDK_Down, 0, lib3270_cursor_down }, // OK
73   - { GDK_Tab, 0, lib3270_nextfield }, // OK
74   - { GDK_ISO_Left_Tab, GDK_SHIFT_MASK, lib3270_previousfield }, // OK
75   - { GDK_KP_Left, 0, lib3270_cursor_left },
76   - { GDK_KP_Up, 0, lib3270_cursor_up },
77   - { GDK_KP_Right, 0, lib3270_cursor_right },
78   - { GDK_KP_Down, 0, lib3270_cursor_down },
79   -
80   - { GDK_3270_PrintScreen, 0, lib3270_print_all },
81   - { GDK_P, GDK_CONTROL_MASK, lib3270_print_all },
82   -
83   - { GDK_Sys_Req, 0, lib3270_sysreq },
84   -
85   - { GDK_Print, GDK_CONTROL_MASK, lib3270_print_all },
86   - { GDK_Print, GDK_SHIFT_MASK, lib3270_sysreq },
87   -
88   -
89   -//#ifdef WIN32
90   -// { GDK_Pause, 0, NULL },
91   -//#endif
92   -
93   - };
94   - */
95   -
96 59 /*--[ Implement ]------------------------------------------------------------------------------------*/
97 60  
98 61 #define keyval_is_alt() (event->keyval == GDK_Alt_L || event->keyval == GDK_Meta_L || event->keyval == GDK_ISO_Level3_Shift)
... ... @@ -121,11 +84,65 @@
121 84  
122 85 }
123 86  
124   - static gboolean check_keypress(v3270 *widget, GdkEventKey *event)
  87 + static gboolean check_keypress(v3270 *widget, const GdkEventKey *event)
125 88 {
126   -// int f;
127   - GdkModifierType state = event->state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_ALT_MASK);
128   - gboolean handled = FALSE;
  89 + GdkKeymap * keymap = gdk_keymap_get_for_display(gtk_widget_get_display(GTK_WIDGET(widget)));
  90 +
  91 + // From gtk_accelerator_name at https://gitlab.gnome.org/GNOME/gtk/blob/master/gtk/gtkaccelgroup.c
  92 + // Side steps issue from https://mail.gnome.org/archives/gtk-app-devel-list/2007-August/msg00053.html
  93 + guint keyval = gdk_keyval_to_lower(event->keyval);
  94 +
  95 + // Add virtual modifiers to event state.
  96 + GdkModifierType state = event->state & ~GDK_RELEASE_MASK;
  97 + gdk_keymap_add_virtual_modifiers(keymap,&state);
  98 +
  99 + // Check if the application can handle the key.
  100 + gboolean handled = FALSE;
  101 + g_signal_emit(
  102 + GTK_WIDGET(widget),
  103 + v3270_widget_signal[V3270_SIGNAL_KEYPRESS],
  104 + 0,
  105 + keyval,
  106 + state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_ALT_MASK), // FIXME: Remove the reset flags after the main application update.
  107 + &handled
  108 + );
  109 +
  110 + debug("Keyboard action was %s (keyval=%08x state=%08x)",handled ? "Handled" : "Not handled",event->keyval,event->state);
  111 + if(handled)
  112 + return TRUE;
  113 +
  114 + //
  115 + // Check for accelerator.
  116 + //
  117 + const V3270Accelerator * accel = v3270_get_accelerator(GTK_WIDGET(widget), keyval, state);
  118 + if(accel)
  119 + {
  120 + debug("%s will fire",__FUNCTION__);
  121 + v3270_accelerator_activate(accel,GTK_WIDGET(widget));
  122 + return TRUE;
  123 + }
  124 +
  125 + // Check PFKeys
  126 + if(keyval >= GDK_F1 && keyval <= GDK_F12 && !(state & (GDK_CONTROL_MASK|GDK_ALT_MASK)))
  127 + {
  128 + int pfcode = (keyval - GDK_F1) + ((state & GDK_SHIFT_MASK) ? 13 : 1);
  129 +
  130 + debug("%s: PF%d will fire",__FUNCTION__,pfcode);
  131 +
  132 + if(pfcode > 0 && pfcode < 25)
  133 + {
  134 + lib3270_pfkey(widget->host,pfcode);
  135 + return TRUE;
  136 + }
  137 + else
  138 + {
  139 + g_warning("Invalid PFCode %d",pfcode);
  140 + }
  141 + }
  142 +
  143 + /*
  144 + gboolean handled = FALSE;
  145 + const V3270Accelerator * accel;
129 146  
130 147 #ifdef WIN32
131 148 // FIXME (perry#1#): Find a better way!
... ... @@ -133,35 +150,46 @@
133 150 event->keyval = GDK_Pause;
134 151  
135 152 // Windows sets <ctrl> in left/right control
136   - else if(state & GDK_CONTROL_MASK && (event->keyval == GDK_Control_R || event->keyval == GDK_Control_L))
137   - state &= ~GDK_CONTROL_MASK;
  153 + else if(event->state & GDK_CONTROL_MASK && (event->keyval == GDK_Control_R || event->keyval == GDK_Control_L))
  154 + event->state &= ~GDK_CONTROL_MASK;
138 155 #endif
139 156  
140   - g_signal_emit(GTK_WIDGET(widget), v3270_widget_signal[V3270_SIGNAL_KEYPRESS], 0, event->keyval, state, &handled);
  157 + g_signal_emit(
  158 + GTK_WIDGET(widget),
  159 + v3270_widget_signal[V3270_SIGNAL_KEYPRESS],
  160 + 0,
  161 + event->keyval,
  162 + event->state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_ALT_MASK),
  163 + &handled
  164 + );
141 165 debug("Keyboard action was %s",handled ? "Handled" : "Not handled");
142 166 if(handled)
143 167 return TRUE;
144 168  
145 169 #ifdef DEBUG
146 170 {
147   - g_autofree gchar * keyname = gtk_accelerator_name(event->keyval, state);
  171 + g_autofree gchar * keyname = gtk_accelerator_name(event->keyval, event->state);
148 172 debug("Keyname: %s",keyname);
149 173 }
150 174 #endif // DEBUG
151 175  
152 176 // Check accelerator table.
153   - const V3270Accelerator * acel = v3270_get_accelerator(GTK_WIDGET(widget), event->keyval, state);
154   - if(acel)
  177 + accel = v3270_get_accelerator(GTK_WIDGET(widget), event->keyval, event->state);
  178 +
  179 + if(!accel)
  180 + accel = v3270_get_accelerator(GTK_WIDGET(widget), event->keyval, event->state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_ALT_MASK));
  181 +
  182 + if(accel)
155 183 {
156 184 debug("%s will fire",__FUNCTION__);
157   - v3270_accelerator_activate(acel,GTK_WIDGET(widget));
  185 + v3270_accelerator_activate(accel,GTK_WIDGET(widget));
158 186 return TRUE;
159 187 }
160 188  
161 189 // Check PFKeys
162   - if(event->keyval >= GDK_F1 && event->keyval <= GDK_F12 && !(state & (GDK_CONTROL_MASK|GDK_ALT_MASK)))
  190 + if(event->keyval >= GDK_F1 && event->keyval <= GDK_F12 && !(event->state & (GDK_CONTROL_MASK|GDK_ALT_MASK)))
163 191 {
164   - int pfcode = (event->keyval - GDK_F1) + ((state & GDK_SHIFT_MASK) ? 13 : 1);
  192 + int pfcode = (event->keyval - GDK_F1) + ((event->state & GDK_SHIFT_MASK) ? 13 : 1);
165 193  
166 194 if(pfcode > 0 && pfcode < 25)
167 195 {
... ... @@ -169,6 +197,7 @@
169 197 return TRUE;
170 198 }
171 199 }
  200 + */
172 201  
173 202 return FALSE;
174 203 }
... ...
src/terminal/keyboard/accelerator.c
... ... @@ -56,9 +56,41 @@
56 56 }
57 57  
58 58  
59   - gboolean v3270_accelerator_compare(const V3270Accelerator * accell, const guint keyval, const GdkModifierType mods)
  59 + gboolean v3270_accelerator_compare(const V3270Accelerator * accel, const guint keyval, const GdkModifierType mods)
60 60 {
61   - return accell->key == keyval && accell->mods == mods;
  61 + // Problems:
  62 +
  63 + debug("%s: keys: %08x %08x",__FUNCTION__,accel->key,keyval);
  64 +
  65 + // It's the same key?
  66 + if(accel->key != keyval)
  67 + {
  68 + g_autofree gchar * acckey = gtk_accelerator_name(accel->key,accel->mods);
  69 + g_autofree gchar * qkey = gtk_accelerator_name(keyval,mods);
  70 + debug("%s: Rejected by key %08x %08x (%s %s)",__FUNCTION__,accel->key,keyval,acckey,qkey);
  71 + return FALSE;
  72 + }
  73 +
  74 + // The same key and same mods, Found it!
  75 + if(accel->mods == mods)
  76 + return TRUE;
  77 +
  78 +#ifdef DEBUG
  79 + {
  80 + g_autofree gchar * acckey = gtk_accelerator_name(accel->key,accel->mods);
  81 + g_autofree gchar * qkey = gtk_accelerator_name(keyval,mods);
  82 + 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));
  83 + }
  84 +#endif // DEBUG
  85 +
  86 + // All of the required mods is "ON"?
  87 + if(accel->mods != (mods & accel->mods))
  88 + {
  89 + debug("%s: Rejected %08x %08x",__FUNCTION__,accel->mods,(mods & accel->mods));
  90 + return FALSE;
  91 + }
  92 +
  93 + return TRUE;
62 94 }
63 95  
64 96 void v3270_accelerator_activate(const V3270Accelerator * acel, GtkWidget *terminal)
... ... @@ -80,6 +112,33 @@
80 112 return (V3270Accelerator *) ix->data;
81 113 }
82 114  
  115 +#ifdef DEBUG
  116 + {
  117 + g_autofree gchar * keyname = gtk_accelerator_name(keyval,state);
  118 + debug("%s: Can't find accelerator for %s",__FUNCTION__,keyname);
  119 + debug("Keyval: %d (%s) State: %04x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
  120 + keyval,
  121 + gdk_keyval_name(keyval),
  122 + state,
  123 + state & GDK_SHIFT_MASK ? " GDK_SHIFT_MASK" : "",
  124 + state & GDK_LOCK_MASK ? " GDK_LOCK_MASK" : "",
  125 + state & GDK_CONTROL_MASK ? " GDK_CONTROL_MASK" : "",
  126 + state & GDK_MOD1_MASK ? " GDK_MOD1_MASK" : "",
  127 + state & GDK_MOD2_MASK ? " GDK_MOD2_MASK" : "",
  128 + state & GDK_MOD3_MASK ? " GDK_MOD3_MASK" : "",
  129 + state & GDK_MOD4_MASK ? " GDK_MOD4_MASK" : "",
  130 + state & GDK_MOD5_MASK ? " GDK_MOD5_MASK" : "",
  131 + state & GDK_BUTTON1_MASK ? " GDK_BUTTON1_MASK" : "",
  132 + state & GDK_BUTTON2_MASK ? " GDK_BUTTON2_MASK" : "",
  133 + state & GDK_BUTTON3_MASK ? " GDK_BUTTON3_MASK" : "",
  134 + state & GDK_BUTTON4_MASK ? " GDK_BUTTON4_MASK" : "",
  135 + state & GDK_BUTTON5_MASK ? " GDK_BUTTON5_MASK" : "",
  136 + state & GDK_RELEASE_MASK ? " GDK_RELEASE_MASK" : "",
  137 + state & GDK_MODIFIER_MASK ? " GDK_MODIFIER_MASK" : ""
  138 + );
  139 +
  140 + }
  141 +#endif // DEBUG
83 142 return NULL;
84 143  
85 144 }
... ...
src/terminal/keyboard/keyfile.c
... ... @@ -95,7 +95,7 @@
95 95 {
96 96 V3270Accelerator * accel = NULL;
97 97  
98   - // Find accelerator by name
  98 + // Remove accelerator by name
99 99 {
100 100 GSList * ix = terminal->accelerators;
101 101  
... ...