diff --git a/darwin/entry.m b/darwin/entry.m index 99630264..9d9bbb07 100644 --- a/darwin/entry.m +++ b/darwin/entry.m @@ -59,6 +59,7 @@ struct uiEntry { NSTextField *textfield; void (*onChanged)(uiEntry *, void *); void *onChangedData; + int (*onKeyEvent)(uiEntry *, uiAreaKeyEvent *); }; static BOOL isSearchField(NSTextField *tf) @@ -66,8 +67,37 @@ static BOOL isSearchField(NSTextField *tf) return [tf isKindOfClass:[NSSearchField class]]; } +static 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; +} + +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 { uiprivMap *entries; + id eventMonitor; } - (void)controlTextDidChange:(NSNotification *)note; - (IBAction)onSearch:(id)sender; @@ -82,11 +112,27 @@ static BOOL isSearchField(NSTextField *tf) self = [super init]; if (self) self->entries = uiprivNewMap(); + + NSEvent* (^eventHandler)(NSEvent*) = ^(NSEvent *theEvent) { + uiAreaKeyEvent ke; + ke.Key = 0; + ke.ExtKey = 0; + ke.Modifier = 0; + ke.Modifiers = parseModifiers(theEvent); + + if (uiprivFromKeycode([theEvent keyCode], &ke)) + uiprivMapWalkWithData(self->entries, &ke, triggerOnKeyEvent); + + return theEvent; + }; + eventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSKeyDownMask handler:eventHandler]; + return self; } - (void)dealloc { + [NSEvent removeMonitor:eventMonitor]; uiprivMapDestroy(self->entries); [super dealloc]; } @@ -155,6 +201,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 [e->textfield isEditable] == NO; @@ -175,6 +226,12 @@ static void defaultOnChanged(uiEntry *e, void *data) // 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 :/ void uiprivFinishNewTextField(NSTextField *t, BOOL isEntry) { @@ -220,6 +277,7 @@ static uiEntry *finishNewEntry(Class class) } [entryDelegate registerEntry:e]; uiEntryOnChanged(e, defaultOnChanged, NULL); + uiEntryOnKeyEvent(e, defaultOnKeyEvent); return e; } diff --git a/darwin/map.m b/darwin/map.m index a9774170..aac7f6f3 100644 --- a/darwin/map.m +++ b/darwin/map.m @@ -55,6 +55,20 @@ void uiprivMapWalk(uiprivMap *m, void (*f)(void *key, void *value)) 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) { NSResetMapTable(m->m); diff --git a/darwin/uipriv_darwin.h b/darwin/uipriv_darwin.h index 5d50f623..8e43fb5a 100644 --- a/darwin/uipriv_darwin.h +++ b/darwin/uipriv_darwin.h @@ -31,6 +31,7 @@ extern void *uiprivMapGet(uiprivMap *m, void *key); extern void uiprivMapSet(uiprivMap *m, void *key, void *value); extern void uiprivMapDelete(uiprivMap *m, void *key); 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); // menu.m