mirror of
https://github.com/MonitorControl/MonitorControl.git
synced 2026-05-15 14:15:55 -06:00
Fix non-standard volume/brightness scales not working properly (#245)
This commit is contained in:
parent
9ff4a939c5
commit
5cacd25d11
6 changed files with 76 additions and 28 deletions
|
|
@ -51,6 +51,7 @@
|
|||
F0445D40200259C10025AE82 /* DisplayPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0445D3F200259C10025AE82 /* DisplayPrefsViewController.swift */; };
|
||||
F06792EA200A73460066C438 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = F06792E9200A73460066C438 /* main.swift */; };
|
||||
F06792F6200A745F0066C438 /* MonitorControlHelper.app in [Login] Copy Helper to start at Login */ = {isa = PBXBuildFile; fileRef = F06792E7200A73460066C438 /* MonitorControlHelper.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
FE4E0896249D584C003A50BB /* OSDUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE4E0895249D584C003A50BB /* OSDUtils.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
|
|
@ -163,6 +164,7 @@
|
|||
F06792F0200A73470066C438 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
F06792F1200A73470066C438 /* MonitorControlHelper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MonitorControlHelper.entitlements; sourceTree = "<group>"; };
|
||||
F0A987D61F77B290009B603D /* OSD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OSD.framework; sourceTree = "<group>"; };
|
||||
FE4E0895249D584C003A50BB /* OSDUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSDUtils.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -291,6 +293,7 @@
|
|||
F01B0683228221B6008E64DB /* Utils.swift */,
|
||||
6C2EA1CC228F644B00060E3F /* OnlyIntegerValueFormatter.swift */,
|
||||
6C2EA1CE228F7DFB00060E3F /* PollingMode.swift */,
|
||||
FE4E0895249D584C003A50BB /* OSDUtils.swift */,
|
||||
);
|
||||
path = Support;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -531,6 +534,7 @@
|
|||
F03FE4C0228DF62B001F59A4 /* FriendlyNameCellView.swift in Sources */,
|
||||
6C2EA1CF228F7DFB00060E3F /* PollingMode.swift in Sources */,
|
||||
6CBFE27C23DB27A200D1BC41 /* InternalDisplay.swift in Sources */,
|
||||
FE4E0896249D584C003A50BB /* OSDUtils.swift in Sources */,
|
||||
6CBFE27A23DB266000D1BC41 /* Display.swift in Sources */,
|
||||
F03A8DF21FFBAA6F0034DC27 /* ExternalDisplay.swift in Sources */,
|
||||
F0445D40200259C10025AE82 /* DisplayPrefsViewController.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>647</string>
|
||||
<string>719</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import DDC
|
||||
import Foundation
|
||||
import os.log
|
||||
|
||||
class Display {
|
||||
internal let identifier: CGDirectDisplayID
|
||||
|
|
@ -42,7 +43,7 @@ class Display {
|
|||
return self.prefs.string(forKey: "friendlyName-\(self.identifier)") ?? self.name
|
||||
}
|
||||
|
||||
func showOsd(command: DDC.Command, value: Int, maxValue: Int = 100) {
|
||||
func showOsd(command: DDC.Command, value: Int, maxValue: Int = 100, roundChiclet: Bool = false) {
|
||||
guard let manager = OSDManager.sharedManager() as? OSDManager else {
|
||||
return
|
||||
}
|
||||
|
|
@ -59,12 +60,25 @@ class Display {
|
|||
osdImage = 1
|
||||
}
|
||||
|
||||
manager.showImage(osdImage,
|
||||
onDisplayID: self.identifier,
|
||||
priority: 0x1F4,
|
||||
msecUntilFade: 1000,
|
||||
filledChiclets: UInt32(value),
|
||||
totalChiclets: UInt32(maxValue),
|
||||
locked: false)
|
||||
if roundChiclet {
|
||||
let osdChiclet = OSDUtils.chiclet(fromValue: Float(value), maxValue: Float(maxValue))
|
||||
let filledChiclets = round(osdChiclet)
|
||||
|
||||
manager.showImage(osdImage,
|
||||
onDisplayID: self.identifier,
|
||||
priority: 0x1F4,
|
||||
msecUntilFade: 1000,
|
||||
filledChiclets: UInt32(filledChiclets),
|
||||
totalChiclets: UInt32(16),
|
||||
locked: false)
|
||||
} else {
|
||||
manager.showImage(osdImage,
|
||||
onDisplayID: self.identifier,
|
||||
priority: 0x1F4,
|
||||
msecUntilFade: 1000,
|
||||
filledChiclets: UInt32(value),
|
||||
totalChiclets: UInt32(maxValue),
|
||||
locked: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ class ExternalDisplay: Display {
|
|||
}
|
||||
|
||||
private var audioPlayer: AVAudioPlayer?
|
||||
private let osdChicletBoxes: Float = 16
|
||||
|
||||
override init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?) {
|
||||
super.init(identifier, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber)
|
||||
|
|
@ -90,7 +89,7 @@ class ExternalDisplay: Display {
|
|||
|
||||
if !fromVolumeSlider {
|
||||
self.hideDisplayOsd()
|
||||
self.showOsd(command: volumeOSDValue > 0 ? .audioSpeakerVolume : .audioMuteScreenBlank, value: volumeOSDValue)
|
||||
self.showOsd(command: volumeOSDValue > 0 ? .audioSpeakerVolume : .audioMuteScreenBlank, value: volumeOSDValue, roundChiclet: true)
|
||||
|
||||
if volumeOSDValue > 0 {
|
||||
self.playVolumeChangedSound()
|
||||
|
|
@ -106,7 +105,6 @@ class ExternalDisplay: Display {
|
|||
var muteValue: Int?
|
||||
let volumeOSDValue = self.calcNewValue(for: .audioSpeakerVolume, isUp: isUp, isSmallIncrement: isSmallIncrement)
|
||||
let volumeDDCValue = UInt16(volumeOSDValue)
|
||||
|
||||
if self.isMuted(), volumeOSDValue > 0 {
|
||||
muteValue = 2
|
||||
} else if !self.isMuted(), volumeOSDValue == 0 {
|
||||
|
|
@ -132,7 +130,7 @@ class ExternalDisplay: Display {
|
|||
}
|
||||
|
||||
self.hideDisplayOsd()
|
||||
self.showOsd(command: .audioSpeakerVolume, value: volumeOSDValue)
|
||||
self.showOsd(command: .audioSpeakerVolume, value: volumeOSDValue, roundChiclet: !isSmallIncrement)
|
||||
|
||||
if !isAlreadySet {
|
||||
self.saveValue(volumeOSDValue, for: .audioSpeakerVolume)
|
||||
|
|
@ -163,7 +161,7 @@ class ExternalDisplay: Display {
|
|||
}
|
||||
}
|
||||
|
||||
self.showOsd(command: .brightness, value: osdValue)
|
||||
self.showOsd(command: .brightness, value: osdValue, roundChiclet: !isSmallIncrement)
|
||||
|
||||
if !isAlreadySet {
|
||||
if let slider = self.brightnessSliderHandler?.slider {
|
||||
|
|
@ -221,25 +219,32 @@ class ExternalDisplay: Display {
|
|||
func calcNewValue(for command: DDC.Command, isUp: Bool, isSmallIncrement: Bool) -> Int {
|
||||
let currentValue = self.getValue(for: command)
|
||||
let nextValue: Int
|
||||
let maxValue = Float(self.getMaxValue(for: command))
|
||||
|
||||
if isSmallIncrement {
|
||||
nextValue = currentValue + (isUp ? 1 : -1)
|
||||
} else {
|
||||
let filledChicletBoxes = self.osdChicletBoxes * (Float(currentValue) / Float(self.getMaxValue(for: command)))
|
||||
let osdChicletFromValue = OSDUtils.chiclet(fromValue: Float(currentValue), maxValue: maxValue)
|
||||
|
||||
var nextFilledChicletBoxes: Float
|
||||
var filledChicletBoxesRel: Float = isUp ? 1 : -1
|
||||
let distance = OSDUtils.getDistance(fromNearestChiclet: osdChicletFromValue)
|
||||
// get the next rounded chiclet
|
||||
var nextFilledChiclet = isUp ? ceil(osdChicletFromValue) : floor(osdChicletFromValue)
|
||||
|
||||
// This is a workaround to ensure that if the user has set the value using a small step (that is, the current chiclet box isn't completely filled,
|
||||
// the next regular up or down step will only fill or empty that chiclet, and not the next one as well - it only really works because the max value is 100
|
||||
if (isUp && ceil(filledChicletBoxes) - filledChicletBoxes > 0.15) || (!isUp && filledChicletBoxes - floor(filledChicletBoxes) > 0.15) {
|
||||
filledChicletBoxesRel = 0
|
||||
// Depending on the direction, if the chiclet is above or below a certain threshold, we go to the next whole chiclet
|
||||
let distanceThreshold = Float(0.25) // 25% of the distance between the edges of an osd box
|
||||
if distance == 0 {
|
||||
nextFilledChiclet += isUp ? 1 : -1
|
||||
} else if !isUp, distance < distanceThreshold {
|
||||
nextFilledChiclet -= 1
|
||||
} else if isUp, distance > (1 - distanceThreshold) {
|
||||
nextFilledChiclet += 1
|
||||
}
|
||||
|
||||
nextFilledChicletBoxes = isUp ? ceil(filledChicletBoxes + filledChicletBoxesRel) : floor(filledChicletBoxes + filledChicletBoxesRel)
|
||||
nextValue = Int(Float(self.getMaxValue(for: command)) * (nextFilledChicletBoxes / self.osdChicletBoxes))
|
||||
nextValue = Int(round(OSDUtils.value(fromChiclet: nextFilledChiclet, maxValue: maxValue)))
|
||||
|
||||
os_log("next: .value %{public}@/%{public}@, .osd %{public}@/%{public}@", type: .debug, String(nextValue), String(maxValue), String(nextFilledChiclet), String(OSDUtils.chicletCount))
|
||||
}
|
||||
return max(0, min(self.getMaxValue(for: command), Int(nextValue)))
|
||||
return max(0, min(self.getMaxValue(for: command), nextValue))
|
||||
}
|
||||
|
||||
func getValue(for command: DDC.Command) -> Int {
|
||||
|
|
@ -308,11 +313,11 @@ class ExternalDisplay: Display {
|
|||
}
|
||||
|
||||
private func stepSize(for command: DDC.Command, isSmallIncrement: Bool) -> Int {
|
||||
return isSmallIncrement ? 1 : Int(floor(Float(self.getMaxValue(for: command)) / self.osdChicletBoxes))
|
||||
return isSmallIncrement ? 1 : Int(floor(Float(self.getMaxValue(for: command)) / OSDUtils.chicletCount))
|
||||
}
|
||||
|
||||
override func showOsd(command: DDC.Command, value: Int, maxValue _: Int = 100) {
|
||||
super.showOsd(command: command, value: value, maxValue: self.getMaxValue(for: command))
|
||||
override func showOsd(command: DDC.Command, value: Int, maxValue _: Int = 100, roundChiclet: Bool = false) {
|
||||
super.showOsd(command: command, value: value, maxValue: self.getMaxValue(for: command), roundChiclet: roundChiclet)
|
||||
}
|
||||
|
||||
private func supportsMuteCommand() -> Bool {
|
||||
|
|
|
|||
25
MonitorControl/Support/OSDUtils.swift
Normal file
25
MonitorControl/Support/OSDUtils.swift
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// OSDUtils.swift
|
||||
// MonitorControl
|
||||
//
|
||||
// Created by Victor Chabbert on 19/06/2020.
|
||||
// Copyright © 2020 Guillaume Broder. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
class OSDUtils: NSObject {
|
||||
static let chicletCount: Float = 16
|
||||
|
||||
static func chiclet(fromValue value: Float, maxValue: Float) -> Float {
|
||||
return (value * self.chicletCount) / maxValue
|
||||
}
|
||||
|
||||
static func value(fromChiclet chiclet: Float, maxValue: Float) -> Float {
|
||||
return (chiclet * maxValue) / self.chicletCount
|
||||
}
|
||||
|
||||
static func getDistance(fromNearestChiclet chiclet: Float) -> Float {
|
||||
return abs(chiclet.rounded(.towardZero) - chiclet)
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>647</string>
|
||||
<string>719</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSBackgroundOnly</key>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue