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,6 +71,12 @@
71 71
72 /*--[ Globals ]--------------------------------------------------------------------------------------*/ 72 /*--[ Globals ]--------------------------------------------------------------------------------------*/
73 73
  74 + struct KeyMap
  75 + {
  76 + guint key;
  77 + GdkModifierType mods;
  78 + };
  79 +
74 static void load(GtkWidget *w, GtkWidget *terminal); 80 static void load(GtkWidget *w, GtkWidget *terminal);
75 static void apply(GtkWidget *w, GtkWidget *terminal); 81 static void apply(GtkWidget *w, GtkWidget *terminal);
76 82
@@ -198,6 +204,8 @@ struct AccelEditInfo @@ -198,6 +204,8 @@ struct AccelEditInfo
198 int id_mask; 204 int id_mask;
199 }; 205 };
200 206
  207 +
  208 +
201 static gboolean check_accel(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, struct AccelEditInfo * info) 209 static gboolean check_accel(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, struct AccelEditInfo * info)
202 { 210 {
203 static const gint columns[] = { MAIN_MASK, MAIN_VALUE, ALTERNATIVE_MASK, ALTERNATIVE_VALUE }; 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,12 +378,6 @@ static void alternative_edited(GtkCellRendererAccel G_GNUC_UNUSED(*accel), gchar
370 378
371 void load(GtkWidget *widget, GtkWidget *terminal) 379 void load(GtkWidget *widget, GtkWidget *terminal)
372 { 380 {
373 - struct KeyMap  
374 - {  
375 - guint key;  
376 - GdkModifierType mods;  
377 - };  
378 -  
379 debug("%s::%s","V3270AcceleratorSettings",__FUNCTION__); 381 debug("%s::%s","V3270AcceleratorSettings",__FUNCTION__);
380 382
381 GtkListStore * store = GTK_V3270_ACCELERATOR_SETTINGS(widget)->store; 383 GtkListStore * store = GTK_V3270_ACCELERATOR_SETTINGS(widget)->store;
@@ -433,8 +435,75 @@ void load(GtkWidget *widget, GtkWidget *terminal) @@ -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 debug("%s::%s","V3270AcceleratorSettings",__FUNCTION__); 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,43 +56,6 @@
56 #define GDK_NUMLOCK_MASK GDK_MOD2_MASK 56 #define GDK_NUMLOCK_MASK GDK_MOD2_MASK
57 #endif 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 /*--[ Implement ]------------------------------------------------------------------------------------*/ 59 /*--[ Implement ]------------------------------------------------------------------------------------*/
97 60
98 #define keyval_is_alt() (event->keyval == GDK_Alt_L || event->keyval == GDK_Meta_L || event->keyval == GDK_ISO_Level3_Shift) 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,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 #ifdef WIN32 147 #ifdef WIN32
131 // FIXME (perry#1#): Find a better way! 148 // FIXME (perry#1#): Find a better way!
@@ -133,35 +150,46 @@ @@ -133,35 +150,46 @@
133 event->keyval = GDK_Pause; 150 event->keyval = GDK_Pause;
134 151
135 // Windows sets <ctrl> in left/right control 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 #endif 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 debug("Keyboard action was %s",handled ? "Handled" : "Not handled"); 165 debug("Keyboard action was %s",handled ? "Handled" : "Not handled");
142 if(handled) 166 if(handled)
143 return TRUE; 167 return TRUE;
144 168
145 #ifdef DEBUG 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 debug("Keyname: %s",keyname); 172 debug("Keyname: %s",keyname);
149 } 173 }
150 #endif // DEBUG 174 #endif // DEBUG
151 175
152 // Check accelerator table. 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 debug("%s will fire",__FUNCTION__); 184 debug("%s will fire",__FUNCTION__);
157 - v3270_accelerator_activate(acel,GTK_WIDGET(widget)); 185 + v3270_accelerator_activate(accel,GTK_WIDGET(widget));
158 return TRUE; 186 return TRUE;
159 } 187 }
160 188
161 // Check PFKeys 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 if(pfcode > 0 && pfcode < 25) 194 if(pfcode > 0 && pfcode < 25)
167 { 195 {
@@ -169,6 +197,7 @@ @@ -169,6 +197,7 @@
169 return TRUE; 197 return TRUE;
170 } 198 }
171 } 199 }
  200 + */
172 201
173 return FALSE; 202 return FALSE;
174 } 203 }
src/terminal/keyboard/accelerator.c
@@ -56,9 +56,41 @@ @@ -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 void v3270_accelerator_activate(const V3270Accelerator * acel, GtkWidget *terminal) 96 void v3270_accelerator_activate(const V3270Accelerator * acel, GtkWidget *terminal)
@@ -80,6 +112,33 @@ @@ -80,6 +112,33 @@
80 return (V3270Accelerator *) ix->data; 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 return NULL; 142 return NULL;
84 143
85 } 144 }
src/terminal/keyboard/keyfile.c
@@ -95,7 +95,7 @@ @@ -95,7 +95,7 @@
95 { 95 {
96 V3270Accelerator * accel = NULL; 96 V3270Accelerator * accel = NULL;
97 97
98 - // Find accelerator by name 98 + // Remove accelerator by name
99 { 99 {
100 GSList * ix = terminal->accelerators; 100 GSList * ix = terminal->accelerators;
101 101