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,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