diff --git a/glfw/cocoa_init.m b/glfw/cocoa_init.m index 15a4b919f..2d883d084 100644 --- a/glfw/cocoa_init.m +++ b/glfw/cocoa_init.m @@ -26,7 +26,11 @@ #include "internal.h" #include // For MAXPATHLEN - +#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 + #define NSEventMaskKeyUp NSKeyUpMask + #define NSEventMaskKeyDown NSKeyDownMask + #define NSEventModifierFlagCommand NSCommandKeyMask +#endif // Change to our application bundle's resources directory, if present // @@ -274,17 +278,21 @@ static GLFWbool initializeTIS(void) return updateUnicodeDataNS(); } -@interface GLFWLayoutListener : NSObject +@interface GLFWHelper : NSObject @end -@implementation GLFWLayoutListener +@implementation GLFWHelper - (void)selectedKeyboardInputSourceChanged:(NSObject* )object { updateUnicodeDataNS(); } -@end +- (void)doNothing:(id)object +{ +} + +@end // GLFWHelper ////////////////////////////////////////////////////////////////////////// @@ -294,13 +302,53 @@ static GLFWbool initializeTIS(void) int _glfwPlatformInit(void) { _glfw.ns.autoreleasePool = [[NSAutoreleasePool alloc] init]; + _glfw.ns.helper = [[GLFWHelper alloc] init]; + [NSThread detachNewThreadSelector:@selector(doNothing:) + toTarget:_glfw.ns.helper + withObject:nil]; + + [NSApplication sharedApplication]; + + NSEvent* (^keydown_block)(NSEvent*) = ^ NSEvent* (NSEvent* event) + { + NSEventModifierFlags modifierFlags = [event modifierFlags]; + if (event.keyCode == kVK_Tab && (modifierFlags == NSEventModifierFlagControl || modifierFlags == (NSEventModifierFlagControl | NSEventModifierFlagShift))) { + // Cocoa swallows Ctrl+Tab to cycle between views + [[NSApp keyWindow].contentView keyDown:event]; + } + + return event; + }; + + NSEvent* (^keyup_block)(NSEvent*) = ^ NSEvent* (NSEvent* event) + { + NSEventModifierFlags modifierFlags = [event modifierFlags]; + if ([event modifierFlags] & NSEventModifierFlagCommand) { + // From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost + // This works around an AppKit bug, where key up events while holding + // down the command key don't get sent to the key window. + [[NSApp keyWindow] sendEvent:event]; + } + if (event.keyCode == kVK_Tab && (modifierFlags == NSEventModifierFlagControl || modifierFlags == (NSEventModifierFlagControl | NSEventModifierFlagShift))) { + // Cocoa swallows Ctrl+Tab to cycle between views + [[NSApp keyWindow].contentView keyUp:event]; + } + + return event; + }; + + _glfw.ns.keyUpMonitor = + [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp + handler:keyup_block]; + _glfw.ns.keyDownMonitor = + [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown + handler:keydown_block]; if (_glfw.hints.init.ns.chdir) changeToResourcesDirectory(); - _glfw.ns.listener = [[GLFWLayoutListener alloc] init]; [[NSNotificationCenter defaultCenter] - addObserver:_glfw.ns.listener + addObserver:_glfw.ns.helper selector:@selector(selectedKeyboardInputSourceChanged:) name:NSTextInputContextKeyboardSelectionDidChangeNotification object:nil]; @@ -345,17 +393,21 @@ void _glfwPlatformTerminate(void) _glfw.ns.delegate = nil; } - if (_glfw.ns.listener) + if (_glfw.ns.helper) { [[NSNotificationCenter defaultCenter] - removeObserver:_glfw.ns.listener + removeObserver:_glfw.ns.helper name:NSTextInputContextKeyboardSelectionDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] - removeObserver:_glfw.ns.listener]; - [_glfw.ns.listener release]; - _glfw.ns.listener = nil; + removeObserver:_glfw.ns.helper]; + [_glfw.ns.helper release]; + _glfw.ns.helper = nil; } + if (_glfw.ns.keyUpMonitor) + [NSEvent removeMonitor:_glfw.ns.keyUpMonitor]; + if (_glfw.ns.keyDownMonitor) + [NSEvent removeMonitor:_glfw.ns.keyDownMonitor]; free(_glfw.ns.clipboardString); diff --git a/glfw/cocoa_platform.h b/glfw/cocoa_platform.h index 1f1542062..0f96e5d29 100644 --- a/glfw/cocoa_platform.h +++ b/glfw/cocoa_platform.h @@ -118,7 +118,9 @@ typedef struct _GLFWlibraryNS TISInputSourceRef inputSource; IOHIDManagerRef hidManager; id unicodeData; - id listener; + id helper; + id keyUpMonitor; + id keyDownMonitor; char keyName[64]; char text[256]; diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index 95ef935d4..b275c7c58 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -47,7 +47,6 @@ #define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask #define NSEventMaskAny NSAnyEventMask #define NSEventTypeApplicationDefined NSApplicationDefined - #define NSEventTypeKeyUp NSKeyUp #endif #if (MAC_OS_X_VERSION_MAX_ALLOWED < 101400) @@ -1087,67 +1086,6 @@ is_ascii_control_char(char x) { @end -//------------------------------------------------------------------------ -// GLFW application class -//------------------------------------------------------------------------ - -@interface GLFWApplication : NSApplication -{ - NSArray* nibObjects; -} - -@end - -@implementation GLFWApplication - -- (void)sendEvent:(NSEvent *)event -{ - NSEventType etype = [event type]; - NSEventModifierFlags flags; - switch(etype) { - case NSEventTypeKeyUp: - flags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask; - if (flags & NSEventModifierFlagCommand) { - // From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost - // This works around an AppKit bug, where key up events while holding - // down the command key don't get sent to the key window. - [[self keyWindow] sendEvent:event]; - return; - } - if (event.keyCode == kVK_Tab && (flags == NSEventModifierFlagControl || flags == (NSEventModifierFlagControl | NSEventModifierFlagShift))) { - // Cocoa swallows Ctrl+Tab to cycle between views - [[self keyWindow].contentView keyUp:event]; - return; - } - break; - case NSEventTypeKeyDown: - flags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask; - if (event.keyCode == kVK_Tab && (flags == NSEventModifierFlagControl || flags == (NSEventModifierFlagControl | NSEventModifierFlagShift))) { - // Cocoa swallows Ctrl+Tab to cycle between views - [[self keyWindow].contentView keyDown:event]; - return; - } - break; - default: - break; - } - - [super sendEvent:event]; -} - - -// No-op thread entry point -// -- (void)doNothing:(id)object -{ -} - -- (void)loadMainMenu -{ // removed by Kovid as it generated compiler warnings -} - -@end - // Set up the menu bar (manually) // This is nasty, nasty stuff -- calls to undocumented semi-private APIs that // could go away at any moment, lots of stuff that really should be @@ -1257,32 +1195,9 @@ static void createMenuBar(void) // static GLFWbool initializeAppKit(void) { - if (NSApp) + if (_glfw.ns.delegate) return GLFW_TRUE; - // Implicitly create shared NSApplication instance - [GLFWApplication sharedApplication]; - - // Make Cocoa enter multi-threaded mode - [NSThread detachNewThreadSelector:@selector(doNothing:) - toTarget:NSApp - withObject:nil]; - - if (_glfw.hints.init.ns.menubar) - { - // In case we are unbundled, make us a proper UI application - [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; - - // Menu bar setup must go between sharedApplication above and - // finishLaunching below, in order to properly emulate the behavior - // of NSApplicationMain - - if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"]) - [NSApp loadMainMenu]; - else - createMenuBar(); - } - // There can only be one application delegate, but we allocate it the // first time a window is created to keep all window code in this file _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init]; @@ -1292,8 +1207,24 @@ static GLFWbool initializeAppKit(void) "Cocoa: Failed to create application delegate"); return GLFW_FALSE; } - [NSApp setDelegate:_glfw.ns.delegate]; + + if (_glfw.hints.init.ns.menubar) + { + // In case we are unbundled, make us a proper UI application + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + + // Menu bar setup must go between sharedApplication above and + // finishLaunching below, in order to properly emulate the behavior + // of NSApplicationMain + + // disabled by Kovid + /* if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"]) */ + /* [NSApp loadMainMenu]; */ + /* else */ + createMenuBar(); + } + [NSApp run]; // Press and Hold prevents some keys from emitting repeated characters @@ -1810,9 +1741,6 @@ void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) void _glfwPlatformPollEvents(void) { - if (!initializeAppKit()) - return; - for (;;) { NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny @@ -1953,8 +1881,6 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, NSImage* native; NSBitmapImageRep* rep; - if (!initializeAppKit()) - return GLFW_FALSE; native = [[NSImage alloc] initWithSize:NSMakeSize(image->width, image->height)]; if (native == nil) return GLFW_FALSE; @@ -1991,8 +1917,6 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor, int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape) { - if (!initializeAppKit()) - return GLFW_FALSE; if (shape == GLFW_ARROW_CURSOR) cursor->ns.object = [NSCursor arrowCursor];