diff --git a/MonitorControl.xcodeproj/project.pbxproj b/MonitorControl.xcodeproj/project.pbxproj index 470f5a8..c4d3b00 100644 --- a/MonitorControl.xcodeproj/project.pbxproj +++ b/MonitorControl.xcodeproj/project.pbxproj @@ -313,11 +313,13 @@ ); inputPaths = ( "${SRCROOT}/Pods/Target Support Files/Pods-MonitorControl/Pods-MonitorControl-frameworks.sh", + "${BUILT_PRODUCTS_DIR}/AMCoreAudio/AMCoreAudio.framework", "${BUILT_PRODUCTS_DIR}/MASPreferences/MASPreferences.framework", "${BUILT_PRODUCTS_DIR}/MediaKeyTap/MediaKeyTap.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AMCoreAudio.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MASPreferences.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MediaKeyTap.framework", ); diff --git a/MonitorControl/AppDelegate.swift b/MonitorControl/AppDelegate.swift index 4e0e13e..592e565 100644 --- a/MonitorControl/AppDelegate.swift +++ b/MonitorControl/AppDelegate.swift @@ -11,6 +11,7 @@ import Cocoa import Foundation import MediaKeyTap import MASPreferences +import AMCoreAudio var app: AppDelegate! = nil let prefs = UserDefaults.standard @@ -36,12 +37,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ aNotification: Notification) { app = self - let listenFor = prefs.integer(forKey: Utils.PrefKeys.listenFor.rawValue) - if listenFor == Utils.ListenForKeys.brightnessOnlyKeys.rawValue { - keysListenedFor.removeSubrange(2...4) - } else if listenFor == Utils.ListenForKeys.volumeOnlyKeys.rawValue { - keysListenedFor.removeSubrange(0...1) - } + setVolumeKeysMode() mediaKeyTap = MediaKeyTap.init(delegate: self, for: keysListenedFor, observeBuiltIn: false) let storyboard: NSStoryboard = NSStoryboard.init(name: "Main", bundle: Bundle.main) @@ -55,6 +51,9 @@ class AppDelegate: NSObject, NSApplicationDelegate { NotificationCenter.default.addObserver(self, selector: #selector(handleListenForChanged), name: NSNotification.Name.init(Utils.PrefKeys.listenFor.rawValue), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(handleShowContrastChanged), name: NSNotification.Name.init(Utils.PrefKeys.showContrast.rawValue), object: nil) + // subscribe Audio output detector (AMCoreAudio) + NotificationCenter.defaultCenter.subscribe(self, eventType: AudioHardwareEvent.self, dispatchQueue: DispatchQueue.main) + statusItem.image = NSImage.init(named: "status") statusItem.menu = statusMenu @@ -203,8 +202,10 @@ class AppDelegate: NSObject, NSApplicationDelegate { extension AppDelegate: MediaKeyTapDelegate { func handle(mediaKey: MediaKey, event: KeyEvent?) { + guard let currentDisplay = Utils.getCurrentDisplay(from: displays) else { return } let allDisplays = prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) ? displays : [currentDisplay] + for display in allDisplays { if (prefs.object(forKey: "\(display.identifier)-state") as? Bool) ?? true { switch mediaKey { @@ -222,6 +223,7 @@ extension AppDelegate: MediaKeyTapDelegate { case .volumeDown: let value = display.calcNewValue(for: AUDIO_SPEAKER_VOLUME, withRel: -step) display.setVolume(to: value) + default: return } @@ -233,6 +235,22 @@ extension AppDelegate: MediaKeyTapDelegate { // MARK: - Prefs notification @objc func handleListenForChanged() { + + readKeyListenPreferences() + setKeysToListenFor() + } + + @objc func handleShowContrastChanged() { + self.updateDisplays() + } + + private func setKeysToListenFor() { + mediaKeyTap?.stop() + mediaKeyTap = MediaKeyTap.init(delegate: self, for: keysListenedFor, observeBuiltIn: false) + mediaKeyTap?.start() + } + + private func readKeyListenPreferences() { let listenFor = prefs.integer(forKey: Utils.PrefKeys.listenFor.rawValue) keysListenedFor = [.brightnessUp, .brightnessDown, .mute, .volumeUp, .volumeDown] if listenFor == Utils.ListenForKeys.brightnessOnlyKeys.rawValue { @@ -240,13 +258,49 @@ extension AppDelegate: MediaKeyTapDelegate { } else if listenFor == Utils.ListenForKeys.volumeOnlyKeys.rawValue { keysListenedFor.removeSubrange(0...1) } - - mediaKeyTap?.stop() - mediaKeyTap = MediaKeyTap.init(delegate: self, for: keysListenedFor, observeBuiltIn: false) - mediaKeyTap?.start() - } - - @objc func handleShowContrastChanged() { - self.updateDisplays() + } +} + +extension AppDelegate: EventSubscriber { + + /** + Fires off when a change in default audio device is detected. + */ + func eventReceiver(_ event: Event) { + + switch event { + case let event as AudioHardwareEvent: + switch event { + case .defaultOutputDeviceChanged(let audioDevice): + #if DEBUG + print("Default output device changed to \(audioDevice)") + print("Can device set its own volume? \(audioDevice.canSetVirtualMasterVolume(direction: .playback))") + #endif + setVolumeKeysMode() + default: break + } + default: break + } + } + + /** + We check if the current default audio output device can change the volume, + if not, we know for sure that we don't need to interact with it. + */ + func setVolumeKeysMode() { + + readKeyListenPreferences() + + if let defaultOutputDevice = AudioDevice.defaultOutputDevice() { + if defaultOutputDevice.canSetVirtualMasterVolume(direction: .playback) { + // Remove volume related keys + let keysToDelete: [MediaKey] = [.volumeUp, .volumeDown, .mute] + keysListenedFor = keysListenedFor.filter({ !keysToDelete.contains($0) }) + } else { + // load keys to listen to from prefs like normal + readKeyListenPreferences() + } + setKeysToListenFor() + } } } diff --git a/Podfile b/Podfile index fb675d6..e928394 100644 --- a/Podfile +++ b/Podfile @@ -7,4 +7,5 @@ target 'MonitorControl' do pod 'MediaKeyTap', :git => 'https://github.com/JoniVR/MediaKeyTap.git' pod 'MASPreferences', :git => 'https://github.com/JoniVR/MASPreferences.git' + pod 'AMCoreAudio', '~> 3.2' end diff --git a/Podfile.lock b/Podfile.lock index a3285f7..1daf432 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,11 +1,17 @@ PODS: + - AMCoreAudio (3.2.1) - MASPreferences (1.3) - MediaKeyTap (2.1.0) DEPENDENCIES: + - AMCoreAudio (~> 3.2) - MASPreferences (from `https://github.com/JoniVR/MASPreferences.git`) - MediaKeyTap (from `https://github.com/JoniVR/MediaKeyTap.git`) +SPEC REPOS: + https://github.com/cocoapods/specs.git: + - AMCoreAudio + EXTERNAL SOURCES: MASPreferences: :git: https://github.com/JoniVR/MASPreferences.git @@ -21,9 +27,10 @@ CHECKOUT OPTIONS: :git: https://github.com/JoniVR/MediaKeyTap.git SPEC CHECKSUMS: + AMCoreAudio: 7fa6b718dc93acc29f849d60c3ad680ae1bf07b5 MASPreferences: c08b8622dd17b47da87669e741efd7c92e970e8c MediaKeyTap: b652877e9ae2d52ca4f5310fa5152945ad3f0798 -PODFILE CHECKSUM: ef3a41f0dd719b389cc8241f6f5dd5fe52e55556 +PODFILE CHECKSUM: 947d8968124719d712379b2dbc0a24b1595515fe COCOAPODS: 1.5.3 diff --git a/README.md b/README.md index 9fd6d0e..d6cf83a 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ You're all set ! Now open the `MonitorControl.xcworkspace` with Xcode - [MediaKeyTap](https://github.com/JoniVR/MediaKeyTap) - [MASPreferences](https://github.com/JoniVR/MASPreferences) - [ddcctl](https://github.com/kfix/ddcctl) +- [AMCoreAudio](https://github.com/rnine/AMCoreAudio) ## Support - macOS Sierra (`10.12`) and up.