1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-27 15:29:34 +00:00

Rationalises protocol for application-level event theft.

This commit is contained in:
Thomas Harte 2019-09-24 22:31:20 -04:00
parent 298694a881
commit 7112f0336c
3 changed files with 37 additions and 63 deletions

View File

@ -11,20 +11,22 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
@protocol CSApplicationKeyboardEventDelegate @class CSApplication;
- (void)sendEvent:(nonnull NSEvent *)event;
@protocol CSApplicationEventDelegate
- (BOOL)application:(nonnull CSApplication *)application shouldSendEvent:(nonnull NSEvent *)event;
@end @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, If conected, an eventDelegate will be offered all application events prior to their propagation
@c NSEventTypeKeyDown and @c NSEventTypeFlagsChanged will be diverted to it into the application proper. It may opt to remove those events from the queue. This primarily
rather than passed through the usual processing. As a result keyboard shortcuts and assistive provides a way to divert things like the command key that will otherwise trigger menu
dialogue navigations won't work. shortcuts, for periods when it is appropriate to do so.
*/ */
@interface CSApplication: NSApplication @interface CSApplication: NSApplication
@property(nonatomic, weak, nullable) id<CSApplicationKeyboardEventDelegate> keyboardEventDelegate; @property(nonatomic, weak, nullable) id<CSApplicationEventDelegate> eventDelegate;
@end @end

View File

@ -11,27 +11,10 @@
@implementation CSApplication @implementation CSApplication
- (void)sendEvent:(NSEvent *)event { - (void)sendEvent:(NSEvent *)event {
// The only reason to capture events here rather than at the window or view // Send the event unless an event delegate says otherwise.
// is to divert key combinations such as command+w or command+q in the few if(!self.eventDelegate || [self.eventDelegate application:self shouldSendEvent:event]) {
// 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]; [super sendEvent:event];
} }
} }
@end @end

View File

@ -11,7 +11,7 @@
@import CoreVideo; @import CoreVideo;
@import GLKit; @import GLKit;
@interface CSOpenGLView () <NSDraggingDestination, CSApplicationKeyboardEventDelegate> @interface CSOpenGLView () <NSDraggingDestination, CSApplicationEventDelegate>
@end @end
@implementation CSOpenGLView { @implementation CSOpenGLView {
@ -140,17 +140,15 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
return YES; return YES;
} }
- (void)propagateKeyboardEvent:(NSEvent *)event { - (void)keyDown:(NSEvent *)event {
switch(event.type) {
default: break;
case kCGEventKeyDown:
[self.responderDelegate keyDown:event]; [self.responderDelegate keyDown:event];
break; }
case kCGEventKeyUp:
- (void)keyUp:(NSEvent *)event {
[self.responderDelegate keyUp:event]; [self.responderDelegate keyUp:event];
break; }
case kCGEventFlagsChanged:
- (void)flagsChanged:(NSEvent *)event {
// Release the mouse upon a control + command. // Release the mouse upon a control + command.
if(_mouseIsCaptured && if(_mouseIsCaptured &&
event.modifierFlags & NSEventModifierFlagControl && event.modifierFlags & NSEventModifierFlagControl &&
@ -159,26 +157,17 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
} }
[self.responderDelegate flagsChanged:event]; [self.responderDelegate flagsChanged:event];
break; }
- (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)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];
}
- (void)paste:(id)sender { - (void)paste:(id)sender {
[self.responderDelegate paste:sender]; [self.responderDelegate paste:sender];
} }
@ -245,7 +234,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
CGAssociateMouseAndMouseCursorPosition(true); CGAssociateMouseAndMouseCursorPosition(true);
[NSCursor unhide]; [NSCursor unhide];
[self.delegate openGLViewDidReleaseMouse:self]; [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); CGAssociateMouseAndMouseCursorPosition(false);
[self.delegate openGLViewDidCaptureMouse:self]; [self.delegate openGLViewDidCaptureMouse:self];
if(self.shouldUsurpCommand) { 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 // Don't report the first click to the delegate; treat that as merely