├── .gitignore ├── Spotify Bluetooth Headset Listener ├── en.lproj │ ├── InfoPlist.strings │ └── Credits.rtf ├── Images.xcassets │ ├── AppIcon.appiconset │ │ ├── AppIcon.png │ │ ├── AppIcon-1.png │ │ ├── AppIcon-2.png │ │ ├── AppIcon-3.png │ │ ├── AppIcon-4.png │ │ ├── AppIcon-5.png │ │ ├── AppIcon-6.png │ │ ├── AppIcon-7.png │ │ ├── AppIcon-8.png │ │ ├── AppIcon-9.png │ │ └── Contents.json │ └── MenuItemTemplate.imageset │ │ ├── MenuItemTemplate.png │ │ ├── MenuItemTemplate-1.png │ │ ├── MenuItemTemplate-2.png │ │ └── Contents.json ├── Spotify Bluetooth Headset Listener-Prefix.pch ├── main.m ├── KDMAppDelegate.h ├── MediaKey.h ├── MediaKey.m ├── Spotify Bluetooth Headset Listener-Info.plist ├── KDMAppDelegate.m └── Base.lproj │ └── MainMenu.xib ├── Spotify Bluetooth Headset ListenerTests ├── en.lproj │ └── InfoPlist.strings ├── Spotify Bluetooth Headset ListenerTests-Info.plist └── Spotify_Bluetooth_Headset_ListenerTests.m ├── Spotify Bluetooth Headset Listener.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── .gitignore ├── .gitignore └── project.pbxproj ├── .travis.yml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build 3 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset ListenerTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jguice/mac-bt-headset-fix/HEAD/Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon.png -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jguice/mac-bt-headset-fix/HEAD/Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-1.png -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jguice/mac-bt-headset-fix/HEAD/Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-2.png -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jguice/mac-bt-headset-fix/HEAD/Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-3.png -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jguice/mac-bt-headset-fix/HEAD/Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-4.png -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jguice/mac-bt-headset-fix/HEAD/Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-5.png -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jguice/mac-bt-headset-fix/HEAD/Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-6.png -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jguice/mac-bt-headset-fix/HEAD/Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-7.png -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jguice/mac-bt-headset-fix/HEAD/Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-8.png -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jguice/mac-bt-headset-fix/HEAD/Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/AppIcon-9.png -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Images.xcassets/MenuItemTemplate.imageset/MenuItemTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jguice/mac-bt-headset-fix/HEAD/Spotify Bluetooth Headset Listener/Images.xcassets/MenuItemTemplate.imageset/MenuItemTemplate.png -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Images.xcassets/MenuItemTemplate.imageset/MenuItemTemplate-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jguice/mac-bt-headset-fix/HEAD/Spotify Bluetooth Headset Listener/Images.xcassets/MenuItemTemplate.imageset/MenuItemTemplate-1.png -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Images.xcassets/MenuItemTemplate.imageset/MenuItemTemplate-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jguice/mac-bt-headset-fix/HEAD/Spotify Bluetooth Headset Listener/Images.xcassets/MenuItemTemplate.imageset/MenuItemTemplate-2.png -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Spotify Bluetooth Headset Listener-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #endif 10 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Spotify Bluetooth Headset Listener 4 | // 5 | // Created by Vincent Le Normand on 06/01/2014. 6 | // Copyright (c) 2014 KDM Software. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, const char * argv[]) 12 | { 13 | return NSApplicationMain(argc, argv); 14 | } 15 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/KDMAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // KDMAppDelegate.h 3 | // Spotify Bluetooth Headset Listener 4 | // 5 | // Created by KillerDeMouches on 06/01/2014. 6 | // Copyright (c) 2014 KDM Software. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface KDMAppDelegate : NSObject 12 | 13 | @property (assign) IBOutlet NSWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} 2 | {\colortbl;\red255\green255\blue255;} 3 | \paperw9840\paperh8400 4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural 5 | 6 | \f0\b\fs24 \cf0 Engineering: 7 | \b0 \ 8 | Some people\ 9 | \ 10 | 11 | \b Human Interface Design: 12 | \b0 \ 13 | Some other people\ 14 | \ 15 | 16 | \b Testing: 17 | \b0 \ 18 | Hopefully not nobody\ 19 | \ 20 | 21 | \b Documentation: 22 | \b0 \ 23 | Whoever\ 24 | \ 25 | 26 | \b With special thanks to: 27 | \b0 \ 28 | Mom\ 29 | } 30 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Images.xcassets/MenuItemTemplate.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "MenuItemTemplate.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x", 11 | "filename" : "MenuItemTemplate-2.png" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x", 16 | "filename" : "MenuItemTemplate-1.png" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode", 22 | "template-rendering-intent" : "template" 23 | } 24 | } -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener.xcodeproj/.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | 19 | # CocoaPods 20 | # 21 | # We recommend against adding the Pods directory to your .gitignore. However 22 | # you should judge for yourself, the pros and cons are mentioned at: 23 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control? 24 | # 25 | # Pods/ 26 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener.xcodeproj/project.xcworkspace/.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | 19 | # CocoaPods 20 | # 21 | # We recommend against adding the Pods directory to your .gitignore. However 22 | # you should judge for yourself, the pros and cons are mentioned at: 23 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control? 24 | # 25 | # Pods/ 26 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | script: "./build.sh" 3 | branches: 4 | only: 5 | - master 6 | - media-keys 7 | deploy: 8 | provider: s3 9 | region: us-west-2 10 | access_key_id: 11 | secure: gB/EKRMvGDDSyS1cRqCFm3qzAUmKy5mfV77HyvqI6yyJZSSYzNAEZuavL8oUPmAyzqEhuIhDtDT3Fnpa0V1eb0IdcAa2llWyvhiL2nZ5WArEgIO0EAthq1NxuZ5/TPILwhUeRPGnvxzQ7enLCXJqn5fdE5+u9YN2vL0AQp5/C8A= 12 | secret_access_key: 13 | secure: UHkOeeWzMc5tBC87IhYFG4nez94+JiSt5K4mqPausqTdEY7pcSjNkBdmiJvP1/nRJLgMpYzGJfDaLslG+BfIfpviT4SMokTXY0Od9JPvbgXM3bP3ps7aH38pNEm+K+N1KRfFW1b77ti/pmy39OotBrNIh4+kiVNotV9CsaZN11c= 14 | bucket: jguice 15 | acl: public_read 16 | local-dir: dist 17 | upload-dir: mac-bt-headset-fix 18 | skip_cleanup: true 19 | on: 20 | all_branches: true 21 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/MediaKey.h: -------------------------------------------------------------------------------- 1 | // 2 | // MediaKeys.h 3 | // Spotify Bluetooth Headset Listener 4 | // 5 | // Created by Josh Guice on 3/15/15. 6 | // 7 | // Generates media key events. e.g. 8 | // 9 | // [MediaKey send:NX_KEYTYPE_PLAY]; 10 | // [MediaKey send:NX_KEYTYPE_NEXT]; 11 | // [MediaKey send:NX_KEYTYPE_PREVIOUS]; 12 | // 13 | // Note that these DEFINEs are coming directly from ev_keymap.h ;) 14 | // 15 | 16 | #ifndef Spotify_Bluetooth_Headset_Listener_MediaKey_h 17 | #define Spotify_Bluetooth_Headset_Listener_MediaKey_h 18 | 19 | // required to send media "key" events 20 | #import 21 | #import 22 | 23 | @interface MediaKey : NSObject 24 | + (void)send: (int)key; // send desired key (down) then (up) event 25 | @end 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset ListenerTests/Spotify Bluetooth Headset ListenerTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.kdm.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset ListenerTests/Spotify_Bluetooth_Headset_ListenerTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // Spotify_Bluetooth_Headset_ListenerTests.m 3 | // Spotify Bluetooth Headset ListenerTests 4 | // 5 | // Created by Vincent Le Normand on 06/01/2014. 6 | // Copyright (c) 2014 KDM Software. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface Spotify_Bluetooth_Headset_ListenerTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Spotify_Bluetooth_Headset_ListenerTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/MediaKey.m: -------------------------------------------------------------------------------- 1 | // 2 | // MediaKey.m 3 | // Spotify Bluetooth Headset Listener 4 | // 5 | // Created by Josh Guice on 3/15/15. 6 | // 7 | 8 | #import 9 | #import "MediaKey.h" 10 | 11 | @implementation MediaKey 12 | 13 | NSEvent* key_event; 14 | 15 | // simulate a key press 16 | + (void) send: (int)key { 17 | // create and send down key event 18 | key_event = [NSEvent otherEventWithType:NSSystemDefined location:CGPointZero modifierFlags:0xa00 timestamp:0 windowNumber:0 context:0 subtype:8 data1:((key << 16) | (0xa << 8)) data2:-1]; 19 | CGEventPost(0, key_event.CGEvent); 20 | NSLog(@"%d keycode (down) sent",key); 21 | 22 | // create and send up key event 23 | key_event = [NSEvent otherEventWithType:NSSystemDefined location:CGPointZero modifierFlags:0xb00 timestamp:0 windowNumber:0 context:0 subtype:8 data1:((key << 16) | (0xb << 8)) data2:-1]; 24 | CGEventPost(0, key_event.CGEvent); 25 | NSLog(@"%d keycode (up) sent",key); 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Spotify Bluetooth Headset Listener-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.kdm.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSHumanReadableCopyright 28 | Copyright © 2014 KDM Software. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | LSUIElement 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "AppIcon-9.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "AppIcon-8.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "AppIcon-7.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "AppIcon-6.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "AppIcon-5.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "AppIcon-4.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "AppIcon-3.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "AppIcon-2.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "AppIcon-1.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "AppIcon.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | mac-bt-headset-fix build status 2 | ================== 3 | 4 | #### Try the **[Beta Version](https://github.com/jguice/mac-bt-headset-fix#beta-version)** below for Sierra (10.12.1+) :grin: 5 | 6 | Small mac application that fixes broken bluetooth headset control by listening for headset keypress events and re-triggers them as media key presses (as if one pushed the buttons on the keyboard). 7 | 8 | The app should work with any player/etc. that responds to media keys, but allow you to use your bluetooth headset controls instead :-). 9 | 10 | Download the [latest stable version](https://s3-us-west-2.amazonaws.com/jguice/mac-bt-headset-fix/Spotify+Bluetooth+Headset+Listener.zip). 11 | 12 | ## Usage 13 | Download the above file and unzip it. Double-click to run the app (you may need to generally allow unsigned apps or authorize this one in particular). 14 | 15 | Try connecting your bluetooth device and pressing the play/pause/etc. buttons (press and hold too). Your media player should respond to them just as if you'd pressed the relevant keyboard media key. :) 16 | 17 | If you're using an in-browser player you might need an extension to make the app respond to media keys (which should also make it work with your headset). For **chrome** try [streamkeys](https://chrome.google.com/webstore/detail/streamkeys/ekpipjofdicppbepocohdlgenahaneen?hl=en). 18 | 19 | ## What it does 20 | On execution the application will background itself and listen for bluetooth headset events. You'll see a **menu bar icon** that can be used to quit the app (or hide the menu icon). **Note** *that the menu icon will remain visible for 30 seconds before hiding to allow changing the hide option or quitting, etc.* 21 | 22 | The app will intercept common bluetooth headset key presses and re-fire them as media key presses. Currently the following key presses are supported: 23 | 24 | - play/pause 25 | - next 26 | - prev 27 | - fast-forward 28 | - rewind 29 | 30 | The mapping on headsets seems to be a bit inconsistent. If pressing next/prev doesn't work, try a press and hold. :) 31 | 32 | On launch it will also attempt to unload the built-in Remote Control Daemon (rcd) which seems to be responsible for starting iTunes when a play event is first received. 33 | 34 | **Note** *that this will probably cause any remote controls you use to stop working.* 35 | 36 | If you find iTunes still loads you might try this [play-button-itunes-patch](http://github.com/thebitguru/play-button-itunes-patch). 37 | 38 | ## Quitting the Application when menu bar icon is hidden 39 | Run this command in Terminal: 40 | 41 | kill "$(pgrep 'Spotify Bluetooth Headset Listener')" 42 | 43 | If you want to relaunch the app (possibly to show the icon again), run this instead: 44 | 45 | PID="$(pgrep 'Spotify Bluetooth Headset Listener')"; \ 46 | APP="$(dirname "$(ps -o "comm" -p "$PID" | tail -n 1)")/../../"; \ 47 | kill $PID; \ 48 | open "$APP" 49 | 50 | You will have 30 seconds to disable hiding the icon if you so choose. 51 | 52 | **Note**: *on quit the application will try to reload the Remote Control Daemon to restore whatever functionality it provides* 53 | 54 | ## Beta Version 55 | 56 | If you're feeling lucky try the [beta version](https://s3-us-west-2.amazonaws.com/jguice/mac-bt-headset-fix-beta/bubo.app.zip). 57 | 58 | ### Changes 59 | - renamed app to bubo[1] 60 | - works on macOS Sierra 10.12.1+ 61 | - no longer mucks with launchctl daemons to keep iTunes from starting 62 | - Objective-C -> Swift 63 | - signed app (legit!) 64 | 65 | ## Origin 66 | The original version of this app was posted on [this spotify community thread](http://community.spotify.com/t5/Help-Desktop-Linux-Mac-and/Bluetooth-headset-buttons/m-p/161796). It controlled the spotify mac player directly via the scripting bridge (objC -> applescript). I did not write it, but was granted permission to post it to github for sharing and encouraging enhancements. It was published here under the [MIT License](http://opensource.org/licenses/MIT) as requested by the author. :) 67 | 68 | This current version has been completely re-written, but retains that same license. 69 | 70 | ## Alternatives 71 | - https://github.com/JamesFator/BTHSControl 72 | 73 | ## Donations 74 | Feel free to donate any amount If you'd like to contribute to further development of this little app or just say "Thanks!" 75 | 76 | --- 77 | 78 | [1] a tiny invisible mechanical owl that sits on your shoulder and, when you press a bluetooth headset button, flies to the keyboard and pecks it for you. :bird: 79 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/KDMAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // KDMAppDelegate.m 3 | // Spotify Bluetooth Headset Listener 4 | // 5 | // Created by KillerDeMouches on 06/01/2014. 6 | // Copyright (c) 2014 KDM Software. All rights reserved. 7 | // 8 | 9 | // TODO rename this app to MacBluetoothHeadsetListener (or something even *more* catchy ;) ) 10 | 11 | #import "KDMAppDelegate.h" 12 | #import "MediaKey.h" 13 | 14 | @interface KDMAppDelegate() 15 | @property id eventMonitor; 16 | @end 17 | 18 | @implementation KDMAppDelegate { 19 | NSStatusItem * statusItem; 20 | IBOutlet NSMenu * statusItemMenu; 21 | } 22 | 23 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 24 | { 25 | if(![[NSUserDefaults standardUserDefaults] boolForKey:@"Hide menu Item"]){ 26 | [self setupMenuItem]; 27 | } 28 | 29 | // TODO determine why there is sometimes a several second delay before this monitor fires (is there another way that might be faster?) 30 | [NSTask launchedTaskWithLaunchPath:@"/bin/launchctl" arguments:@[@"unload",@"/System/Library/LaunchAgents/com.apple.rcd.plist"]]; 31 | self.eventMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:(NSKeyDownMask|NSSystemDefinedMask) handler:^(NSEvent * event) { 32 | int keyCode = (([event data1] & 0xFFFF0000) >> 16); 33 | 34 | int keyFlags = ([event data1] & 0x0000FFFF); 35 | 36 | int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA; 37 | 38 | if(keyCode == 10 && keyFlags == 6972) { 39 | 40 | switch ([event data2]) { 41 | case 786608: // Play / Pause on OS < 10.10 Yosemite 42 | case 786637: // Play / Pause on OS >= 10.10 Yosemite 43 | NSLog(@"Play/Pause bluetooth keypress detected...sending corresponding media key event"); 44 | [MediaKey send:NX_KEYTYPE_PLAY]; 45 | break; 46 | case 786611: // Next 47 | NSLog(@"Next bluetooth keypress detected...sending corresponding media key event"); 48 | [MediaKey send:NX_KEYTYPE_NEXT]; 49 | break; 50 | case 786612: // Previous 51 | NSLog(@"Previous bluetooth keypress detected...sending corresponding media key event"); 52 | [MediaKey send:NX_KEYTYPE_PREVIOUS]; 53 | break; 54 | case 786613: // Fast-forward 55 | NSLog(@"Fast-forward bluetooth keypress detected...sending corresponding media key event"); 56 | [MediaKey send:NX_KEYTYPE_FAST]; 57 | break; 58 | case 786614: // Rewind 59 | NSLog(@"Rewind bluetooth keypress detected...sending corresponding media key event"); 60 | [MediaKey send:NX_KEYTYPE_REWIND]; 61 | break; 62 | default: 63 | // TODO make this popup a message in the UI (with a link to submit the issue and a "don't show this message again" checkbox) 64 | NSLog(@"Unknown bluetooth key received. Please visit https://github.com/jguice/mac-bt-headset-fix/issues and submit an issue describing what you expect the key to do (include the following data): keyCode:%i keyFlags:%i keyState:%i %li",keyCode,keyFlags,keyState,(long)[event data2]); 65 | break; 66 | } 67 | } 68 | }]; 69 | return; 70 | } 71 | 72 | -(BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender { 73 | if(statusItem == nil) { 74 | [self setupMenuItem]; 75 | [statusItem popUpStatusItemMenu:statusItem.menu]; 76 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(30 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 77 | if([[NSUserDefaults standardUserDefaults] boolForKey:@"Hide menu Item"]){ 78 | [statusItem.statusBar removeStatusItem:statusItem]; 79 | } 80 | }); 81 | } 82 | return NO; 83 | } 84 | 85 | - (void) setupMenuItem { 86 | if(statusItem == nil) { 87 | statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength]; 88 | statusItem.image = [NSImage imageNamed:@"MenuItemTemplate"]; 89 | statusItem.menu = statusItemMenu; 90 | } 91 | } 92 | 93 | - (void) applicationWillTerminate:(NSNotification *)notification { 94 | [NSTask launchedTaskWithLaunchPath:@"/bin/launchctl" arguments:@[@"load",@"/System/Library/LaunchAgents/com.apple.rcd.plist"]]; 95 | [NSEvent removeMonitor:self.eventMonitor]; 96 | } 97 | 98 | - (IBAction)hide:(id)sender { 99 | NSUserDefaults * standardUserDefaults = [NSUserDefaults standardUserDefaults]; 100 | if([standardUserDefaults boolForKey:@"Hide menu Item"]) { 101 | [standardUserDefaults setBool:NO forKey:@"Hide menu Item"]; 102 | [self setupMenuItem]; 103 | } 104 | else { 105 | [standardUserDefaults setBool:YES forKey:@"Hide menu Item"]; 106 | [statusItem.statusBar removeStatusItem:statusItem]; 107 | statusItem = nil; 108 | } 109 | } 110 | - (BOOL) validateMenuItem:(NSMenuItem *)menuItem { 111 | if([menuItem action] == @selector(hide:)) { 112 | [menuItem setState:[[NSUserDefaults standardUserDefaults] boolForKey:@"Hide menu Item"]?NSOnState:NSOffState]; 113 | return YES; 114 | } 115 | return NO; 116 | } 117 | @end -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /Spotify Bluetooth Headset Listener.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B5FB3D091AB677610064CEE7 /* MediaKey.m in Sources */ = {isa = PBXBuildFile; fileRef = B5FB3D081AB677610064CEE7 /* MediaKey.m */; }; 11 | BFF9B267187AB88D00F93B58 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFF9B266187AB88D00F93B58 /* Cocoa.framework */; }; 12 | BFF9B271187AB88D00F93B58 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = BFF9B26F187AB88D00F93B58 /* InfoPlist.strings */; }; 13 | BFF9B273187AB88D00F93B58 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BFF9B272187AB88D00F93B58 /* main.m */; }; 14 | BFF9B277187AB88D00F93B58 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = BFF9B275187AB88D00F93B58 /* Credits.rtf */; }; 15 | BFF9B27A187AB88D00F93B58 /* KDMAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BFF9B279187AB88D00F93B58 /* KDMAppDelegate.m */; }; 16 | BFF9B27D187AB88E00F93B58 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = BFF9B27B187AB88E00F93B58 /* MainMenu.xib */; }; 17 | BFF9B27F187AB88E00F93B58 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BFF9B27E187AB88E00F93B58 /* Images.xcassets */; }; 18 | BFF9B286187AB88E00F93B58 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFF9B285187AB88E00F93B58 /* XCTest.framework */; }; 19 | BFF9B287187AB88E00F93B58 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFF9B266187AB88D00F93B58 /* Cocoa.framework */; }; 20 | BFF9B28F187AB88E00F93B58 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = BFF9B28D187AB88E00F93B58 /* InfoPlist.strings */; }; 21 | BFF9B291187AB88E00F93B58 /* Spotify_Bluetooth_Headset_ListenerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BFF9B290187AB88E00F93B58 /* Spotify_Bluetooth_Headset_ListenerTests.m */; }; 22 | BFF9B29F187B094C00F93B58 /* ScriptingBridge.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFF9B29E187B094C00F93B58 /* ScriptingBridge.framework */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | BFF9B288187AB88E00F93B58 /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = BFF9B25B187AB88C00F93B58 /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = BFF9B262187AB88D00F93B58; 31 | remoteInfo = "Spotify Bluetooth Headset Listener"; 32 | }; 33 | /* End PBXContainerItemProxy section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | B5FB3D071AB676100064CEE7 /* MediaKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaKey.h; sourceTree = ""; }; 37 | B5FB3D081AB677610064CEE7 /* MediaKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MediaKey.m; sourceTree = ""; }; 38 | BFF9B263187AB88D00F93B58 /* Spotify Bluetooth Headset Listener.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Spotify Bluetooth Headset Listener.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | BFF9B266187AB88D00F93B58 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 40 | BFF9B269187AB88D00F93B58 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 41 | BFF9B26A187AB88D00F93B58 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 42 | BFF9B26B187AB88D00F93B58 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 43 | BFF9B26E187AB88D00F93B58 /* Spotify Bluetooth Headset Listener-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Spotify Bluetooth Headset Listener-Info.plist"; sourceTree = ""; }; 44 | BFF9B270187AB88D00F93B58 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 45 | BFF9B272187AB88D00F93B58 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 46 | BFF9B274187AB88D00F93B58 /* Spotify Bluetooth Headset Listener-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Spotify Bluetooth Headset Listener-Prefix.pch"; sourceTree = ""; }; 47 | BFF9B276187AB88D00F93B58 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; 48 | BFF9B278187AB88D00F93B58 /* KDMAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KDMAppDelegate.h; sourceTree = ""; }; 49 | BFF9B279187AB88D00F93B58 /* KDMAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KDMAppDelegate.m; sourceTree = ""; }; 50 | BFF9B27C187AB88E00F93B58 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 51 | BFF9B27E187AB88E00F93B58 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 52 | BFF9B284187AB88E00F93B58 /* Spotify Bluetooth Headset ListenerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Spotify Bluetooth Headset ListenerTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | BFF9B285187AB88E00F93B58 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 54 | BFF9B28C187AB88E00F93B58 /* Spotify Bluetooth Headset ListenerTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Spotify Bluetooth Headset ListenerTests-Info.plist"; sourceTree = ""; }; 55 | BFF9B28E187AB88E00F93B58 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 56 | BFF9B290187AB88E00F93B58 /* Spotify_Bluetooth_Headset_ListenerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Spotify_Bluetooth_Headset_ListenerTests.m; sourceTree = ""; }; 57 | BFF9B29A187AB8E100F93B58 /* IOBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOBluetooth.framework; path = System/Library/Frameworks/IOBluetooth.framework; sourceTree = SDKROOT; }; 58 | BFF9B29C187ABD3100F93B58 /* IOBluetoothUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOBluetoothUI.framework; path = System/Library/Frameworks/IOBluetoothUI.framework; sourceTree = SDKROOT; }; 59 | BFF9B29E187B094C00F93B58 /* ScriptingBridge.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ScriptingBridge.framework; path = System/Library/Frameworks/ScriptingBridge.framework; sourceTree = SDKROOT; }; 60 | /* End PBXFileReference section */ 61 | 62 | /* Begin PBXFrameworksBuildPhase section */ 63 | BFF9B260187AB88D00F93B58 /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | BFF9B29F187B094C00F93B58 /* ScriptingBridge.framework in Frameworks */, 68 | BFF9B267187AB88D00F93B58 /* Cocoa.framework in Frameworks */, 69 | ); 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | BFF9B281187AB88E00F93B58 /* Frameworks */ = { 73 | isa = PBXFrameworksBuildPhase; 74 | buildActionMask = 2147483647; 75 | files = ( 76 | BFF9B287187AB88E00F93B58 /* Cocoa.framework in Frameworks */, 77 | BFF9B286187AB88E00F93B58 /* XCTest.framework in Frameworks */, 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | /* End PBXFrameworksBuildPhase section */ 82 | 83 | /* Begin PBXGroup section */ 84 | BFF9B25A187AB88C00F93B58 = { 85 | isa = PBXGroup; 86 | children = ( 87 | BFF9B26C187AB88D00F93B58 /* Spotify Bluetooth Headset Listener */, 88 | BFF9B28A187AB88E00F93B58 /* Spotify Bluetooth Headset ListenerTests */, 89 | BFF9B265187AB88D00F93B58 /* Frameworks */, 90 | BFF9B264187AB88D00F93B58 /* Products */, 91 | ); 92 | sourceTree = ""; 93 | }; 94 | BFF9B264187AB88D00F93B58 /* Products */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | BFF9B263187AB88D00F93B58 /* Spotify Bluetooth Headset Listener.app */, 98 | BFF9B284187AB88E00F93B58 /* Spotify Bluetooth Headset ListenerTests.xctest */, 99 | ); 100 | name = Products; 101 | sourceTree = ""; 102 | }; 103 | BFF9B265187AB88D00F93B58 /* Frameworks */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | BFF9B29E187B094C00F93B58 /* ScriptingBridge.framework */, 107 | BFF9B29C187ABD3100F93B58 /* IOBluetoothUI.framework */, 108 | BFF9B29A187AB8E100F93B58 /* IOBluetooth.framework */, 109 | BFF9B266187AB88D00F93B58 /* Cocoa.framework */, 110 | BFF9B285187AB88E00F93B58 /* XCTest.framework */, 111 | BFF9B268187AB88D00F93B58 /* Other Frameworks */, 112 | ); 113 | name = Frameworks; 114 | sourceTree = ""; 115 | }; 116 | BFF9B268187AB88D00F93B58 /* Other Frameworks */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | BFF9B269187AB88D00F93B58 /* AppKit.framework */, 120 | BFF9B26A187AB88D00F93B58 /* CoreData.framework */, 121 | BFF9B26B187AB88D00F93B58 /* Foundation.framework */, 122 | ); 123 | name = "Other Frameworks"; 124 | sourceTree = ""; 125 | }; 126 | BFF9B26C187AB88D00F93B58 /* Spotify Bluetooth Headset Listener */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | B5FB3D071AB676100064CEE7 /* MediaKey.h */, 130 | BFF9B278187AB88D00F93B58 /* KDMAppDelegate.h */, 131 | BFF9B279187AB88D00F93B58 /* KDMAppDelegate.m */, 132 | BFF9B27B187AB88E00F93B58 /* MainMenu.xib */, 133 | BFF9B27E187AB88E00F93B58 /* Images.xcassets */, 134 | BFF9B26D187AB88D00F93B58 /* Supporting Files */, 135 | B5FB3D081AB677610064CEE7 /* MediaKey.m */, 136 | ); 137 | path = "Spotify Bluetooth Headset Listener"; 138 | sourceTree = ""; 139 | }; 140 | BFF9B26D187AB88D00F93B58 /* Supporting Files */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | BFF9B26E187AB88D00F93B58 /* Spotify Bluetooth Headset Listener-Info.plist */, 144 | BFF9B26F187AB88D00F93B58 /* InfoPlist.strings */, 145 | BFF9B272187AB88D00F93B58 /* main.m */, 146 | BFF9B274187AB88D00F93B58 /* Spotify Bluetooth Headset Listener-Prefix.pch */, 147 | BFF9B275187AB88D00F93B58 /* Credits.rtf */, 148 | ); 149 | name = "Supporting Files"; 150 | sourceTree = ""; 151 | }; 152 | BFF9B28A187AB88E00F93B58 /* Spotify Bluetooth Headset ListenerTests */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | BFF9B290187AB88E00F93B58 /* Spotify_Bluetooth_Headset_ListenerTests.m */, 156 | BFF9B28B187AB88E00F93B58 /* Supporting Files */, 157 | ); 158 | path = "Spotify Bluetooth Headset ListenerTests"; 159 | sourceTree = ""; 160 | }; 161 | BFF9B28B187AB88E00F93B58 /* Supporting Files */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | BFF9B28C187AB88E00F93B58 /* Spotify Bluetooth Headset ListenerTests-Info.plist */, 165 | BFF9B28D187AB88E00F93B58 /* InfoPlist.strings */, 166 | ); 167 | name = "Supporting Files"; 168 | sourceTree = ""; 169 | }; 170 | /* End PBXGroup section */ 171 | 172 | /* Begin PBXNativeTarget section */ 173 | BFF9B262187AB88D00F93B58 /* Spotify Bluetooth Headset Listener */ = { 174 | isa = PBXNativeTarget; 175 | buildConfigurationList = BFF9B294187AB88E00F93B58 /* Build configuration list for PBXNativeTarget "Spotify Bluetooth Headset Listener" */; 176 | buildPhases = ( 177 | BFF9B25F187AB88D00F93B58 /* Sources */, 178 | BFF9B260187AB88D00F93B58 /* Frameworks */, 179 | BFF9B261187AB88D00F93B58 /* Resources */, 180 | ); 181 | buildRules = ( 182 | ); 183 | dependencies = ( 184 | ); 185 | name = "Spotify Bluetooth Headset Listener"; 186 | productName = "Spotify Bluetooth Headset Listener"; 187 | productReference = BFF9B263187AB88D00F93B58 /* Spotify Bluetooth Headset Listener.app */; 188 | productType = "com.apple.product-type.application"; 189 | }; 190 | BFF9B283187AB88E00F93B58 /* Spotify Bluetooth Headset ListenerTests */ = { 191 | isa = PBXNativeTarget; 192 | buildConfigurationList = BFF9B297187AB88E00F93B58 /* Build configuration list for PBXNativeTarget "Spotify Bluetooth Headset ListenerTests" */; 193 | buildPhases = ( 194 | BFF9B280187AB88E00F93B58 /* Sources */, 195 | BFF9B281187AB88E00F93B58 /* Frameworks */, 196 | BFF9B282187AB88E00F93B58 /* Resources */, 197 | ); 198 | buildRules = ( 199 | ); 200 | dependencies = ( 201 | BFF9B289187AB88E00F93B58 /* PBXTargetDependency */, 202 | ); 203 | name = "Spotify Bluetooth Headset ListenerTests"; 204 | productName = "Spotify Bluetooth Headset ListenerTests"; 205 | productReference = BFF9B284187AB88E00F93B58 /* Spotify Bluetooth Headset ListenerTests.xctest */; 206 | productType = "com.apple.product-type.bundle.unit-test"; 207 | }; 208 | /* End PBXNativeTarget section */ 209 | 210 | /* Begin PBXProject section */ 211 | BFF9B25B187AB88C00F93B58 /* Project object */ = { 212 | isa = PBXProject; 213 | attributes = { 214 | CLASSPREFIX = KDM; 215 | LastUpgradeCheck = 0500; 216 | ORGANIZATIONNAME = "KDM Software"; 217 | TargetAttributes = { 218 | BFF9B283187AB88E00F93B58 = { 219 | TestTargetID = BFF9B262187AB88D00F93B58; 220 | }; 221 | }; 222 | }; 223 | buildConfigurationList = BFF9B25E187AB88C00F93B58 /* Build configuration list for PBXProject "Spotify Bluetooth Headset Listener" */; 224 | compatibilityVersion = "Xcode 3.2"; 225 | developmentRegion = English; 226 | hasScannedForEncodings = 0; 227 | knownRegions = ( 228 | en, 229 | Base, 230 | ); 231 | mainGroup = BFF9B25A187AB88C00F93B58; 232 | productRefGroup = BFF9B264187AB88D00F93B58 /* Products */; 233 | projectDirPath = ""; 234 | projectRoot = ""; 235 | targets = ( 236 | BFF9B262187AB88D00F93B58 /* Spotify Bluetooth Headset Listener */, 237 | BFF9B283187AB88E00F93B58 /* Spotify Bluetooth Headset ListenerTests */, 238 | ); 239 | }; 240 | /* End PBXProject section */ 241 | 242 | /* Begin PBXResourcesBuildPhase section */ 243 | BFF9B261187AB88D00F93B58 /* Resources */ = { 244 | isa = PBXResourcesBuildPhase; 245 | buildActionMask = 2147483647; 246 | files = ( 247 | BFF9B271187AB88D00F93B58 /* InfoPlist.strings in Resources */, 248 | BFF9B27F187AB88E00F93B58 /* Images.xcassets in Resources */, 249 | BFF9B277187AB88D00F93B58 /* Credits.rtf in Resources */, 250 | BFF9B27D187AB88E00F93B58 /* MainMenu.xib in Resources */, 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | }; 254 | BFF9B282187AB88E00F93B58 /* Resources */ = { 255 | isa = PBXResourcesBuildPhase; 256 | buildActionMask = 2147483647; 257 | files = ( 258 | BFF9B28F187AB88E00F93B58 /* InfoPlist.strings in Resources */, 259 | ); 260 | runOnlyForDeploymentPostprocessing = 0; 261 | }; 262 | /* End PBXResourcesBuildPhase section */ 263 | 264 | /* Begin PBXSourcesBuildPhase section */ 265 | BFF9B25F187AB88D00F93B58 /* Sources */ = { 266 | isa = PBXSourcesBuildPhase; 267 | buildActionMask = 2147483647; 268 | files = ( 269 | B5FB3D091AB677610064CEE7 /* MediaKey.m in Sources */, 270 | BFF9B273187AB88D00F93B58 /* main.m in Sources */, 271 | BFF9B27A187AB88D00F93B58 /* KDMAppDelegate.m in Sources */, 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | }; 275 | BFF9B280187AB88E00F93B58 /* Sources */ = { 276 | isa = PBXSourcesBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | BFF9B291187AB88E00F93B58 /* Spotify_Bluetooth_Headset_ListenerTests.m in Sources */, 280 | ); 281 | runOnlyForDeploymentPostprocessing = 0; 282 | }; 283 | /* End PBXSourcesBuildPhase section */ 284 | 285 | /* Begin PBXTargetDependency section */ 286 | BFF9B289187AB88E00F93B58 /* PBXTargetDependency */ = { 287 | isa = PBXTargetDependency; 288 | target = BFF9B262187AB88D00F93B58 /* Spotify Bluetooth Headset Listener */; 289 | targetProxy = BFF9B288187AB88E00F93B58 /* PBXContainerItemProxy */; 290 | }; 291 | /* End PBXTargetDependency section */ 292 | 293 | /* Begin PBXVariantGroup section */ 294 | BFF9B26F187AB88D00F93B58 /* InfoPlist.strings */ = { 295 | isa = PBXVariantGroup; 296 | children = ( 297 | BFF9B270187AB88D00F93B58 /* en */, 298 | ); 299 | name = InfoPlist.strings; 300 | sourceTree = ""; 301 | }; 302 | BFF9B275187AB88D00F93B58 /* Credits.rtf */ = { 303 | isa = PBXVariantGroup; 304 | children = ( 305 | BFF9B276187AB88D00F93B58 /* en */, 306 | ); 307 | name = Credits.rtf; 308 | sourceTree = ""; 309 | }; 310 | BFF9B27B187AB88E00F93B58 /* MainMenu.xib */ = { 311 | isa = PBXVariantGroup; 312 | children = ( 313 | BFF9B27C187AB88E00F93B58 /* Base */, 314 | ); 315 | name = MainMenu.xib; 316 | sourceTree = ""; 317 | }; 318 | BFF9B28D187AB88E00F93B58 /* InfoPlist.strings */ = { 319 | isa = PBXVariantGroup; 320 | children = ( 321 | BFF9B28E187AB88E00F93B58 /* en */, 322 | ); 323 | name = InfoPlist.strings; 324 | sourceTree = ""; 325 | }; 326 | /* End PBXVariantGroup section */ 327 | 328 | /* Begin XCBuildConfiguration section */ 329 | BFF9B292187AB88E00F93B58 /* Debug */ = { 330 | isa = XCBuildConfiguration; 331 | buildSettings = { 332 | ALWAYS_SEARCH_USER_PATHS = NO; 333 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 334 | CLANG_CXX_LIBRARY = "libc++"; 335 | CLANG_ENABLE_OBJC_ARC = YES; 336 | CLANG_WARN_BOOL_CONVERSION = YES; 337 | CLANG_WARN_CONSTANT_CONVERSION = YES; 338 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 339 | CLANG_WARN_EMPTY_BODY = YES; 340 | CLANG_WARN_ENUM_CONVERSION = YES; 341 | CLANG_WARN_INT_CONVERSION = YES; 342 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 343 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 344 | COPY_PHASE_STRIP = NO; 345 | GCC_C_LANGUAGE_STANDARD = gnu99; 346 | GCC_DYNAMIC_NO_PIC = NO; 347 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 348 | GCC_OPTIMIZATION_LEVEL = 0; 349 | GCC_PREPROCESSOR_DEFINITIONS = ( 350 | "DEBUG=1", 351 | "$(inherited)", 352 | ); 353 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 354 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 355 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 356 | GCC_WARN_UNDECLARED_SELECTOR = YES; 357 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 358 | GCC_WARN_UNUSED_FUNCTION = YES; 359 | GCC_WARN_UNUSED_VARIABLE = YES; 360 | MACOSX_DEPLOYMENT_TARGET = 10.9; 361 | ONLY_ACTIVE_ARCH = YES; 362 | SDKROOT = macosx; 363 | }; 364 | name = Debug; 365 | }; 366 | BFF9B293187AB88E00F93B58 /* Release */ = { 367 | isa = XCBuildConfiguration; 368 | buildSettings = { 369 | ALWAYS_SEARCH_USER_PATHS = NO; 370 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 371 | CLANG_CXX_LIBRARY = "libc++"; 372 | CLANG_ENABLE_OBJC_ARC = YES; 373 | CLANG_WARN_BOOL_CONVERSION = YES; 374 | CLANG_WARN_CONSTANT_CONVERSION = YES; 375 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 376 | CLANG_WARN_EMPTY_BODY = YES; 377 | CLANG_WARN_ENUM_CONVERSION = YES; 378 | CLANG_WARN_INT_CONVERSION = YES; 379 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 380 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 381 | COPY_PHASE_STRIP = YES; 382 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 383 | ENABLE_NS_ASSERTIONS = NO; 384 | GCC_C_LANGUAGE_STANDARD = gnu99; 385 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 386 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 387 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 388 | GCC_WARN_UNDECLARED_SELECTOR = YES; 389 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 390 | GCC_WARN_UNUSED_FUNCTION = YES; 391 | GCC_WARN_UNUSED_VARIABLE = YES; 392 | MACOSX_DEPLOYMENT_TARGET = 10.9; 393 | SDKROOT = macosx; 394 | }; 395 | name = Release; 396 | }; 397 | BFF9B295187AB88E00F93B58 /* Debug */ = { 398 | isa = XCBuildConfiguration; 399 | buildSettings = { 400 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 401 | COMBINE_HIDPI_IMAGES = YES; 402 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 403 | GCC_PREFIX_HEADER = "Spotify Bluetooth Headset Listener/Spotify Bluetooth Headset Listener-Prefix.pch"; 404 | INFOPLIST_FILE = "Spotify Bluetooth Headset Listener/Spotify Bluetooth Headset Listener-Info.plist"; 405 | MACOSX_DEPLOYMENT_TARGET = 10.6; 406 | PRODUCT_NAME = "$(TARGET_NAME)"; 407 | WRAPPER_EXTENSION = app; 408 | }; 409 | name = Debug; 410 | }; 411 | BFF9B296187AB88E00F93B58 /* Release */ = { 412 | isa = XCBuildConfiguration; 413 | buildSettings = { 414 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 415 | COMBINE_HIDPI_IMAGES = YES; 416 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 417 | GCC_PREFIX_HEADER = "Spotify Bluetooth Headset Listener/Spotify Bluetooth Headset Listener-Prefix.pch"; 418 | INFOPLIST_FILE = "Spotify Bluetooth Headset Listener/Spotify Bluetooth Headset Listener-Info.plist"; 419 | MACOSX_DEPLOYMENT_TARGET = 10.6; 420 | PRODUCT_NAME = "$(TARGET_NAME)"; 421 | WRAPPER_EXTENSION = app; 422 | }; 423 | name = Release; 424 | }; 425 | BFF9B298187AB88E00F93B58 /* Debug */ = { 426 | isa = XCBuildConfiguration; 427 | buildSettings = { 428 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Spotify Bluetooth Headset Listener.app/Contents/MacOS/Spotify Bluetooth Headset Listener"; 429 | COMBINE_HIDPI_IMAGES = YES; 430 | FRAMEWORK_SEARCH_PATHS = ( 431 | "$(DEVELOPER_FRAMEWORKS_DIR)", 432 | "$(inherited)", 433 | ); 434 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 435 | GCC_PREFIX_HEADER = "Spotify Bluetooth Headset Listener/Spotify Bluetooth Headset Listener-Prefix.pch"; 436 | GCC_PREPROCESSOR_DEFINITIONS = ( 437 | "DEBUG=1", 438 | "$(inherited)", 439 | ); 440 | INFOPLIST_FILE = "Spotify Bluetooth Headset ListenerTests/Spotify Bluetooth Headset ListenerTests-Info.plist"; 441 | PRODUCT_NAME = "$(TARGET_NAME)"; 442 | TEST_HOST = "$(BUNDLE_LOADER)"; 443 | WRAPPER_EXTENSION = xctest; 444 | }; 445 | name = Debug; 446 | }; 447 | BFF9B299187AB88E00F93B58 /* Release */ = { 448 | isa = XCBuildConfiguration; 449 | buildSettings = { 450 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Spotify Bluetooth Headset Listener.app/Contents/MacOS/Spotify Bluetooth Headset Listener"; 451 | COMBINE_HIDPI_IMAGES = YES; 452 | FRAMEWORK_SEARCH_PATHS = ( 453 | "$(DEVELOPER_FRAMEWORKS_DIR)", 454 | "$(inherited)", 455 | ); 456 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 457 | GCC_PREFIX_HEADER = "Spotify Bluetooth Headset Listener/Spotify Bluetooth Headset Listener-Prefix.pch"; 458 | INFOPLIST_FILE = "Spotify Bluetooth Headset ListenerTests/Spotify Bluetooth Headset ListenerTests-Info.plist"; 459 | PRODUCT_NAME = "$(TARGET_NAME)"; 460 | TEST_HOST = "$(BUNDLE_LOADER)"; 461 | WRAPPER_EXTENSION = xctest; 462 | }; 463 | name = Release; 464 | }; 465 | /* End XCBuildConfiguration section */ 466 | 467 | /* Begin XCConfigurationList section */ 468 | BFF9B25E187AB88C00F93B58 /* Build configuration list for PBXProject "Spotify Bluetooth Headset Listener" */ = { 469 | isa = XCConfigurationList; 470 | buildConfigurations = ( 471 | BFF9B292187AB88E00F93B58 /* Debug */, 472 | BFF9B293187AB88E00F93B58 /* Release */, 473 | ); 474 | defaultConfigurationIsVisible = 0; 475 | defaultConfigurationName = Release; 476 | }; 477 | BFF9B294187AB88E00F93B58 /* Build configuration list for PBXNativeTarget "Spotify Bluetooth Headset Listener" */ = { 478 | isa = XCConfigurationList; 479 | buildConfigurations = ( 480 | BFF9B295187AB88E00F93B58 /* Debug */, 481 | BFF9B296187AB88E00F93B58 /* Release */, 482 | ); 483 | defaultConfigurationIsVisible = 0; 484 | defaultConfigurationName = Release; 485 | }; 486 | BFF9B297187AB88E00F93B58 /* Build configuration list for PBXNativeTarget "Spotify Bluetooth Headset ListenerTests" */ = { 487 | isa = XCConfigurationList; 488 | buildConfigurations = ( 489 | BFF9B298187AB88E00F93B58 /* Debug */, 490 | BFF9B299187AB88E00F93B58 /* Release */, 491 | ); 492 | defaultConfigurationIsVisible = 0; 493 | defaultConfigurationName = Release; 494 | }; 495 | /* End XCConfigurationList section */ 496 | }; 497 | rootObject = BFF9B25B187AB88C00F93B58 /* Project object */; 498 | } 499 | --------------------------------------------------------------------------------