diff --git a/MonitorControl/Enums/PrefKey.swift b/MonitorControl/Enums/PrefKey.swift
index 76b5f29..3f9a18e 100644
--- a/MonitorControl/Enums/PrefKey.swift
+++ b/MonitorControl/Enums/PrefKey.swift
@@ -212,4 +212,6 @@ enum KeyboardVolume: Int {
case custom = 1
case both = 2
case disabled = 3
+ /// Like `media`, but always captures volume/mute keys even when macOS can control the default output device.
+ case mediaForce = 4
}
diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist
index 39d5cf8..e06e3af 100644
--- a/MonitorControl/Info.plist
+++ b/MonitorControl/Info.plist
@@ -19,7 +19,7 @@
CFBundleShortVersionString
$(MARKETING_VERSION)
CFBundleVersion
- 7175
+ 7176
LSApplicationCategoryType
public.app-category.utilities
LSMinimumSystemVersion
diff --git a/MonitorControl/Support/AppDelegate.swift b/MonitorControl/Support/AppDelegate.swift
index 6d1013b..7d7525b 100644
--- a/MonitorControl/Support/AppDelegate.swift
+++ b/MonitorControl/Support/AppDelegate.swift
@@ -161,7 +161,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
func checkPermissions(firstAsk: Bool = false) {
- let permissionsRequired: Bool = [KeyboardVolume.media.rawValue, KeyboardVolume.both.rawValue].contains(prefs.integer(forKey: PrefKey.keyboardVolume.rawValue)) || [KeyboardBrightness.media.rawValue, KeyboardBrightness.both.rawValue].contains(prefs.integer(forKey: PrefKey.keyboardBrightness.rawValue))
+ let permissionsRequired: Bool = [KeyboardVolume.media.rawValue, KeyboardVolume.both.rawValue, KeyboardVolume.mediaForce.rawValue].contains(prefs.integer(forKey: PrefKey.keyboardVolume.rawValue)) || [KeyboardBrightness.media.rawValue, KeyboardBrightness.both.rawValue].contains(prefs.integer(forKey: PrefKey.keyboardBrightness.rawValue))
if !MediaKeyTapManager.readPrivileges(prompt: false), permissionsRequired {
MediaKeyTapManager.acquirePrivileges(firstAsk: firstAsk)
}
diff --git a/MonitorControl/Support/CustomHUD.swift b/MonitorControl/Support/CustomHUD.swift
index 9b69c7f..7a18777 100644
--- a/MonitorControl/Support/CustomHUD.swift
+++ b/MonitorControl/Support/CustomHUD.swift
@@ -3,10 +3,6 @@
import Cocoa
-#if swift(>=5.3)
-import SwiftUI
-#endif
-
// MARK: - Custom HUD Manager
/// Manages custom HUD windows for brightness/volume display on macOS 26+
@@ -181,11 +177,13 @@ class CustomHUDManager {
window.alphaValue = 1.0
window.orderFrontRegardless()
- // Schedule fade out after 1.5 seconds
- fadeTimers[displayID] = Timer.scheduledTimer(withTimeInterval: 1.5, repeats: false) { [weak self, weak window] _ in
+ // Schedule fade out after 1.5 seconds (common mode so it still fires during nested run-loop work)
+ let timer = Timer(timeInterval: 1.5, repeats: false) { [weak self, weak window] _ in
guard let window = window else { return }
self?.fadeOut(window: window)
}
+ fadeTimers[displayID] = timer
+ RunLoop.main.add(timer, forMode: .common)
}
private func fadeOut(window: NSWindow) {
diff --git a/MonitorControl/Support/DisplayManager.swift b/MonitorControl/Support/DisplayManager.swift
index f53d5bb..babf0c3 100644
--- a/MonitorControl/Support/DisplayManager.swift
+++ b/MonitorControl/Support/DisplayManager.swift
@@ -311,6 +311,9 @@ class DisplayManager {
}
func clearDisplays() {
+ for display in self.displays {
+ CustomHUDManager.shared.cleanupDisplay(display.identifier)
+ }
self.displays = []
}
diff --git a/MonitorControl/Support/MediaKeyTapManager.swift b/MonitorControl/Support/MediaKeyTapManager.swift
index f484a6e..5ebb97e 100644
--- a/MonitorControl/Support/MediaKeyTapManager.swift
+++ b/MonitorControl/Support/MediaKeyTapManager.swift
@@ -150,7 +150,7 @@ class MediaKeyTapManager: MediaKeyTapDelegate {
if [KeyboardBrightness.media.rawValue, KeyboardBrightness.both.rawValue].contains(prefs.integer(forKey: PrefKey.keyboardBrightness.rawValue)) {
keys.append(contentsOf: [.brightnessUp, .brightnessDown])
}
- if [KeyboardVolume.media.rawValue, KeyboardVolume.both.rawValue].contains(prefs.integer(forKey: PrefKey.keyboardVolume.rawValue)) {
+ if [KeyboardVolume.media.rawValue, KeyboardVolume.both.rawValue, KeyboardVolume.mediaForce.rawValue].contains(prefs.integer(forKey: PrefKey.keyboardVolume.rawValue)) {
keys.append(contentsOf: [.mute, .volumeUp, .volumeDown])
}
// Remove brightness keys if no external displays are connected, but only if brightness fine control is not active
@@ -166,8 +166,8 @@ class MediaKeyTapManager: MediaKeyTapDelegate {
let keysToDelete: [MediaKey] = [.brightnessUp, .brightnessDown]
keys.removeAll { keysToDelete.contains($0) }
}
- // Remove volume related keys if audio device is controllable
- if let defaultAudioDevice = app.coreAudio.defaultOutputDevice {
+ // Remove volume related keys if audio device is controllable (skip when user chose force-capture mode)
+ if prefs.integer(forKey: PrefKey.keyboardVolume.rawValue) != KeyboardVolume.mediaForce.rawValue, let defaultAudioDevice = app.coreAudio.defaultOutputDevice {
let keysToDelete: [MediaKey] = [.volumeUp, .volumeDown, .mute]
if prefs.integer(forKey: PrefKey.multiKeyboardVolume.rawValue) == MultiKeyboardVolume.audioDeviceNameMatching.rawValue {
if DisplayManager.shared.updateAudioControlTargetDisplays(deviceName: defaultAudioDevice.name) == 0 {
diff --git a/MonitorControl/Support/SliderHandler.swift b/MonitorControl/Support/SliderHandler.swift
index 320623f..7d2a3a0 100644
--- a/MonitorControl/Support/SliderHandler.swift
+++ b/MonitorControl/Support/SliderHandler.swift
@@ -360,9 +360,7 @@ class SliderHandler {
slider.floatValue = value
}
}
- if self.percentageBox == self.percentageBox {
- self.percentageBox?.stringValue = "" + String(Int(value * 100)) + "%"
- }
+ self.percentageBox?.stringValue = "" + String(Int(value * 100)) + "%"
for display in self.displays {
slider.setHighlightItem(display.identifier, value: value)
if self.command == .brightness, let appleDisplay = display as? AppleDisplay {
@@ -418,9 +416,7 @@ class SliderHandler {
} else {
slider.setDisplayHighlightItems(false)
}
- if self.percentageBox == self.percentageBox {
- self.percentageBox?.stringValue = "" + String(Int(value * 100)) + "%"
- }
+ self.percentageBox?.stringValue = "" + String(Int(value * 100)) + "%"
}
}
}
diff --git a/MonitorControl/UI/Base.lproj/Main.storyboard b/MonitorControl/UI/Base.lproj/Main.storyboard
index c269c53..a3b1e56 100644
--- a/MonitorControl/UI/Base.lproj/Main.storyboard
+++ b/MonitorControl/UI/Base.lproj/Main.storyboard
@@ -997,13 +997,14 @@
-
+