entry: handle keyboard events in unix part
This commit is contained in:
parent
209fb97902
commit
64348a152e
124
unix/area.c
124
unix/area.c
|
@ -1,5 +1,6 @@
|
||||||
// 4 september 2015
|
// 4 september 2015
|
||||||
#include "uipriv_unix.h"
|
#include "uipriv_unix.h"
|
||||||
|
#include "keyboard.h"
|
||||||
|
|
||||||
// notes:
|
// 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)
|
// - 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+
|
// 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)
|
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)
|
// 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
|
// 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()
|
// 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)
|
static int areaKeyEvent(uiArea *a, int up, GdkEventKey *e)
|
||||||
{
|
{
|
||||||
uiAreaKeyEvent ke;
|
uiAreaKeyEvent ke;
|
||||||
guint state;
|
if (fillUiKeyEvent(&ke, e)) {
|
||||||
int i;
|
ke.Up = up;
|
||||||
|
return (*(a->ah->KeyEvent))(a->ah, a, &ke);
|
||||||
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
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
keyFound:
|
|
||||||
return (*(a->ah->KeyEvent))(a->ah, a, &ke);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean areaWidget_key_press_event(GtkWidget *w, GdkEventKey *e)
|
static gboolean areaWidget_key_press_event(GtkWidget *w, GdkEventKey *e)
|
||||||
|
|
28
unix/entry.c
28
unix/entry.c
|
@ -1,5 +1,6 @@
|
||||||
// 11 june 2015
|
// 11 june 2015
|
||||||
#include "uipriv_unix.h"
|
#include "uipriv_unix.h"
|
||||||
|
#include "keyboard.h"
|
||||||
|
|
||||||
struct uiEntry {
|
struct uiEntry {
|
||||||
uiUnixControl c;
|
uiUnixControl c;
|
||||||
|
@ -9,6 +10,7 @@ struct uiEntry {
|
||||||
void (*onChanged)(uiEntry *, void *);
|
void (*onChanged)(uiEntry *, void *);
|
||||||
void *onChangedData;
|
void *onChangedData;
|
||||||
gulong onChangedSignal;
|
gulong onChangedSignal;
|
||||||
|
int (*onKeyEvent)(uiEntry *, uiAreaKeyEvent *);
|
||||||
};
|
};
|
||||||
|
|
||||||
uiUnixControlAllDefaults(uiEntry)
|
uiUnixControlAllDefaults(uiEntry)
|
||||||
|
@ -25,6 +27,22 @@ static void defaultOnChanged(uiEntry *e, void *data)
|
||||||
// do nothing
|
// 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)
|
char *uiEntryText(uiEntry *e)
|
||||||
{
|
{
|
||||||
return uiUnixStrdupText(gtk_entry_get_text(e->entry));
|
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;
|
e->onChangedData = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void uiEntryOnKeyEvent(uiEntry *e, int (*f)(uiEntry *, uiAreaKeyEvent *))
|
||||||
|
{
|
||||||
|
e->onKeyEvent = f;
|
||||||
|
}
|
||||||
|
|
||||||
int uiEntryReadOnly(uiEntry *e)
|
int uiEntryReadOnly(uiEntry *e)
|
||||||
{
|
{
|
||||||
return gtk_editable_get_editable(e->editable) == FALSE;
|
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);
|
e->onChangedSignal = g_signal_connect(e->widget, signal, G_CALLBACK(onChanged), e);
|
||||||
uiEntryOnChanged(e, defaultOnChanged, NULL);
|
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;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
// 22 april 2015
|
// 22 april 2015
|
||||||
|
#pragma once
|
||||||
#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_40
|
#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_40
|
||||||
#define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_40
|
#define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_40
|
||||||
#define GDK_VERSION_MIN_REQUIRED GDK_VERSION_3_10
|
#define GDK_VERSION_MIN_REQUIRED GDK_VERSION_3_10
|
||||||
|
|
Loading…
Reference in New Issue