diff --git a/OSBindings/Mac/Clock Signal/CSApplication.h b/OSBindings/Mac/Clock Signal/CSApplication.h index 76a81a56a..e7fbe4734 100644 --- a/OSBindings/Mac/Clock Signal/CSApplication.h +++ b/OSBindings/Mac/Clock Signal/CSApplication.h @@ -11,20 +11,22 @@ #import -@protocol CSApplicationKeyboardEventDelegate -- (void)sendEvent:(nonnull NSEvent *)event; +@class CSApplication; + +@protocol CSApplicationEventDelegate +- (BOOL)application:(nonnull CSApplication *)application shouldSendEvent:(nonnull NSEvent *)event; @end /*! - CSApplication differs from NSApplication in only one regard: it supports a keyboardEventDelegate. + CSApplication differs from NSApplication in only one regard: it supports an eventDelegate. - If a keyboardEventDelegate is installed, all keyboard events — @c NSEventTypeKeyUp, - @c NSEventTypeKeyDown and @c NSEventTypeFlagsChanged — will be diverted to it - rather than passed through the usual processing. As a result keyboard shortcuts and assistive - dialogue navigations won't work. + If conected, an eventDelegate will be offered all application events prior to their propagation + into the application proper. It may opt to remove those events from the queue. This primarily + provides a way to divert things like the command key that will otherwise trigger menu + shortcuts, for periods when it is appropriate to do so. */ @interface CSApplication: NSApplication -@property(nonatomic, weak, nullable) id keyboardEventDelegate; +@property(nonatomic, weak, nullable) id eventDelegate; @end diff --git a/OSBindings/Mac/Clock Signal/CSApplication.m b/OSBindings/Mac/Clock Signal/CSApplication.m index 7769255c1..bd23938a0 100644 --- a/OSBindings/Mac/Clock Signal/CSApplication.m +++ b/OSBindings/Mac/Clock Signal/CSApplication.m @@ -11,27 +11,10 @@ @implementation CSApplication - (void)sendEvent:(NSEvent *)event { - // The only reason to capture events here rather than at the window or view - // is to divert key combinations such as command+w or command+q in the few - // occasions when the user would expect those to affect a running machine - // rather than to affect application state. - // - // Most obviously: when emulating a Macintosh, you'd expect command+q to - // quit the application inside the Macintosh, not to quit the emulator. - - switch(event.type) { - case NSEventTypeKeyUp: - case NSEventTypeKeyDown: - case NSEventTypeFlagsChanged: - if(self.keyboardEventDelegate) { - [self.keyboardEventDelegate sendEvent:event]; - return; - } - - default: - [super sendEvent:event]; + // Send the event unless an event delegate says otherwise. + if(!self.eventDelegate || [self.eventDelegate application:self shouldSendEvent:event]) { + [super sendEvent:event]; } - } @end diff --git a/OSBindings/Mac/Clock Signal/Views/CSOpenGLView.m b/OSBindings/Mac/Clock Signal/Views/CSOpenGLView.m index a41c07e9d..283f6e19b 100644 --- a/OSBindings/Mac/Clock Signal/Views/CSOpenGLView.m +++ b/OSBindings/Mac/Clock Signal/Views/CSOpenGLView.m @@ -11,7 +11,7 @@ @import CoreVideo; @import GLKit; -@interface CSOpenGLView () +@interface CSOpenGLView () @end @implementation CSOpenGLView { @@ -140,43 +140,32 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt return YES; } -- (void)propagateKeyboardEvent:(NSEvent *)event { - switch(event.type) { - default: break; +- (void)keyDown:(NSEvent *)event { + [self.responderDelegate keyDown:event]; +} - case kCGEventKeyDown: - [self.responderDelegate keyDown:event]; - break; - case kCGEventKeyUp: - [self.responderDelegate keyUp:event]; - break; - case kCGEventFlagsChanged: - // Release the mouse upon a control + command. - if(_mouseIsCaptured && - event.modifierFlags & NSEventModifierFlagControl && - event.modifierFlags & NSEventModifierFlagCommand) { - [self releaseMouse]; - } +- (void)keyUp:(NSEvent *)event { + [self.responderDelegate keyUp:event]; +} - [self.responderDelegate flagsChanged:event]; - break; +- (void)flagsChanged:(NSEvent *)event { + // Release the mouse upon a control + command. + if(_mouseIsCaptured && + event.modifierFlags & NSEventModifierFlagControl && + event.modifierFlags & NSEventModifierFlagCommand) { + [self releaseMouse]; } + + [self.responderDelegate flagsChanged:event]; } -- (void)keyDown:(NSEvent *)theEvent { - [self propagateKeyboardEvent:theEvent]; -} - -- (void)keyUp:(NSEvent *)theEvent { - [self propagateKeyboardEvent:theEvent]; -} - -- (void)flagsChanged:(NSEvent *)theEvent { - [self propagateKeyboardEvent:theEvent]; -} - -- (void)sendEvent:(NSEvent *)event { - [self propagateKeyboardEvent:event]; +- (BOOL)application:(nonnull CSApplication *)application shouldSendEvent:(nonnull NSEvent *)event { + switch(event.type) { + default: return YES; + case NSEventTypeKeyUp: [self keyUp:event]; return NO; + case NSEventTypeKeyDown: [self keyDown:event]; return NO; + case NSEventTypeFlagsChanged: [self flagsChanged:event]; return NO; + } } - (void)paste:(id)sender { @@ -245,7 +234,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt CGAssociateMouseAndMouseCursorPosition(true); [NSCursor unhide]; [self.delegate openGLViewDidReleaseMouse:self]; - ((CSApplication *)[NSApplication sharedApplication]).keyboardEventDelegate = nil; + ((CSApplication *)[NSApplication sharedApplication]).eventDelegate = nil; } } @@ -306,7 +295,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt CGAssociateMouseAndMouseCursorPosition(false); [self.delegate openGLViewDidCaptureMouse:self]; if(self.shouldUsurpCommand) { - ((CSApplication *)[NSApplication sharedApplication]).keyboardEventDelegate = self; + ((CSApplication *)[NSApplication sharedApplication]).eventDelegate = self; } // Don't report the first click to the delegate; treat that as merely