Merge pull request #1 from RustamGamidov/entry_keyEvent
entry. handle key event
This commit is contained in:
commit
cd3f9d29a2
|
@ -11,7 +11,6 @@
|
||||||
BOOL libui_enabled;
|
BOOL libui_enabled;
|
||||||
}
|
}
|
||||||
- (id)initWithFrame:(NSRect)r area:(uiArea *)a;
|
- (id)initWithFrame:(NSRect)r area:(uiArea *)a;
|
||||||
- (uiModifiers)parseModifiers:(NSEvent *)e;
|
|
||||||
- (void)doMouseEvent:(NSEvent *)e;
|
- (void)doMouseEvent:(NSEvent *)e;
|
||||||
- (int)sendKeyEvent:(uiAreaKeyEvent *)ke;
|
- (int)sendKeyEvent:(uiAreaKeyEvent *)ke;
|
||||||
- (int)doKeyDownUp:(NSEvent *)e up:(int)up;
|
- (int)doKeyDownUp:(NSEvent *)e up:(int)up;
|
||||||
|
@ -87,24 +86,6 @@ struct uiArea {
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (uiModifiers)parseModifiers:(NSEvent *)e
|
|
||||||
{
|
|
||||||
NSEventModifierFlags mods;
|
|
||||||
uiModifiers m;
|
|
||||||
|
|
||||||
m = 0;
|
|
||||||
mods = [e modifierFlags];
|
|
||||||
if ((mods & NSControlKeyMask) != 0)
|
|
||||||
m |= uiModifierCtrl;
|
|
||||||
if ((mods & NSAlternateKeyMask) != 0)
|
|
||||||
m |= uiModifierAlt;
|
|
||||||
if ((mods & NSShiftKeyMask) != 0)
|
|
||||||
m |= uiModifierShift;
|
|
||||||
if ((mods & NSCommandKeyMask) != 0)
|
|
||||||
m |= uiModifierSuper;
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setupNewTrackingArea
|
- (void)setupNewTrackingArea
|
||||||
{
|
{
|
||||||
self->libui_ta = [[NSTrackingArea alloc] initWithRect:[self bounds]
|
self->libui_ta = [[NSTrackingArea alloc] initWithRect:[self bounds]
|
||||||
|
@ -178,7 +159,7 @@ struct uiArea {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
me.Modifiers = [self parseModifiers:e];
|
me.Modifiers = parseModifiers(e);
|
||||||
|
|
||||||
pmb = [NSEvent pressedMouseButtons];
|
pmb = [NSEvent pressedMouseButtons];
|
||||||
me.Held1To64 = 0;
|
me.Held1To64 = 0;
|
||||||
|
@ -260,7 +241,7 @@ mouseEvent(otherMouseUp)
|
||||||
ke.ExtKey = 0;
|
ke.ExtKey = 0;
|
||||||
ke.Modifier = 0;
|
ke.Modifier = 0;
|
||||||
|
|
||||||
ke.Modifiers = [self parseModifiers:e];
|
ke.Modifiers = parseModifiers(e);
|
||||||
|
|
||||||
ke.Up = up;
|
ke.Up = up;
|
||||||
|
|
||||||
|
@ -292,7 +273,7 @@ mouseEvent(otherMouseUp)
|
||||||
if (!uiprivKeycodeModifier([e keyCode], &whichmod))
|
if (!uiprivKeycodeModifier([e keyCode], &whichmod))
|
||||||
return 0;
|
return 0;
|
||||||
ke.Modifier = whichmod;
|
ke.Modifier = whichmod;
|
||||||
ke.Modifiers = [self parseModifiers:e];
|
ke.Modifiers = parseModifiers(e);
|
||||||
ke.Up = (ke.Modifiers & ke.Modifier) == 0;
|
ke.Up = (ke.Modifiers & ke.Modifier) == 0;
|
||||||
// and then drop the current modifier from Modifiers
|
// and then drop the current modifier from Modifiers
|
||||||
ke.Modifiers &= ~ke.Modifier;
|
ke.Modifiers &= ~ke.Modifier;
|
||||||
|
|
|
@ -157,3 +157,21 @@ BOOL uiprivKeycodeModifier(unsigned short keycode, uiModifiers *mod)
|
||||||
}
|
}
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uiModifiers parseModifiers(NSEvent *e)
|
||||||
|
{
|
||||||
|
NSEventModifierFlags mods;
|
||||||
|
uiModifiers m;
|
||||||
|
|
||||||
|
m = 0;
|
||||||
|
mods = [e modifierFlags];
|
||||||
|
if ((mods & NSControlKeyMask) != 0)
|
||||||
|
m |= uiModifierCtrl;
|
||||||
|
if ((mods & NSAlternateKeyMask) != 0)
|
||||||
|
m |= uiModifierAlt;
|
||||||
|
if ((mods & NSShiftKeyMask) != 0)
|
||||||
|
m |= uiModifierShift;
|
||||||
|
if ((mods & NSCommandKeyMask) != 0)
|
||||||
|
m |= uiModifierSuper;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
|
@ -59,6 +59,7 @@ struct uiEntry {
|
||||||
NSTextField *textfield;
|
NSTextField *textfield;
|
||||||
void (*onChanged)(uiEntry *, void *);
|
void (*onChanged)(uiEntry *, void *);
|
||||||
void *onChangedData;
|
void *onChangedData;
|
||||||
|
int (*onKeyEvent)(uiEntry *, uiAreaKeyEvent *);
|
||||||
};
|
};
|
||||||
|
|
||||||
static BOOL isSearchField(NSTextField *tf)
|
static BOOL isSearchField(NSTextField *tf)
|
||||||
|
@ -66,8 +67,19 @@ static BOOL isSearchField(NSTextField *tf)
|
||||||
return [tf isKindOfClass:[NSSearchField class]];
|
return [tf isKindOfClass:[NSSearchField class]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void triggerOnKeyEvent(void *key, void *e, void *data)
|
||||||
|
{
|
||||||
|
uiEntry *entry = (uiEntry *)e;
|
||||||
|
void *firstResponder = [entry->textfield window].firstResponder;
|
||||||
|
BOOL sameObj = (entry->textfield == firstResponder);
|
||||||
|
BOOL currentEditor = (entry->textfield.currentEditor && entry->textfield.currentEditor == firstResponder);
|
||||||
|
if (sameObj || currentEditor)
|
||||||
|
entry->onKeyEvent(entry, data);
|
||||||
|
}
|
||||||
|
|
||||||
@interface entryDelegateClass : NSObject<NSTextFieldDelegate> {
|
@interface entryDelegateClass : NSObject<NSTextFieldDelegate> {
|
||||||
uiprivMap *entries;
|
uiprivMap *entries;
|
||||||
|
id eventMonitor;
|
||||||
}
|
}
|
||||||
- (void)controlTextDidChange:(NSNotification *)note;
|
- (void)controlTextDidChange:(NSNotification *)note;
|
||||||
- (IBAction)onSearch:(id)sender;
|
- (IBAction)onSearch:(id)sender;
|
||||||
|
@ -82,11 +94,28 @@ static BOOL isSearchField(NSTextField *tf)
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self)
|
if (self)
|
||||||
self->entries = uiprivNewMap();
|
self->entries = uiprivNewMap();
|
||||||
|
|
||||||
|
NSEvent* (^eventHandler)(NSEvent*) = ^(NSEvent *theEvent) {
|
||||||
|
uiAreaKeyEvent ke;
|
||||||
|
ke.Key = 0;
|
||||||
|
ke.ExtKey = 0;
|
||||||
|
ke.Modifier = 0;
|
||||||
|
ke.Modifiers = parseModifiers(theEvent);
|
||||||
|
ke.Up = ([theEvent type] == NSKeyUp ? 1 : 0);
|
||||||
|
|
||||||
|
if (uiprivFromKeycode([theEvent keyCode], &ke))
|
||||||
|
uiprivMapWalkWithData(self->entries, &ke, triggerOnKeyEvent);
|
||||||
|
|
||||||
|
return theEvent;
|
||||||
|
};
|
||||||
|
eventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:(NSKeyDownMask | NSKeyUpMask) handler:eventHandler];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
|
[NSEvent removeMonitor:eventMonitor];
|
||||||
uiprivMapDestroy(self->entries);
|
uiprivMapDestroy(self->entries);
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
@ -155,6 +184,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 [e->textfield isEditable] == NO;
|
return [e->textfield isEditable] == NO;
|
||||||
|
@ -175,6 +209,12 @@ static void defaultOnChanged(uiEntry *e, void *data)
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int defaultOnKeyEvent(uiEntry *e, uiAreaKeyEvent *ke)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
// these are based on interface builder defaults; my comments in the old code weren't very good so I don't really know what talked about what, sorry :/
|
// these are based on interface builder defaults; my comments in the old code weren't very good so I don't really know what talked about what, sorry :/
|
||||||
void uiprivFinishNewTextField(NSTextField *t, BOOL isEntry)
|
void uiprivFinishNewTextField(NSTextField *t, BOOL isEntry)
|
||||||
{
|
{
|
||||||
|
@ -220,6 +260,7 @@ static uiEntry *finishNewEntry(Class class)
|
||||||
}
|
}
|
||||||
[entryDelegate registerEntry:e];
|
[entryDelegate registerEntry:e];
|
||||||
uiEntryOnChanged(e, defaultOnChanged, NULL);
|
uiEntryOnChanged(e, defaultOnChanged, NULL);
|
||||||
|
uiEntryOnKeyEvent(e, defaultOnKeyEvent);
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
14
darwin/map.m
14
darwin/map.m
|
@ -55,6 +55,20 @@ void uiprivMapWalk(uiprivMap *m, void (*f)(void *key, void *value))
|
||||||
NSEndMapTableEnumeration(&e);
|
NSEndMapTableEnumeration(&e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void uiprivMapWalkWithData(uiprivMap *m, void *data, void (*f)(void *key, void *value, void *data))
|
||||||
|
{
|
||||||
|
NSMapEnumerator e;
|
||||||
|
void *k, *v;
|
||||||
|
|
||||||
|
e = NSEnumerateMapTable(m->m);
|
||||||
|
k = NULL;
|
||||||
|
v = NULL;
|
||||||
|
while (NSNextMapEnumeratorPair(&e, &k, &v))
|
||||||
|
f(k, v, data);
|
||||||
|
NSEndMapTableEnumeration(&e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void uiprivMapReset(uiprivMap *m)
|
void uiprivMapReset(uiprivMap *m)
|
||||||
{
|
{
|
||||||
NSResetMapTable(m->m);
|
NSResetMapTable(m->m);
|
||||||
|
|
|
@ -31,6 +31,7 @@ extern void *uiprivMapGet(uiprivMap *m, void *key);
|
||||||
extern void uiprivMapSet(uiprivMap *m, void *key, void *value);
|
extern void uiprivMapSet(uiprivMap *m, void *key, void *value);
|
||||||
extern void uiprivMapDelete(uiprivMap *m, void *key);
|
extern void uiprivMapDelete(uiprivMap *m, void *key);
|
||||||
extern void uiprivMapWalk(uiprivMap *m, void (*f)(void *key, void *value));
|
extern void uiprivMapWalk(uiprivMap *m, void (*f)(void *key, void *value));
|
||||||
|
extern void uiprivMapWalkWithData(uiprivMap *m, void *data, void (*f)(void *key, void *value, void *data));
|
||||||
extern void uiprivMapReset(uiprivMap *m);
|
extern void uiprivMapReset(uiprivMap *m);
|
||||||
|
|
||||||
// menu.m
|
// menu.m
|
||||||
|
@ -110,6 +111,7 @@ extern int uiprivSendAreaEvents(NSEvent *);
|
||||||
// areaevents.m
|
// areaevents.m
|
||||||
extern BOOL uiprivFromKeycode(unsigned short keycode, uiAreaKeyEvent *ke);
|
extern BOOL uiprivFromKeycode(unsigned short keycode, uiAreaKeyEvent *ke);
|
||||||
extern BOOL uiprivKeycodeModifier(unsigned short keycode, uiModifiers *mod);
|
extern BOOL uiprivKeycodeModifier(unsigned short keycode, uiModifiers *mod);
|
||||||
|
extern uiModifiers parseModifiers(NSEvent *e);
|
||||||
|
|
||||||
// draw.m
|
// draw.m
|
||||||
extern uiDrawContext *uiprivDrawNewContext(CGContextRef, CGFloat);
|
extern uiDrawContext *uiprivDrawNewContext(CGContextRef, CGFloat);
|
||||||
|
|
12
ui.h
12
ui.h
|
@ -45,6 +45,12 @@ _UI_ENUM(uiForEach) {
|
||||||
uiForEachStop,
|
uiForEachStop,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct uiArea uiArea;
|
||||||
|
typedef struct uiAreaHandler uiAreaHandler;
|
||||||
|
typedef struct uiAreaDrawParams uiAreaDrawParams;
|
||||||
|
typedef struct uiAreaMouseEvent uiAreaMouseEvent;
|
||||||
|
typedef struct uiAreaKeyEvent uiAreaKeyEvent;
|
||||||
|
|
||||||
typedef struct uiInitOptions uiInitOptions;
|
typedef struct uiInitOptions uiInitOptions;
|
||||||
|
|
||||||
struct uiInitOptions {
|
struct uiInitOptions {
|
||||||
|
@ -162,6 +168,7 @@ typedef struct uiEntry uiEntry;
|
||||||
_UI_EXTERN char *uiEntryText(uiEntry *e);
|
_UI_EXTERN char *uiEntryText(uiEntry *e);
|
||||||
_UI_EXTERN void uiEntrySetText(uiEntry *e, const char *text);
|
_UI_EXTERN void uiEntrySetText(uiEntry *e, const char *text);
|
||||||
_UI_EXTERN void uiEntryOnChanged(uiEntry *e, void (*f)(uiEntry *e, void *data), void *data);
|
_UI_EXTERN void uiEntryOnChanged(uiEntry *e, void (*f)(uiEntry *e, void *data), void *data);
|
||||||
|
_UI_EXTERN void uiEntryOnKeyEvent(uiEntry *e, int (*f)(uiEntry *e, uiAreaKeyEvent *event));
|
||||||
_UI_EXTERN int uiEntryReadOnly(uiEntry *e);
|
_UI_EXTERN int uiEntryReadOnly(uiEntry *e);
|
||||||
_UI_EXTERN void uiEntrySetReadOnly(uiEntry *e, int readonly);
|
_UI_EXTERN void uiEntrySetReadOnly(uiEntry *e, int readonly);
|
||||||
_UI_EXTERN uiEntry *uiNewEntry(void);
|
_UI_EXTERN uiEntry *uiNewEntry(void);
|
||||||
|
@ -297,11 +304,6 @@ _UI_EXTERN char *uiSaveFile(uiWindow *parent);
|
||||||
_UI_EXTERN void uiMsgBox(uiWindow *parent, const char *title, const char *description);
|
_UI_EXTERN void uiMsgBox(uiWindow *parent, const char *title, const char *description);
|
||||||
_UI_EXTERN void uiMsgBoxError(uiWindow *parent, const char *title, const char *description);
|
_UI_EXTERN void uiMsgBoxError(uiWindow *parent, const char *title, const char *description);
|
||||||
|
|
||||||
typedef struct uiArea uiArea;
|
|
||||||
typedef struct uiAreaHandler uiAreaHandler;
|
|
||||||
typedef struct uiAreaDrawParams uiAreaDrawParams;
|
|
||||||
typedef struct uiAreaMouseEvent uiAreaMouseEvent;
|
|
||||||
typedef struct uiAreaKeyEvent uiAreaKeyEvent;
|
|
||||||
|
|
||||||
typedef struct uiDrawContext uiDrawContext;
|
typedef struct uiDrawContext uiDrawContext;
|
||||||
|
|
||||||
|
|
122
unix/area.c
122
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,100 +297,15 @@ 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.Key = 0;
|
|
||||||
ke.ExtKey = 0;
|
|
||||||
ke.Modifier = 0;
|
|
||||||
|
|
||||||
state = translateModifiers(e->state, e->window);
|
|
||||||
ke.Modifiers = toModifiers(state);
|
|
||||||
|
|
||||||
ke.Up = up;
|
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;
|
|
||||||
|
|
||||||
keyFound:
|
|
||||||
return (*(a->ah->KeyEvent))(a->ah, a, &ke);
|
return (*(a->ah->KeyEvent))(a->ah, a, &ke);
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -1,26 +1,10 @@
|
||||||
// 8 september 2015
|
// 8 september 2015
|
||||||
#include "uipriv_windows.hpp"
|
#include "uipriv_windows.hpp"
|
||||||
#include "area.hpp"
|
#include "area.hpp"
|
||||||
|
#include "keyboard.hpp"
|
||||||
|
|
||||||
// TODO https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/multimedia/DirectWrite/PadWrite/TextEditor.cpp notes on explicit RTL handling under MirrorXCoordinate(); also in areadraw.cpp too?
|
// TODO https://github.com/Microsoft/Windows-classic-samples/blob/master/Samples/Win7Samples/multimedia/DirectWrite/PadWrite/TextEditor.cpp notes on explicit RTL handling under MirrorXCoordinate(); also in areadraw.cpp too?
|
||||||
|
|
||||||
static uiModifiers getModifiers(void)
|
|
||||||
{
|
|
||||||
uiModifiers m = 0;
|
|
||||||
|
|
||||||
if ((GetKeyState(VK_CONTROL) & 0x80) != 0)
|
|
||||||
m |= uiModifierCtrl;
|
|
||||||
if ((GetKeyState(VK_MENU) & 0x80) != 0)
|
|
||||||
m |= uiModifierAlt;
|
|
||||||
if ((GetKeyState(VK_SHIFT) & 0x80) != 0)
|
|
||||||
m |= uiModifierShift;
|
|
||||||
if ((GetKeyState(VK_LWIN) & 0x80) != 0)
|
|
||||||
m |= uiModifierSuper;
|
|
||||||
if ((GetKeyState(VK_RWIN) & 0x80) != 0)
|
|
||||||
m |= uiModifierSuper;
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Windows doesn't natively support mouse crossing events.
|
Windows doesn't natively support mouse crossing events.
|
||||||
|
|
||||||
|
@ -177,81 +161,6 @@ static void onMouseLeft(uiArea *a)
|
||||||
uiprivClickCounterReset(&(a->cc));
|
uiprivClickCounterReset(&(a->cc));
|
||||||
}
|
}
|
||||||
|
|
||||||
// we use VK_SNAPSHOT as a sentinel because libui will never support the print screen key; that key belongs to the user
|
|
||||||
struct extkeymap {
|
|
||||||
WPARAM vk;
|
|
||||||
uiExtKey extkey;
|
|
||||||
};
|
|
||||||
|
|
||||||
// all mappings come from GLFW - https://github.com/glfw/glfw/blob/master/src/win32_window.c#L152
|
|
||||||
static const struct extkeymap numpadExtKeys[] = {
|
|
||||||
{ VK_HOME, uiExtKeyN7 },
|
|
||||||
{ VK_UP, uiExtKeyN8 },
|
|
||||||
{ VK_PRIOR, uiExtKeyN9 },
|
|
||||||
{ VK_LEFT, uiExtKeyN4 },
|
|
||||||
{ VK_CLEAR, uiExtKeyN5 },
|
|
||||||
{ VK_RIGHT, uiExtKeyN6 },
|
|
||||||
{ VK_END, uiExtKeyN1 },
|
|
||||||
{ VK_DOWN, uiExtKeyN2 },
|
|
||||||
{ VK_NEXT, uiExtKeyN3 },
|
|
||||||
{ VK_INSERT, uiExtKeyN0 },
|
|
||||||
{ VK_DELETE, uiExtKeyNDot },
|
|
||||||
{ VK_SNAPSHOT, 0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct extkeymap extKeys[] = {
|
|
||||||
{ VK_ESCAPE, uiExtKeyEscape },
|
|
||||||
{ VK_INSERT, uiExtKeyInsert },
|
|
||||||
{ VK_DELETE, uiExtKeyDelete },
|
|
||||||
{ VK_HOME, uiExtKeyHome },
|
|
||||||
{ VK_END, uiExtKeyEnd },
|
|
||||||
{ VK_PRIOR, uiExtKeyPageUp },
|
|
||||||
{ VK_NEXT, uiExtKeyPageDown },
|
|
||||||
{ VK_UP, uiExtKeyUp },
|
|
||||||
{ VK_DOWN, uiExtKeyDown },
|
|
||||||
{ VK_LEFT, uiExtKeyLeft },
|
|
||||||
{ VK_RIGHT, uiExtKeyRight },
|
|
||||||
{ VK_F1, uiExtKeyF1 },
|
|
||||||
{ VK_F2, uiExtKeyF2 },
|
|
||||||
{ VK_F3, uiExtKeyF3 },
|
|
||||||
{ VK_F4, uiExtKeyF4 },
|
|
||||||
{ VK_F5, uiExtKeyF5 },
|
|
||||||
{ VK_F6, uiExtKeyF6 },
|
|
||||||
{ VK_F7, uiExtKeyF7 },
|
|
||||||
{ VK_F8, uiExtKeyF8 },
|
|
||||||
{ VK_F9, uiExtKeyF9 },
|
|
||||||
{ VK_F10, uiExtKeyF10 },
|
|
||||||
{ VK_F11, uiExtKeyF11 },
|
|
||||||
{ VK_F12, uiExtKeyF12 },
|
|
||||||
// numpad numeric keys and . are handled in common/areaevents.c
|
|
||||||
// numpad enter is handled in code below
|
|
||||||
{ VK_ADD, uiExtKeyNAdd },
|
|
||||||
{ VK_SUBTRACT, uiExtKeyNSubtract },
|
|
||||||
{ VK_MULTIPLY, uiExtKeyNMultiply },
|
|
||||||
{ VK_DIVIDE, uiExtKeyNDivide },
|
|
||||||
{ VK_SNAPSHOT, 0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct {
|
|
||||||
WPARAM vk;
|
|
||||||
uiModifiers mod;
|
|
||||||
} modKeys[] = {
|
|
||||||
// even if the separate left/right aren't necessary, have them here anyway, just to be safe
|
|
||||||
{ VK_CONTROL, uiModifierCtrl },
|
|
||||||
{ VK_LCONTROL, uiModifierCtrl },
|
|
||||||
{ VK_RCONTROL, uiModifierCtrl },
|
|
||||||
{ VK_MENU, uiModifierAlt },
|
|
||||||
{ VK_LMENU, uiModifierAlt },
|
|
||||||
{ VK_RMENU, uiModifierAlt },
|
|
||||||
{ VK_SHIFT, uiModifierShift },
|
|
||||||
{ VK_LSHIFT, uiModifierShift },
|
|
||||||
{ VK_RSHIFT, uiModifierShift },
|
|
||||||
// there's no combined Windows key virtual-key code as there is with the others
|
|
||||||
{ VK_LWIN, uiModifierSuper },
|
|
||||||
{ VK_RWIN, uiModifierSuper },
|
|
||||||
{ VK_SNAPSHOT, 0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
static int areaKeyEvent(uiArea *a, int up, WPARAM wParam, LPARAM lParam)
|
static int areaKeyEvent(uiArea *a, int up, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
uiAreaKeyEvent ke;
|
uiAreaKeyEvent ke;
|
||||||
|
@ -261,9 +170,7 @@ static int areaKeyEvent(uiArea *a, int up, WPARAM wParam, LPARAM lParam)
|
||||||
ke.Key = 0;
|
ke.Key = 0;
|
||||||
ke.ExtKey = 0;
|
ke.ExtKey = 0;
|
||||||
ke.Modifier = 0;
|
ke.Modifier = 0;
|
||||||
|
|
||||||
ke.Modifiers = getModifiers();
|
ke.Modifiers = getModifiers();
|
||||||
|
|
||||||
ke.Up = up;
|
ke.Up = up;
|
||||||
|
|
||||||
// the numeric keypad keys when Num Lock is off are considered left-hand keys as the separate navigation buttons were added later
|
// the numeric keypad keys when Num Lock is off are considered left-hand keys as the separate navigation buttons were added later
|
||||||
|
@ -282,25 +189,7 @@ static int areaKeyEvent(uiArea *a, int up, WPARAM wParam, LPARAM lParam)
|
||||||
goto keyFound;
|
goto keyFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
// okay, those above cases didn't match anything
|
if (fillKeyEvent(ke, wParam, lParam))
|
||||||
// first try the extended keys
|
|
||||||
for (i = 0; extKeys[i].vk != VK_SNAPSHOT; i++)
|
|
||||||
if (extKeys[i].vk == wParam) {
|
|
||||||
ke.ExtKey = extKeys[i].extkey;
|
|
||||||
goto keyFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
// then try modifier keys
|
|
||||||
for (i = 0; modKeys[i].vk != VK_SNAPSHOT; i++)
|
|
||||||
if (modKeys[i].vk == wParam) {
|
|
||||||
ke.Modifier = modKeys[i].mod;
|
|
||||||
// and don't include the key in Modifiers
|
|
||||||
ke.Modifiers &= ~ke.Modifier;
|
|
||||||
goto keyFound;
|
|
||||||
}
|
|
||||||
|
|
||||||
// and finally everything else
|
|
||||||
if (uiprivFromScancode((lParam >> 16) & 0xFF, &ke))
|
|
||||||
goto keyFound;
|
goto keyFound;
|
||||||
|
|
||||||
// not a supported key, assume unhandled
|
// not a supported key, assume unhandled
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// 8 april 2015
|
// 8 april 2015
|
||||||
#include "uipriv_windows.hpp"
|
#include "uipriv_windows.hpp"
|
||||||
|
#include "keyboard.hpp"
|
||||||
|
|
||||||
struct uiEntry {
|
struct uiEntry {
|
||||||
uiWindowsControl c;
|
uiWindowsControl c;
|
||||||
|
@ -7,8 +8,46 @@ struct uiEntry {
|
||||||
void (*onChanged)(uiEntry *, void *);
|
void (*onChanged)(uiEntry *, void *);
|
||||||
void *onChangedData;
|
void *onChangedData;
|
||||||
BOOL inhibitChanged;
|
BOOL inhibitChanged;
|
||||||
|
int (*onKeyEvent)(uiEntry *, uiAreaKeyEvent *);
|
||||||
|
void *self;
|
||||||
|
WNDPROC native_wndproc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static LRESULT CALLBACK entryWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
BOOL righthand = FALSE;
|
||||||
|
uiAreaKeyEvent ke;
|
||||||
|
ke.Key = 0;
|
||||||
|
ke.ExtKey = 0;
|
||||||
|
ke.Modifier = 0;
|
||||||
|
ke.Modifiers = getModifiers();
|
||||||
|
ke.Up = 0;
|
||||||
|
|
||||||
|
int (*onKeyEvent)(uiEntry *, uiAreaKeyEvent *) = (int (*)(uiEntry *, uiAreaKeyEvent *))GetProp(hwnd, L"ON_KEY_EVENT");
|
||||||
|
uiEntry *self = (uiEntry *)GetProp(hwnd, L"SELF");
|
||||||
|
|
||||||
|
switch (uMsg)
|
||||||
|
{
|
||||||
|
case WM_GETDLGCODE:
|
||||||
|
return DLGC_HASSETSEL | DLGC_WANTALLKEYS;
|
||||||
|
break;
|
||||||
|
case WM_KEYUP:
|
||||||
|
ke.Up = 1;
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
if (onKeyEvent) {
|
||||||
|
fillKeyEvent(ke, wParam, lParam);
|
||||||
|
if ((*onKeyEvent)(self, &ke)) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
WNDPROC native_wndproc = (WNDPROC)GetProp(hwnd, L"NATIVE_WNDPROC");
|
||||||
|
return CallWindowProcW(native_wndproc, hwnd, uMsg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
static BOOL onWM_COMMAND(uiControl *c, HWND hwnd, WORD code, LRESULT *lResult)
|
static BOOL onWM_COMMAND(uiControl *c, HWND hwnd, WORD code, LRESULT *lResult)
|
||||||
{
|
{
|
||||||
uiEntry *e = uiEntry(c);
|
uiEntry *e = uiEntry(c);
|
||||||
|
@ -26,6 +65,11 @@ static void uiEntryDestroy(uiControl *c)
|
||||||
{
|
{
|
||||||
uiEntry *e = uiEntry(c);
|
uiEntry *e = uiEntry(c);
|
||||||
|
|
||||||
|
(WNDPROC)SetWindowLongPtrW(e->hwnd, GWLP_WNDPROC, (LONG_PTR)e->native_wndproc);
|
||||||
|
RemoveProp(e->hwnd, L"NATIVE_WNDPROC");
|
||||||
|
RemoveProp(e->hwnd, L"ON_KEY_EVENT");
|
||||||
|
RemoveProp(e->hwnd, L"SELF");
|
||||||
|
|
||||||
uiWindowsUnregisterWM_COMMANDHandler(e->hwnd);
|
uiWindowsUnregisterWM_COMMANDHandler(e->hwnd);
|
||||||
uiWindowsEnsureDestroyWindow(e->hwnd);
|
uiWindowsEnsureDestroyWindow(e->hwnd);
|
||||||
uiFreeControl(uiControl(e));
|
uiFreeControl(uiControl(e));
|
||||||
|
@ -56,6 +100,13 @@ static void defaultOnChanged(uiEntry *e, void *data)
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int defaultOnKeyEvent(uiEntry *e, uiAreaKeyEvent *event)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
char *uiEntryText(uiEntry *e)
|
char *uiEntryText(uiEntry *e)
|
||||||
{
|
{
|
||||||
return uiWindowsWindowText(e->hwnd);
|
return uiWindowsWindowText(e->hwnd);
|
||||||
|
@ -76,6 +127,12 @@ 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;
|
||||||
|
SetProp(e->hwnd, L"ON_KEY_EVENT", (HGLOBAL)(f));
|
||||||
|
}
|
||||||
|
|
||||||
int uiEntryReadOnly(uiEntry *e)
|
int uiEntryReadOnly(uiEntry *e)
|
||||||
{
|
{
|
||||||
return (getStyle(e->hwnd) & ES_READONLY) != 0;
|
return (getStyle(e->hwnd) & ES_READONLY) != 0;
|
||||||
|
@ -105,7 +162,13 @@ static uiEntry *finishNewEntry(DWORD style)
|
||||||
TRUE);
|
TRUE);
|
||||||
|
|
||||||
uiWindowsRegisterWM_COMMANDHandler(e->hwnd, onWM_COMMAND, uiControl(e));
|
uiWindowsRegisterWM_COMMANDHandler(e->hwnd, onWM_COMMAND, uiControl(e));
|
||||||
|
|
||||||
|
e->native_wndproc = (WNDPROC)SetWindowLongPtrW(e->hwnd, GWLP_WNDPROC, (LONG_PTR)entryWndProc);
|
||||||
|
SetProp(e->hwnd, L"NATIVE_WNDPROC", (HGLOBAL)e->native_wndproc);
|
||||||
|
SetProp(e->hwnd, L"SELF", (HGLOBAL)e);
|
||||||
|
|
||||||
uiEntryOnChanged(e, defaultOnChanged, NULL);
|
uiEntryOnChanged(e, defaultOnChanged, NULL);
|
||||||
|
uiEntryOnKeyEvent(e, defaultOnKeyEvent);
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// we use VK_SNAPSHOT as a sentinel because libui will never support the print screen key; that key belongs to the user
|
||||||
|
struct extkeymap {
|
||||||
|
WPARAM vk;
|
||||||
|
uiExtKey extkey;
|
||||||
|
};
|
||||||
|
|
||||||
|
// all mappings come from GLFW - https://github.com/glfw/glfw/blob/master/src/win32_window.c#L152
|
||||||
|
static const struct extkeymap numpadExtKeys[] = {
|
||||||
|
{ VK_HOME, uiExtKeyN7 },
|
||||||
|
{ VK_UP, uiExtKeyN8 },
|
||||||
|
{ VK_PRIOR, uiExtKeyN9 },
|
||||||
|
{ VK_LEFT, uiExtKeyN4 },
|
||||||
|
{ VK_CLEAR, uiExtKeyN5 },
|
||||||
|
{ VK_RIGHT, uiExtKeyN6 },
|
||||||
|
{ VK_END, uiExtKeyN1 },
|
||||||
|
{ VK_DOWN, uiExtKeyN2 },
|
||||||
|
{ VK_NEXT, uiExtKeyN3 },
|
||||||
|
{ VK_INSERT, uiExtKeyN0 },
|
||||||
|
{ VK_DELETE, uiExtKeyNDot },
|
||||||
|
{ VK_SNAPSHOT, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct extkeymap extKeys[] = {
|
||||||
|
{ VK_ESCAPE, uiExtKeyEscape },
|
||||||
|
{ VK_INSERT, uiExtKeyInsert },
|
||||||
|
{ VK_DELETE, uiExtKeyDelete },
|
||||||
|
{ VK_HOME, uiExtKeyHome },
|
||||||
|
{ VK_END, uiExtKeyEnd },
|
||||||
|
{ VK_PRIOR, uiExtKeyPageUp },
|
||||||
|
{ VK_NEXT, uiExtKeyPageDown },
|
||||||
|
{ VK_UP, uiExtKeyUp },
|
||||||
|
{ VK_DOWN, uiExtKeyDown },
|
||||||
|
{ VK_LEFT, uiExtKeyLeft },
|
||||||
|
{ VK_RIGHT, uiExtKeyRight },
|
||||||
|
{ VK_F1, uiExtKeyF1 },
|
||||||
|
{ VK_F2, uiExtKeyF2 },
|
||||||
|
{ VK_F3, uiExtKeyF3 },
|
||||||
|
{ VK_F4, uiExtKeyF4 },
|
||||||
|
{ VK_F5, uiExtKeyF5 },
|
||||||
|
{ VK_F6, uiExtKeyF6 },
|
||||||
|
{ VK_F7, uiExtKeyF7 },
|
||||||
|
{ VK_F8, uiExtKeyF8 },
|
||||||
|
{ VK_F9, uiExtKeyF9 },
|
||||||
|
{ VK_F10, uiExtKeyF10 },
|
||||||
|
{ VK_F11, uiExtKeyF11 },
|
||||||
|
{ VK_F12, uiExtKeyF12 },
|
||||||
|
// numpad numeric keys and . are handled in common/areaevents.c
|
||||||
|
// numpad enter is handled in code below
|
||||||
|
{ VK_ADD, uiExtKeyNAdd },
|
||||||
|
{ VK_SUBTRACT, uiExtKeyNSubtract },
|
||||||
|
{ VK_MULTIPLY, uiExtKeyNMultiply },
|
||||||
|
{ VK_DIVIDE, uiExtKeyNDivide },
|
||||||
|
{ VK_SNAPSHOT, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
WPARAM vk;
|
||||||
|
uiModifiers mod;
|
||||||
|
} modKeys[] = {
|
||||||
|
// even if the separate left/right aren't necessary, have them here anyway, just to be safe
|
||||||
|
{ VK_CONTROL, uiModifierCtrl },
|
||||||
|
{ VK_LCONTROL, uiModifierCtrl },
|
||||||
|
{ VK_RCONTROL, uiModifierCtrl },
|
||||||
|
{ VK_MENU, uiModifierAlt },
|
||||||
|
{ VK_LMENU, uiModifierAlt },
|
||||||
|
{ VK_RMENU, uiModifierAlt },
|
||||||
|
{ VK_SHIFT, uiModifierShift },
|
||||||
|
{ VK_LSHIFT, uiModifierShift },
|
||||||
|
{ VK_RSHIFT, uiModifierShift },
|
||||||
|
// there's no combined Windows key virtual-key code as there is with the others
|
||||||
|
{ VK_LWIN, uiModifierSuper },
|
||||||
|
{ VK_RWIN, uiModifierSuper },
|
||||||
|
{ VK_SNAPSHOT, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static uiModifiers getModifiers(void)
|
||||||
|
{
|
||||||
|
uiModifiers m = 0;
|
||||||
|
|
||||||
|
if ((GetKeyState(VK_CONTROL) & 0x80) != 0)
|
||||||
|
m |= uiModifierCtrl;
|
||||||
|
if ((GetKeyState(VK_MENU) & 0x80) != 0)
|
||||||
|
m |= uiModifierAlt;
|
||||||
|
if ((GetKeyState(VK_SHIFT) & 0x80) != 0)
|
||||||
|
m |= uiModifierShift;
|
||||||
|
if ((GetKeyState(VK_LWIN) & 0x80) != 0)
|
||||||
|
m |= uiModifierSuper;
|
||||||
|
if ((GetKeyState(VK_RWIN) & 0x80) != 0)
|
||||||
|
m |= uiModifierSuper;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static BOOL fillKeyEvent(uiAreaKeyEvent &ke, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; extKeys[i].vk != VK_SNAPSHOT; i++) {
|
||||||
|
if (extKeys[i].vk == wParam) {
|
||||||
|
ke.ExtKey = extKeys[i].extkey;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; modKeys[i].vk != VK_SNAPSHOT; i++) {
|
||||||
|
if (modKeys[i].vk == wParam) {
|
||||||
|
ke.Modifier = modKeys[i].mod;
|
||||||
|
ke.Modifiers &= ~ke.Modifier;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO the original code only did this if ke.Modifiers == 0 - why?
|
||||||
|
if (uiprivFromScancode((lParam >> 16) & 0xFF, &ke)) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
Loading…
Reference in New Issue