♻️ Refactoring + Identifier + Mute

- I've rewritten some so it should easier to read now
- Mute should work like on a mac, meaning you can mute and unmute back to the previous volume
- Removed the "default" system as I now use the "main" screen for keyboard shortcuts, meaning, in a multiple screen environement you can now control the current screen with your keyboard
- I now use the `identifier` instead of `serial` of the display for saving value, should fix (hopefully) #6

Signed-off-by: Guillaume Broder <iamnotheoneyouseek@gmail.com>
This commit is contained in:
Guillaume Broder 2018-01-07 21:43:10 +01:00
parent e45fb6e705
commit 1112380361
No known key found for this signature in database
GPG key ID: 66FB02D063D9E08F
5 changed files with 115 additions and 82 deletions

View file

@ -25,11 +25,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, MediaKeyTapDelegate {
var monitorItems: [NSMenuItem] = []
var displays: [Display] = []
var sliderHandlers: [SliderHandler] = []
var defaultDisplay: Display! = nil
var defaultBrightnessSlider: NSSlider! = nil
var defaultVolumeSlider: NSSlider! = nil
let step = 100/16
@ -89,17 +84,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, MediaKeyTapDelegate {
// MARK: - Menu
func clearDisplays() {
defaultDisplay = nil
defaultBrightnessSlider = nil
defaultVolumeSlider = nil
for monitor in monitorItems {
statusMenu.removeItem(monitor)
}
monitorItems = []
displays = []
sliderHandlers = []
}
func updateDisplays() {
@ -122,8 +112,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, MediaKeyTapDelegate {
let name = Utils.getDisplayName(forEdid: edid)
let serial = Utils.getDisplaySerial(forEdid: edid)
let display = Display(identifier: id, name: name, serial: serial, isEnabled: true)
displays.append(display)
let display = Display.init(id, name: name, serial: serial)
let monitorSubMenu = NSMenu()
let brightnessSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu,
@ -134,21 +123,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, MediaKeyTapDelegate {
forDisplay: display,
command: AUDIO_SPEAKER_VOLUME,
title: NSLocalizedString("Volume", comment: "Shown in menu"))
sliderHandlers.append(brightnessSliderHandler)
sliderHandlers.append(volumeSliderHandler)
let isDefaultDisplay = defaultDisplay == nil
let defaultMonitorSelectButtom = NSButton(frame: NSRect(x: 25, y: 0, width: 200, height: 25))
defaultMonitorSelectButtom.title = isDefaultDisplay ? NSLocalizedString("Default", comment: "Shown in menu") : NSLocalizedString("Set as default", comment: "Shown in menu")
defaultMonitorSelectButtom.bezelStyle = NSButton.BezelStyle.rounded
defaultMonitorSelectButtom.isEnabled = !isDefaultDisplay
let defaultMonitorView = NSView(frame: NSRect(x: 0, y: 5, width: 250, height: 25))
defaultMonitorView.addSubview(defaultMonitorSelectButtom)
let defaultMonitorItem = NSMenuItem()
defaultMonitorItem.view = defaultMonitorView
monitorSubMenu.addItem(defaultMonitorItem)
display.brightnessSliderHandler = brightnessSliderHandler
display.volumeSliderHandler = volumeSliderHandler
displays.append(display)
let monitorMenuItem = NSMenuItem()
monitorMenuItem.title = "\(name)"
@ -156,16 +133,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, MediaKeyTapDelegate {
monitorItems.append(monitorMenuItem)
statusMenu.insertItem(monitorMenuItem, at: displays.count - 1)
if isDefaultDisplay {
defaultDisplay = display
defaultBrightnessSlider = brightnessSliderHandler.slider
defaultVolumeSlider = volumeSliderHandler.slider
}
}
}
if defaultDisplay == nil {
if displays.count == 0 {
// If no DDC capable display was detected
let item = NSMenuItem()
item.title = NSLocalizedString("No supported display found", comment: "Shown in menu")
@ -178,60 +149,32 @@ class AppDelegate: NSObject, NSApplicationDelegate, MediaKeyTapDelegate {
// MARK: - Media Key Tap delegate
func handle(mediaKey: MediaKey, event: KeyEvent) {
var command = BRIGHTNESS
guard let currentDisplay = Utils.getCurrentDisplay(from: displays) else { return }
var rel = 0
var slider = self.defaultBrightnessSlider
switch mediaKey {
case .brightnessUp:
rel = +self.step
let value = currentDisplay.calcNewValue(for: BRIGHTNESS, withRel: rel)
currentDisplay.setBrightness(to: value)
case .brightnessDown:
rel = -self.step
let value = currentDisplay.calcNewValue(for: BRIGHTNESS, withRel: rel)
currentDisplay.setBrightness(to: value)
case .mute:
rel = -100
command = AUDIO_SPEAKER_VOLUME
slider = self.defaultVolumeSlider
currentDisplay.mute()
case .volumeUp:
rel = +self.step
command = AUDIO_SPEAKER_VOLUME
slider = self.defaultVolumeSlider
let value = currentDisplay.calcNewValue(for: AUDIO_SPEAKER_VOLUME, withRel: rel)
currentDisplay.setVolume(to: value)
case .volumeDown:
rel = -self.step
command = AUDIO_SPEAKER_VOLUME
slider = self.defaultVolumeSlider
let value = currentDisplay.calcNewValue(for: AUDIO_SPEAKER_VOLUME, withRel: rel)
currentDisplay.setVolume(to: value)
default:
return
}
let k = "\(command)-\(self.defaultDisplay.serial)"
let value = max(0, min(100, prefs.integer(forKey: k) + rel))
prefs.setValue(value, forKey: k)
prefs.synchronize()
if let slider = slider {
slider.intValue = Int32(value)
}
Utils.ddcctl(monitor: self.defaultDisplay.identifier, command: command, value: value)
// OSD
if let manager = OSDManager.sharedManager() as? OSDManager {
var osdImage: Int64 = 1 // Brightness Image
if command == AUDIO_SPEAKER_VOLUME {
osdImage = 3 // Speaker image
if value == 0 {
osdImage = 4 // Mute speaker
}
}
manager.showImage(osdImage,
onDisplayID: self.defaultDisplay.identifier,
priority: 0x1f4,
msecUntilFade: 2000,
filledChiclets: UInt32(value/self.step),
totalChiclets: UInt32(100/self.step),
locked: false)
}
}
}

View file

@ -9,9 +9,86 @@
import Cocoa
/// A display
struct Display {
var identifier: CGDirectDisplayID
var name: String
var serial: String
var isEnabled: Bool = true
class Display {
let identifier: CGDirectDisplayID
let name: String
let serial: String
var isEnabled: Bool
var isMuted: Bool = false
var brightnessSliderHandler: SliderHandler?
var volumeSliderHandler: SliderHandler?
init(_ identifier: CGDirectDisplayID, name: String, serial: String, isEnabled: Bool = true) {
self.identifier = identifier
self.name = name
self.serial = serial
self.isEnabled = isEnabled
}
func mute() {
var value = 0
if isMuted {
value = UserDefaults.standard.integer(forKey: "\(AUDIO_SPEAKER_VOLUME)-\(identifier)")
isMuted = false
} else {
isMuted = true
}
Utils.ddcctl(monitor: identifier, command: AUDIO_SPEAKER_VOLUME, value: value)
if let slider = volumeSliderHandler?.slider {
slider.intValue = Int32(value)
}
showOsd(command: AUDIO_SPEAKER_VOLUME, value: value)
}
func setVolume(to value: Int) {
if value > 0 {
isMuted = false
}
Utils.ddcctl(monitor: identifier, command: AUDIO_SPEAKER_VOLUME, value: value)
if let slider = volumeSliderHandler?.slider {
slider.intValue = Int32(value)
}
showOsd(command: AUDIO_SPEAKER_VOLUME, value: value)
saveValue(value, for: AUDIO_SPEAKER_VOLUME)
}
func setBrightness(to value: Int) {
Utils.ddcctl(monitor: identifier, command: BRIGHTNESS, value: value)
if let slider = brightnessSliderHandler?.slider {
slider.intValue = Int32(value)
}
showOsd(command: BRIGHTNESS, value: value)
saveValue(value, for: BRIGHTNESS)
}
func calcNewValue(for command: Int32, withRel rel: Int) -> Int {
let currentValue = UserDefaults.standard.integer(forKey: "\(command)-\(identifier)")
return max(0, min(100, currentValue + rel))
}
func saveValue(_ value: Int, for command: Int32) {
UserDefaults.standard.set(value, forKey: "\(command)-\(identifier)")
}
private func showOsd(command: Int32, value: Int) {
if let manager = OSDManager.sharedManager() as? OSDManager {
var osdImage: Int64 = 1 // Brightness Image
if command == AUDIO_SPEAKER_VOLUME {
osdImage = 3 // Speaker image
if isMuted {
osdImage = 4 // Mute speaker
}
}
let step = 100/16
manager.showImage(osdImage,
onDisplayID: identifier,
priority: 0x1f4,
msecUntilFade: 2000,
filledChiclets: UInt32(value/step),
totalChiclets: UInt32(100/step),
locked: false)
}
}
}

View file

@ -32,8 +32,6 @@ class SliderHandler {
}
Utils.ddcctl(monitor: display.identifier, command: command, value: value)
prefs.setValue(value, forKey: "\(command)-\(display.serial)")
prefs.synchronize()
prefs.setValue(value, forKey: "\(command)-\(display.identifier)")
}
}

View file

@ -53,7 +53,7 @@ class DisplayPrefsViewController: NSViewController, MASPreferencesViewController
if let id = screen.deviceDescription[NSDeviceDescriptionKey.init("NSScreenNumber")] as? CGDirectDisplayID {
// Is Built In Screen (e.g. MBP/iMac Screen)
if CGDisplayIsBuiltin(id) != 0 {
let display = Display(identifier: id, name: "Mac built-in Display", serial: "", isEnabled: false)
let display = Display(id, name: "Mac built-in Display", serial: "", isEnabled: false)
displays.append(display)
continue
}
@ -71,7 +71,7 @@ class DisplayPrefsViewController: NSViewController, MASPreferencesViewController
isEnabled = enabled
}
let display = Display(identifier: id, name: name, serial: serial, isEnabled: isEnabled)
let display = Display(id, name: name, serial: serial, isEnabled: isEnabled)
displays.append(display)
}
}

View file

@ -147,6 +147,21 @@ class Utils: NSObject {
return getDescriptorString(edid, 0xFF) ?? NSLocalizedString("Unknown", comment: "")
}
/// Get the main display from a list of display
///
/// - Parameter displays: List of Display
/// - Returns: the main display or nil if not found
static func getCurrentDisplay(from displays: [Display]) -> Display? {
return displays.first { display -> Bool in
if let main = NSScreen.main {
if let id = main.deviceDescription[NSDeviceDescriptionKey.init("NSScreenNumber")] as? CGDirectDisplayID {
return display.identifier == id
}
}
return false
}
}
/// UserDefault Keys for the app prefs
enum PrefKeys: String {
/// Was the app launched once