app: [macOS] propagate unhandled key shortcuts

By propagation, we restore the system behaviour for shortcuts the program
don't want, for example the system beep.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2025-01-13 23:58:35 +01:00
parent 8107ec2206
commit fe4bf00c70
2 changed files with 52 additions and 23 deletions
+49 -22
View File
@@ -354,9 +354,14 @@ type window struct {
config Config config Config
keysDown map[key.Name]struct{} keysDown map[key.Name]struct{}
// doCommandBySelectorCalled tracks whether a call to // cmdKeys is for storing the current key event while
// interpretKeys resulted in a callback. // waiting for a doCommandBySelector.
doCommandBySelectorCalled bool cmdKeys cmdKeys
}
type cmdKeys struct {
eventStr string
eventMods key.Modifiers
} }
// launched is closed when applicationDidFinishLaunching is called. // launched is closed when applicationDidFinishLaunching is called.
@@ -558,47 +563,64 @@ func (w *window) runOnMain(f func()) {
//export gio_onKeys //export gio_onKeys
func gio_onKeys(h C.uintptr_t, event C.CFTypeRef, cstr C.CFTypeRef, ti C.double, mods C.NSUInteger, keyDown C.bool) { func gio_onKeys(h C.uintptr_t, event C.CFTypeRef, cstr C.CFTypeRef, ti C.double, mods C.NSUInteger, keyDown C.bool) {
w := windowFor(h) w := windowFor(h)
if w.keysDown == nil {
w.keysDown = make(map[key.Name]struct{})
}
str := nsstringToString(cstr) str := nsstringToString(cstr)
kmods := convertMods(mods) kmods := convertMods(mods)
ks := key.Release ks := key.Release
if keyDown { if keyDown {
ks = key.Press ks = key.Press
w.doCommandBySelectorCalled = false w.cmdKeys.eventStr = str
w.cmdKeys.eventMods = kmods
C.interpretKeyEvents(w.view, event) C.interpretKeyEvents(w.view, event)
} }
for _, k := range str { for _, k := range str {
if n, ok := convertKey(k); ok { if n, ok := convertKey(k); ok {
ke := key.Event{
Name: n,
Modifiers: kmods,
State: ks,
}
if keyDown { if keyDown {
if !w.doCommandBySelectorCalled { w.keysDown[ke.Name] = struct{}{}
if _, isCmd := convertCommandKey(k); isCmd { if _, isCmd := convertCommandKey(k); isCmd || kmods.Contain(key.ModCommand) {
// doCommandBySelector was not called, // doCommandBySelector already processed the event.
// so this event was swallowed by an IME. return
return
}
} }
if w.keysDown == nil {
w.keysDown = make(map[key.Name]struct{})
}
w.keysDown[n] = struct{}{}
} else { } else {
if _, pressed := w.keysDown[n]; !pressed { if _, pressed := w.keysDown[n]; !pressed {
continue continue
} }
delete(w.keysDown, n) delete(w.keysDown, n)
} }
w.ProcessEvent(key.Event{ w.ProcessEvent(ke)
Name: n,
Modifiers: kmods,
State: ks,
})
} }
} }
} }
//export gio_onCommandBySelector //export gio_onCommandBySelector
func gio_onCommandBySelector(h C.uintptr_t) { func gio_onCommandBySelector(h C.uintptr_t) C.bool {
w := windowFor(h) w := windowFor(h)
w.doCommandBySelectorCalled = true ev := w.cmdKeys
w.cmdKeys = cmdKeys{}
handled := false
for _, k := range ev.eventStr {
n, ok := convertCommandKey(k)
if !ok && ev.eventMods.Contain(key.ModCommand) {
n, ok = convertKey(k)
}
if !ok {
continue
}
ke := key.Event{
Name: n,
Modifiers: ev.eventMods,
State: key.Press,
}
handled = w.processEvent(ke) || handled
}
return C.bool(handled)
} }
//export gio_onFlagsChanged //export gio_onFlagsChanged
@@ -905,8 +927,13 @@ func (w *window) draw() {
} }
func (w *window) ProcessEvent(e event.Event) { func (w *window) ProcessEvent(e event.Event) {
w.w.ProcessEvent(e) w.processEvent(e)
}
func (w *window) processEvent(e event.Event) bool {
handled := w.w.ProcessEvent(e)
w.loop.FlushEvents() w.loop.FlushEvents()
return handled
} }
func (w *window) Event() event.Event { func (w *window) Event() event.Event {
+3 -1
View File
@@ -147,7 +147,9 @@ static void handleMouse(GioView *view, NSEvent *event, int typ, CGFloat dx, CGFl
gio_onText(self.handle, (__bridge CFTypeRef)string); gio_onText(self.handle, (__bridge CFTypeRef)string);
} }
- (void)doCommandBySelector:(SEL)action { - (void)doCommandBySelector:(SEL)action {
gio_onCommandBySelector(self.handle); if (!gio_onCommandBySelector(self.handle)) {
[super doCommandBySelector:action];
}
} }
- (BOOL)hasMarkedText { - (BOOL)hasMarkedText {
int res = gio_hasMarkedText(self.handle); int res = gio_hasMarkedText(self.handle);