entry: handle keyboard events in unix part

This commit is contained in:
Rustam Gamidov 2020-03-15 08:53:40 +02:00
parent 209fb97902
commit 64348a152e
4 changed files with 164 additions and 119 deletions

View File

@ -1,5 +1,6 @@
// 4 september 2015
#include "uipriv_unix.h"
#include "keyboard.h"
// notes:
// - G_DECLARE_DERIVABLE/FINAL_INTERFACE() requires glib 2.44 and that's starting with debian stretch (testing) (GTK+ 3.18) and ubuntu 15.04 (GTK+ 3.14) - debian jessie has 2.42 (GTK+ 3.14)
@ -170,36 +171,6 @@ static void areaWidget_get_preferred_width(GtkWidget *w, gint *min, gint *nat)
}
}
static guint translateModifiers(guint state, GdkWindow *window)
{
GdkModifierType statetype;
// GDK doesn't initialize the modifier flags fully; we have to explicitly tell it to (thanks to Daniel_S and daniels (two different people) in irc.gimp.net/#gtk+)
statetype = state;
gdk_keymap_add_virtual_modifiers(
gdk_keymap_get_for_display(gdk_window_get_display(window)),
&statetype);
return statetype;
}
static uiModifiers toModifiers(guint state)
{
uiModifiers m;
m = 0;
if ((state & GDK_CONTROL_MASK) != 0)
m |= uiModifierCtrl;
if ((state & GDK_META_MASK) != 0)
m |= uiModifierAlt;
if ((state & GDK_MOD1_MASK) != 0) // GTK+ itself requires this to be Alt (just read through gtkaccelgroup.c)
m |= uiModifierAlt;
if ((state & GDK_SHIFT_MASK) != 0)
m |= uiModifierShift;
if ((state & GDK_SUPER_MASK) != 0)
m |= uiModifierSuper;
return m;
}
// capture on drag is done automatically on GTK+
static void finishMouseEvent(uiArea *a, uiAreaMouseEvent *me, guint mb, gdouble x, gdouble y, guint state, GdkWindow *window)
{
@ -326,99 +297,14 @@ static gboolean areaWidget_leave_notify_event(GtkWidget *w, GdkEventCrossing *e)
// note: there is no equivalent to WM_CAPTURECHANGED on GTK+; there literally is no way to break a grab like that (at least not on X11 and Wayland)
// 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()
// 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(uiArea *a, 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 (uiprivFromScancode(e->hardware_keycode - 8, &ke))
goto keyFound;
// no supported key found; treat as unhandled
if (fillUiKeyEvent(&ke, e)) {
ke.Up = up;
return (*(a->ah->KeyEvent))(a->ah, a, &ke);
}
return 0;
keyFound:
return (*(a->ah->KeyEvent))(a->ah, a, &ke);
}
static gboolean areaWidget_key_press_event(GtkWidget *w, GdkEventKey *e)

View File

@ -1,5 +1,6 @@
// 11 june 2015
#include "uipriv_unix.h"
#include "keyboard.h"
struct uiEntry {
uiUnixControl c;
@ -9,6 +10,7 @@ struct uiEntry {
void (*onChanged)(uiEntry *, void *);
void *onChangedData;
gulong onChangedSignal;
int (*onKeyEvent)(uiEntry *, uiAreaKeyEvent *);
};
uiUnixControlAllDefaults(uiEntry)
@ -25,6 +27,22 @@ static void defaultOnChanged(uiEntry *e, void *data)
// do nothing
}
static gboolean onKeyEvent(GtkEditable *editable, GdkEventKey *event, gpointer data)
{
uiEntry *e = (uiEntry*)(data);
uiAreaKeyEvent ke;
if (fillUiKeyEvent(&ke, event))
return (*(e->onKeyEvent))(e, &ke);
return GDK_EVENT_PROPAGATE;
}
static int defaultOnKeyEvent(uiEntry *e, uiAreaKeyEvent *uke)
{
// do nothing
// return GDK_EVENT_STOP; // to stop further key handling
return GDK_EVENT_PROPAGATE;
}
char *uiEntryText(uiEntry *e)
{
return uiUnixStrdupText(gtk_entry_get_text(e->entry));
@ -45,6 +63,11 @@ void uiEntryOnChanged(uiEntry *e, void (*f)(uiEntry *, void *), void *data)
e->onChangedData = data;
}
void uiEntryOnKeyEvent(uiEntry *e, int (*f)(uiEntry *, uiAreaKeyEvent *))
{
e->onKeyEvent = f;
}
int uiEntryReadOnly(uiEntry *e)
{
return gtk_editable_get_editable(e->editable) == FALSE;
@ -73,6 +96,11 @@ static uiEntry *finishNewEntry(GtkWidget *w, const gchar *signal)
e->onChangedSignal = g_signal_connect(e->widget, signal, G_CALLBACK(onChanged), e);
uiEntryOnChanged(e, defaultOnChanged, NULL);
gtk_widget_add_events(e->widget, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
g_signal_connect(e->widget, "key_press_event", G_CALLBACK(onKeyEvent), e);
g_signal_connect(e->widget, "key_release_event", G_CALLBACK(onKeyEvent), e);
uiEntryOnKeyEvent(e, defaultOnKeyEvent);
return e;
}

130
unix/keyboard.h Normal file
View File

@ -0,0 +1,130 @@
#pragma once
#include "uipriv_unix.h"
static guint translateModifiers(guint state, GdkWindow *window)
{
GdkModifierType statetype;
// GDK doesn't initialize the modifier flags fully; we have to explicitly tell it to (thanks to Daniel_S and daniels (two different people) in irc.gimp.net/#gtk+)
statetype = state;
gdk_keymap_add_virtual_modifiers(
gdk_keymap_get_for_display(gdk_window_get_display(window)),
&statetype);
return statetype;
}
static uiModifiers toModifiers(guint state)
{
uiModifiers m;
m = 0;
if ((state & GDK_CONTROL_MASK) != 0)
m |= uiModifierCtrl;
if ((state & GDK_META_MASK) != 0)
m |= uiModifierAlt;
if ((state & GDK_MOD1_MASK) != 0) // GTK+ itself requires this to be Alt (just read through gtkaccelgroup.c)
m |= uiModifierAlt;
if ((state & GDK_SHIFT_MASK) != 0)
m |= uiModifierShift;
if ((state & GDK_SUPER_MASK) != 0)
m |= uiModifierSuper;
return m;
}
// 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 gboolean fillUiKeyEvent(uiAreaKeyEvent *ke, GdkEventKey *e)
{
guint state;
int i;
ke->Key = 0;
ke->ExtKey = 0;
ke->Modifier = 0;
state = translateModifiers(e->state, e->window);
ke->Modifiers = toModifiers(state);
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 (uiprivFromScancode(e->hardware_keycode - 8, ke))
goto keyFound;
// no supported key found; treat as unhandled
return FALSE;
keyFound:
ke->Up = 0;
if (e->type == GDK_KEY_PRESS)
ke->Up = 1;
return TRUE;
}

View File

@ -1,4 +1,5 @@
// 22 april 2015
#pragma once
#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_40
#define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_40
#define GDK_VERSION_MIN_REQUIRED GDK_VERSION_3_10