mirror of
https://github.com/MonitorControl/MonitorControl.git
synced 2026-05-15 14:15:55 -06:00
Tahoe PR: HUD cleanup, force volume keys, slider/CustomHUD fixes
- Add KeyboardVolume.mediaForce and UI for always capturing volume/mute keys - Clean up CustomHUD windows when displays are cleared - Fix SliderHandler percentage label update (remove tautology check) - CustomHUD: RunLoop.common timer, drop unused SwiftUI import - Widen volume control popup for new menu item; en Main.strings Made-with: Cursor
This commit is contained in:
parent
c6a8fe97b6
commit
8a2e7f1e62
11 changed files with 23 additions and 20 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>7175</string>
|
||||
<string>7176</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -311,6 +311,9 @@ class DisplayManager {
|
|||
}
|
||||
|
||||
func clearDisplays() {
|
||||
for display in self.displays {
|
||||
CustomHUDManager.shared.cleanupDisplay(display.identifier)
|
||||
}
|
||||
self.displays = []
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)) + "%"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -997,13 +997,14 @@
|
|||
</gridCell>
|
||||
<gridCell row="6od-Ek-qTW" column="EiG-65-CTv" xPlacement="leading" id="pCd-dP-Y62">
|
||||
<popUpButton key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="9oZ-JM-bxD">
|
||||
<rect key="frame" x="217" y="187" width="293" height="25"/>
|
||||
<rect key="frame" x="217" y="187" width="360" height="25"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Standard keyboard volume and mute keys" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="1sy-Kd-WL5" id="gTf-PQ-2fA">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="message"/>
|
||||
<menu key="menu" id="LhY-cM-Msq">
|
||||
<items>
|
||||
<menuItem title="Standard keyboard volume and mute keys" state="on" id="1sy-Kd-WL5"/>
|
||||
<menuItem title="Standard keys (force capture)" tag="4" id="fVk-mR-9Xp"/>
|
||||
<menuItem title="Custom keyboard shortcuts" tag="1" id="4CG-0I-anB"/>
|
||||
<menuItem title="Both standard and custom shortcuts" tag="2" id="QDG-SA-mRX">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
|
|
|
|||
|
|
@ -415,5 +415,8 @@
|
|||
/* Class = "NSButtonCell"; title = "Show percentages"; ObjectID = "ZUu-MR-XwA"; */
|
||||
"ZUu-MR-XwA.title" = "Show percentages";
|
||||
|
||||
/* Class = "NSMenuItem"; title = "Standard keys (force capture)"; ObjectID = "fVk-mR-9Xp"; */
|
||||
"fVk-mR-9Xp.title" = "Standard keys (force capture)";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Combined dimming switchover point:"; ObjectID = "zv8-pZ-OPy"; */
|
||||
"zv8-pZ-OPy.title" = "Combined dimming switchover point:";
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class OnboardingViewController: NSViewController {
|
|||
// MARK: - Style
|
||||
|
||||
private func setPermissionsButtonState() {
|
||||
let volumePermissions: Bool = [KeyboardVolume.media.rawValue, KeyboardVolume.both.rawValue].contains(prefs.integer(forKey: PrefKey.keyboardVolume.rawValue))
|
||||
let volumePermissions: Bool = [KeyboardVolume.media.rawValue, KeyboardVolume.both.rawValue, KeyboardVolume.mediaForce.rawValue].contains(prefs.integer(forKey: PrefKey.keyboardVolume.rawValue))
|
||||
let brigthnessPermissions: Bool = [KeyboardBrightness.media.rawValue, KeyboardBrightness.both.rawValue].contains(prefs.integer(forKey: PrefKey.keyboardBrightness.rawValue))
|
||||
let permissionsRequired: Bool = volumePermissions || brigthnessPermissions
|
||||
let enabled: Bool = !MediaKeyTapManager.readPrivileges(prompt: false) && permissionsRequired
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>7175</string>
|
||||
<string>7176</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSBackgroundOnly</key>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue