Commit 906fa5e263945b25f15d8f39a32f95fe52a83d22
1 parent
43282365
Exists in
master
and in
1 other branch
Refactoring accelerator engine to fix issues with <alt><shift><control>
accels.
Showing
4 changed files
with
217 additions
and
60 deletions
Show diff stats
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 | } | ... | ... |