├── .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
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 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
76 |
77 |
83 |
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 |
--------------------------------------------------------------------------------