From 5cd9e49629b920d0d48c884bb2a827ef75a1f2f7 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 31 May 2011 18:17:46 -0400 Subject: [PATCH] Add support for SPMediaKeyTap. This lets tomahawk stop iTunes from opening when a user presses one of the media keys. Thanks to the Clementine project and tyler.s.rhodes@gmail.com for much of the code in this patch. --- src/CMakeLists.osx.txt | 2 + src/CMakeLists.txt | 2 + src/mac/macdelegate.h | 40 +++++++++++++++ src/mac/tomahawkapp_mac.mm | 95 +++++++++++++++++++++++++---------- src/tomahawkapp_macdelegate.h | 43 ---------------- thirdparty/CMakeLists.txt | 3 ++ 6 files changed, 116 insertions(+), 69 deletions(-) create mode 100644 src/mac/macdelegate.h delete mode 100644 src/tomahawkapp_macdelegate.h diff --git a/src/CMakeLists.osx.txt b/src/CMakeLists.osx.txt index f1a5b2d20..f88939b80 100644 --- a/src/CMakeLists.osx.txt +++ b/src/CMakeLists.osx.txt @@ -5,6 +5,8 @@ SET( OS_SPECIFIC_LINK_LIBRARIES ${COREAUDIO_LIBRARY} ${COREFOUNDATION_LIBRARY} + SPMediaKeyTap + /System/Library/Frameworks/AppKit.framework /System/Library/Frameworks/Carbon.framework /System/Library/Frameworks/DiskArbitration.framework diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1d292c954..efedc8706 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -160,6 +160,8 @@ IF( UNIX ) ENDIF( UNIX ) IF( APPLE ) + INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/thirdparty/SPMediaKeyTap ) + SET( tomahawkHeaders ${tomahawkHeaders} mac/tomahawkapp_mac.h mac/macshortcuthandler.h ) SET( tomahawkSources ${tomahawkSources} mac/tomahawkapp_mac.mm mac/macshortcuthandler.cpp ) diff --git a/src/mac/macdelegate.h b/src/mac/macdelegate.h new file mode 100644 index 000000000..7d684d39e --- /dev/null +++ b/src/mac/macdelegate.h @@ -0,0 +1,40 @@ +#ifndef MACDELEGATE_H +#define MACDELEGATE_H + +// This file inspired by clementine's macdelegate.h + +#import + +#include "SPMediaKeyTap.h" + +namespace Tomahawk { + class MacShortcutHandler; + class PlatformInterface; +} + +#ifdef SNOW_LEOPARD +@interface AppDelegate :NSObject { +#else +@interface AppDelegate :NSObject { +#endif + Tomahawk::PlatformInterface* application_handler_; + NSMenu* dock_menu_; + SPMediaKeyTap* key_tap_; + Tomahawk::MacShortcutHandler* shortcut_handler_; +} + +- (id) initWithHandler: (Tomahawk::PlatformInterface*)handler; +// NSApplicationDelegate +- (BOOL) applicationShouldHandleReopen: (NSApplication*)app hasVisibleWindows:(BOOL)flag; +- (NSMenu*) applicationDockMenu: (NSApplication*)sender; +- (void) setDockMenu: (NSMenu*)menu; +- (Tomahawk::MacShortcutHandler*) shortcutHandler; +- (void) setShortcutHandler: (Tomahawk::MacShortcutHandler*)backend; +- (void)applicationDidFinishLaunching:(NSNotification*)aNotification; +- (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*)sender; +- (void) mediaKeyTap: (SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event; +@end + + + +#endif // MACDELEGATE_H diff --git a/src/mac/tomahawkapp_mac.mm b/src/mac/tomahawkapp_mac.mm index 44660e742..144a33853 100644 --- a/src/mac/tomahawkapp_mac.mm +++ b/src/mac/tomahawkapp_mac.mm @@ -17,7 +17,7 @@ */ #include "tomahawkapp_mac.h" -#include "tomahawkapp_macdelegate.h" +#include "macdelegate.h" #include "macshortcuthandler.h" #include @@ -42,6 +42,7 @@ // See: http://www.rogueamoeba.com/utm/2007/09/29/apple-keyboard-media-key-event-handling/ @interface MacApplication :NSApplication { + AppDelegate* delegate_; Tomahawk::MacShortcutHandler* shortcut_handler_; Tomahawk::PlatformInterface* application_handler_; } @@ -51,7 +52,6 @@ - (Tomahawk::PlatformInterface*) application_handler; - (void) setApplicationHandler: (Tomahawk::PlatformInterface*)handler; -- (void) mediaKeyEvent: (int)key state: (BOOL)state repeat: (BOOL)repeat; @end @@ -59,14 +59,22 @@ - (id) init { if ((self = [super init])) { - application_handler_ = nil; -// dock_menu_ = nil; + application_handler_ = nil; + shortcut_handler_ = nil; + //dock_menu_ = nil; } return self; } - (id) initWithHandler: (Tomahawk::PlatformInterface*)handler { application_handler_ = handler; + + // Register defaults for the whitelist of apps that want to use media keys + [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys: + [SPMediaKeyTap defaultMediaKeyUserBundleIdentifiers], @"SPApplicationsNeedingMediaKeys", + nil]]; + + return self; } @@ -76,7 +84,7 @@ } return YES; } -/* + - (void) setDockMenu: (NSMenu*)menu { dock_menu_ = menu; } @@ -84,7 +92,45 @@ - (NSMenu*) applicationDockMenu: (NSApplication*)sender { return dock_menu_; } -*/ + + +- (Tomahawk::MacShortcutHandler*) shortcutHandler { + return shortcut_handler_; +} + +- (void) setShortcutHandler: (Tomahawk::MacShortcutHandler*)handler { + qDebug() << "Setting shortcut handler of MacApp"; + // should be the same as MacApplication's + shortcut_handler_ = handler; +} + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + key_tap_ = [[SPMediaKeyTap alloc] initWithDelegate:self]; + if([SPMediaKeyTap usesGlobalMediaKeyTap]) + [key_tap_ startWatchingMediaKeys]; + else + qWarning()<<"Media key monitoring disabled"; + +} + +- (void) mediaKeyTap: (SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event { + NSAssert([event type] == NSSystemDefined && [event subtype] == SPSystemDefinedEventMediaKeys, @"Unexpected NSEvent in mediaKeyTap:receivedMediaKeyEvent:"); + + int key_code = (([event data1] & 0xFFFF0000) >> 16); + int key_flags = ([event data1] & 0x0000FFFF); + BOOL key_is_pressed = (((key_flags & 0xFF00) >> 8)) == 0xA; + // not used. keep just in case + // int key_repeat = (key_flags & 0x1); + + if (!shortcut_handler_) { + qWarning() << "No shortcut handler when we get a media key event..."; + return; + } + if (key_is_pressed) { + shortcut_handler_->macMediaKeyPressed(key_code); + } +} + - (BOOL) application: (NSApplication*)app openFile:(NSString*)filename { qDebug() << "Wants to open:" << [filename UTF8String]; @@ -94,6 +140,11 @@ return NO; } + +- (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*) sender { + return NSTerminateNow; +} + @end @implementation MacApplication @@ -127,7 +178,7 @@ } - (void) setShortcutHandler: (Tomahawk::MacShortcutHandler*)handler { - qDebug() << "Setting shortcut handler of MacAPp"; + // should be the same as AppDelegate's shortcut_handler_ = handler; } @@ -136,30 +187,22 @@ } - (void) setApplicationHandler: (Tomahawk::PlatformInterface*)handler { - AppDelegate* delegate = [[AppDelegate alloc] initWithHandler:handler]; - [self setDelegate:delegate]; + delegate_ = [[AppDelegate alloc] initWithHandler:handler]; + // App-shortcut-handler set before delegate is set. + // this makes sure the delegate's shortcut_handler is set + [delegate_ setShortcutHandler:shortcut_handler_]; + [self setDelegate:delegate_]; } -(void) sendEvent: (NSEvent*)event { - if ([event type] == NSSystemDefined && [event subtype] == 8) { - int keycode = (([event data1] & 0xFFFF0000) >> 16); - int keyflags = ([event data1] & 0x0000FFFF); - int keystate = (((keyflags & 0xFF00) >> 8)) == 0xA; - int keyrepeat = (keyflags & 0x1); + // If event tap is not installed, handle events that reach the app instead + BOOL shouldHandleMediaKeyEventLocally = ![SPMediaKeyTap usesGlobalMediaKeyTap]; - [self mediaKeyEvent: keycode state: keystate repeat: keyrepeat]; - } + if(shouldHandleMediaKeyEventLocally && [event type] == NSSystemDefined && [event subtype] == SPSystemDefinedEventMediaKeys) { + [(id)[self delegate] mediaKeyTap: nil receivedMediaKeyEvent: event]; + } - [super sendEvent: event]; -} - --(void) mediaKeyEvent: (int)key state: (BOOL)state repeat: (BOOL)repeat { - if (!shortcut_handler_) { - return; - } - if (state == 0) { - shortcut_handler_->macMediaKeyPressed(key); - } + [super sendEvent: event]; } @end diff --git a/src/tomahawkapp_macdelegate.h b/src/tomahawkapp_macdelegate.h deleted file mode 100644 index 01ef7a401..000000000 --- a/src/tomahawkapp_macdelegate.h +++ /dev/null @@ -1,43 +0,0 @@ -/* === This file is part of Tomahawk Player - === - * - * Copyright 2010-2011, Christian Muehlhaeuser - * - * Tomahawk is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Tomahawk is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Tomahawk. If not, see . - */ - -#import - -#include "config.h" - -// this file copied and inspired by mac_startup.* in clementine player, -// copyright David Sansome 2010 -namespace Tomahawk { - class PlatformInterface; -} - -#ifdef SNOW_LEOPARD -@interface AppDelegate : NSObject { -#else -@interface AppDelegate : NSObject { -#endif - Tomahawk::PlatformInterface* application_handler_; - //NSMenu* dock_menu_; -} - -- (id) initWithHandler: (Tomahawk::PlatformInterface*)handler; -// NSApplicationDelegate -- (BOOL) applicationShouldHandleReopen: (NSApplication*)app hasVisibleWindows:(BOOL)flag; -//- (NSMenu*) applicationDockMenu: (NSApplication*)sender; -//- (void) setDockMenu: (NSMenu*)menu; -@end diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 04dc95eb4..096668ed2 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,2 +1,5 @@ ADD_SUBDIRECTORY( qxt ) ADD_SUBDIRECTORY( liblastfm2 ) +IF( APPLE ) + ADD_SUBDIRECTORY( SPMediaKeyTap ) +ENDIF()