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 | } | ... | ... |