c_spk
c_spk

Reputation: 179

GTK: "key-press-event" handling while Shift is pressed

I'm writing a small program: it's a lone drop-down menu with lowercase letters as menuitem labels:

enter image description here

If you hold Shift, the labels become capitalized (I wrote a "key-press-event" and "key-release-event" handler for this). The problem is that while Shift is pressed, I still want to navigate the menu and choose items with Enter press. The default handlers aren't get triggered if some modifier is pressed, so I handle it in the following way:

static gboolean menu_key_event(GtkWidget *menu, GdkEvent *event, gpointer data) {
    (void)data;

    GdkEventKey *key_event = (GdkEventKey*)event;
    switch (key_event->keyval) {
    case GDK_KEY_Shift_L:
    case GDK_KEY_Shift_R: ;
        bool b = (key_event->type == GDK_KEY_PRESS) ? true : false;
        gtk_container_foreach(GTK_CONTAINER(menu), menuitem_capitalize_label, &b);

        return TRUE;
        break;

    case GDK_KEY_Return:
        if ((key_event->type == GDK_KEY_PRESS) &&
            (key_event->state & GDK_SHIFT_MASK)) {
            // I want default callback to handle this
            g_signal_emit_by_name(menu, "activate-current");

            return TRUE;
        }
        break;

    case GDK_KEY_Up:
    case GDK_KEY_Down:
        if ((key_event->type == GDK_KEY_PRESS) &&
            (key_event->state & GDK_SHIFT_MASK)) {
            // Some function I wrote to fiddle with menu items,
            // simulating default selection behavior
            menu_rotate_selection(GTK_MENU_SHELL(menu), key_event->keyval);

            return TRUE;
        }
        break;
    }

    return FALSE;
}

Could this be done in a more elegant fashion? In short, I want my application handle Enter, arrow keys and Shift+Enter, Shift+ arrow keys the same way without needing to manually process it.

Upvotes: 0

Views: 1113

Answers (1)

c_spk
c_spk

Reputation: 179

I've finally found needed signal to select menuitems ("move-current"), so my own menu_rotate_selection function is no longer needed. That signal name is confusing though, I'd rather think its purpose to actually move the menuitem itself whithin the menu (first I thought the other obscure-named signal "cycle-focus" is for changing selection). Now it can be rewriten as following:

...
case GDK_KEY_Up:
case GDK_KEY_Down:
    if ((key_event->type == GDK_KEY_PRESS) &&
        (key_event->state & GDK_SHIFT_MASK)) {
        GtkMenuDirectionType dir = (key_event->keyval == GDK_KEY_Up) ?
            GTK_MENU_DIR_PREV : GTK_MENU_DIR_NEXT;
        g_signal_emit_by_name(menu, "move-current", dir);

        return TRUE;
    }
    break;
...

This pretty much answers my question.

Upvotes: 0

Related Questions