From 1ac9bdaa0240f89e613416b921af1b9b6e8a89b6 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sun, 13 Sep 2015 15:21:21 -0400 Subject: [PATCH] Implemented keyboard events on GTK+ uiArea. --- gtkarea/area.c | 116 +++++++++++++++++++++++++++++++++++++++++++++-- gtkarea/main.c | 2 +- gtkarea/uipriv.h | 2 + 3 files changed, 116 insertions(+), 4 deletions(-) diff --git a/gtkarea/area.c b/gtkarea/area.c index c1ab08a8..a16c26be 100644 --- a/gtkarea/area.c +++ b/gtkarea/area.c @@ -295,7 +295,117 @@ gboolean areaWidget_enterleave_notify_event(GtkWidget *w, GdkEventCrossing *e) // even if I invoke the task switcher and switch processes, the mouse grab will still be held until I let go of all buttons // therefore, no DragBroken() -// TODO key events +// we use GDK_KEY_Print as a sentinel because libui will never support the print screen key; that key belongs to the user + +static const struct { + guint keyval; + uiExtKey extkey; +} extKeys[] = { + { GDK_KEY_Escape, uiExtKeyEscape }, + { GDK_KEY_Insert, uiExtKeyInsert }, + { GDK_KEY_Delete, uiExtKeyDelete }, + { GDK_KEY_Home, uiExtKeyHome }, + { GDK_KEY_End, uiExtKeyEnd }, + { GDK_KEY_Page_Up, uiExtKeyPageUp }, + { GDK_KEY_Page_Down, uiExtKeyPageDown }, + { GDK_KEY_Up, uiExtKeyUp }, + { GDK_KEY_Down, uiExtKeyDown }, + { GDK_KEY_Left, uiExtKeyLeft }, + { GDK_KEY_Right, uiExtKeyRight }, + { GDK_KEY_F1, uiExtKeyF1 }, + { GDK_KEY_F2, uiExtKeyF2 }, + { GDK_KEY_F3, uiExtKeyF3 }, + { GDK_KEY_F4, uiExtKeyF4 }, + { GDK_KEY_F5, uiExtKeyF5 }, + { GDK_KEY_F6, uiExtKeyF6 }, + { GDK_KEY_F7, uiExtKeyF7 }, + { GDK_KEY_F8, uiExtKeyF8 }, + { GDK_KEY_F9, uiExtKeyF9 }, + { GDK_KEY_F10, uiExtKeyF10 }, + { GDK_KEY_F11, uiExtKeyF11 }, + { GDK_KEY_F12, uiExtKeyF12 }, + // numpad numeric keys and . are handled in events.c + { GDK_KEY_KP_Enter, uiExtKeyNEnter }, + { GDK_KEY_KP_Add, uiExtKeyNAdd }, + { GDK_KEY_KP_Subtract, uiExtKeyNSubtract }, + { GDK_KEY_KP_Multiply, uiExtKeyNMultiply }, + { GDK_KEY_KP_Divide, uiExtKeyNDivide }, + { GDK_KEY_Print, 0 }, +}; + +static const struct { + guint keyval; + uiModifiers mod; +} modKeys[] = { + { GDK_KEY_Control_L, uiModifierCtrl }, + { GDK_KEY_Control_R, uiModifierCtrl }, + { GDK_KEY_Alt_L, uiModifierAlt }, + { GDK_KEY_Alt_R, uiModifierAlt }, + { GDK_KEY_Meta_L, uiModifierAlt }, + { GDK_KEY_Meta_R, uiModifierAlt }, + { GDK_KEY_Shift_L, uiModifierShift }, + { GDK_KEY_Shift_R, uiModifierShift }, + { GDK_KEY_Super_L, uiModifierSuper }, + { GDK_KEY_Super_R, uiModifierSuper }, + { GDK_KEY_Print, 0 }, +}; + +static int areaKeyEvent(struct areaPrivate *ap, int up, GdkEventKey *e) +{ + uiAreaKeyEvent ke; + guint state; + int i; + + ke.Key = 0; + ke.ExtKey = 0; + ke.Modifier = 0; + + state = translateModifiers(e->state, e->window); + ke.Modifiers = toModifiers(state); + + ke.Up = up; + + for (i = 0; extKeys[i].keyval != GDK_KEY_Print; i++) + if (extKeys[i].keyval == e->keyval) { + ke.ExtKey = extKeys[i].extkey; + goto keyFound; + } + + for (i = 0; modKeys[i].keyval != GDK_KEY_Print; i++) + if (modKeys[i].keyval == e->keyval) { + ke.Modifier = modKeys[i].mod; + // don't include the modifier in ke.Modifiers + ke.Modifiers &= ~ke.Modifier; + goto keyFound; + } + + if (fromScancode(e->hardware_keycode - 8, &ke)) + goto keyFound; + + // no supported key found; treat as unhandled + return 0; + +keyFound: + return (*(ap->ah->KeyEvent))(ap->ah, ap->a, &ke); +} + +static gboolean areaWidget_key_press_event(GtkWidget *w, GdkEventKey *e) +{ + struct areaPrivate *ap = areaWidget(w)->priv; + + if (areaKeyEvent(ap, 0, e)) + return GDK_EVENT_STOP; + return GDK_EVENT_PROPAGATE; +} + +static gboolean areaWidget_key_release_event(GtkWidget *w, GdkEventKey *e) +{ + struct areaPrivate *ap = areaWidget(w)->priv; + + if (areaKeyEvent(ap, 1, e)) + return GDK_EVENT_STOP; + return GDK_EVENT_PROPAGATE; +} enum { // normal properties must come before override properties @@ -394,8 +504,8 @@ static void areaWidget_class_init(areaWidgetClass *class) GTK_WIDGET_CLASS(class)->motion_notify_event = areaWidget_motion_notify_event; GTK_WIDGET_CLASS(class)->enter_notify_event = areaWidget_enterleave_notify_event; GTK_WIDGET_CLASS(class)->leave_notify_event = areaWidget_enterleave_notify_event; -// GTK_WIDGET_CLASS(class)->key_press_event = areaWidget_key_press_event; -// GTK_WIDGET_CLASS(class)->key_release_event = areaWidget_key_release_event; + GTK_WIDGET_CLASS(class)->key_press_event = areaWidget_key_press_event; + GTK_WIDGET_CLASS(class)->key_release_event = areaWidget_key_release_event; g_type_class_add_private(G_OBJECT_CLASS(class), sizeof (struct areaPrivate)); diff --git a/gtkarea/main.c b/gtkarea/main.c index 2b5bf9d6..73df8450 100644 --- a/gtkarea/main.c +++ b/gtkarea/main.c @@ -139,7 +139,7 @@ static int handlerKeyEvent(uiAreaHandler *ah, uiArea *a, uiAreaKeyEvent *e) k, (int) e->ExtKey, (int) e->Modifier, - (int) e->Modifiers; + (int) e->Modifiers, e->Up); return 0; } diff --git a/gtkarea/uipriv.h b/gtkarea/uipriv.h index d0e1c7d9..e519c93f 100644 --- a/gtkarea/uipriv.h +++ b/gtkarea/uipriv.h @@ -12,3 +12,5 @@ struct clickCounter { }; extern uintmax_t clickCounterClick(clickCounter *, uintmax_t, intmax_t, intmax_t, uintptr_t, uintptr_t, intmax_t, intmax_t); extern void clickCounterReset(clickCounter *); + +extern int fromScancode(uintptr_t, uiAreaKeyEvent *);