diff --git a/.swiftlint.yml b/.swiftlint.yml
index b156b01b..b508d7b9 100644
--- a/.swiftlint.yml
+++ b/.swiftlint.yml
@@ -6,3 +6,4 @@ excluded:
- Pods
type_body_length: 500
file_length: 500
+cyclomatic_complexity: 11
diff --git a/MonitorControl.xcodeproj/project.pbxproj b/MonitorControl.xcodeproj/project.pbxproj
index c5d301b0..783e44f6 100644
--- a/MonitorControl.xcodeproj/project.pbxproj
+++ b/MonitorControl.xcodeproj/project.pbxproj
@@ -359,7 +359,7 @@
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-MonitorControl/Pods-MonitorControl-frameworks.sh",
+ "${PODS_ROOT}/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",
@@ -372,7 +372,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-MonitorControl/Pods-MonitorControl-frameworks.sh\"\n";
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-MonitorControl/Pods-MonitorControl-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
C0EF20D28FC7408CBE89A686 /* [CP] Check Pods Manifest.lock */ = {
diff --git a/MonitorControl/AppDelegate.swift b/MonitorControl/AppDelegate.swift
index dffcda88..7a2fecd6 100644
--- a/MonitorControl/AppDelegate.swift
+++ b/MonitorControl/AppDelegate.swift
@@ -212,11 +212,26 @@ extension AppDelegate: MediaKeyTapDelegate {
if (prefs.object(forKey: "\(display.identifier)-state") as? Bool) ?? true {
switch mediaKey {
case .brightnessUp:
- let value = display.calcNewValue(for: BRIGHTNESS, withRel: +step)
- display.setBrightness(to: value)
+ var brightnessValue = display.readValue(for: BRIGHTNESS)
+ var contrastValue = display.readValue(for: CONTRAST)
+ // increase brightness after contrast
+ if contrastValue < 70 && brightnessValue == 0 && prefs.bool(forKey: Utils.PrefKeys.lowerContrast.rawValue) {
+ contrastValue = display.calcNewValue(for: CONTRAST, withRel: +step)
+ display.setContrast(to: contrastValue)
+ } else {
+ brightnessValue = display.calcNewValue(for: BRIGHTNESS, withRel: +step)
+ }
+ display.setBrightness(to: brightnessValue)
case .brightnessDown:
- let value = currentDisplay.calcNewValue(for: BRIGHTNESS, withRel: -step)
- display.setBrightness(to: value)
+ var brightnessValue = display.readValue(for: BRIGHTNESS)
+ // lower contrast after brightness
+ if brightnessValue <= 0 && prefs.bool(forKey: Utils.PrefKeys.lowerContrast.rawValue) {
+ let contrastValue = display.calcNewValue(for: CONTRAST, withRel: -step)
+ display.setContrast(to: contrastValue)
+ } else {
+ brightnessValue = display.calcNewValue(for: BRIGHTNESS, withRel: -step)
+ }
+ display.setBrightness(to: brightnessValue)
case .mute:
display.mute()
case .volumeUp:
@@ -225,13 +240,11 @@ extension AppDelegate: MediaKeyTapDelegate {
case .volumeDown:
let value = display.calcNewValue(for: AUDIO_SPEAKER_VOLUME, withRel: -step)
display.setVolume(to: value)
-
default:
return
}
}
}
-
}
// MARK: - Prefs notification
diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist
index 6a0afd04..69678096 100644
--- a/MonitorControl/Info.plist
+++ b/MonitorControl/Info.plist
@@ -19,7 +19,7 @@
CFBundleShortVersionString
1.3.1
CFBundleVersion
- 99
+ 105
LSApplicationCategoryType
public.app-category.utilities
LSMinimumSystemVersion
diff --git a/MonitorControl/Objects/Display.swift b/MonitorControl/Objects/Display.swift
index cf0f9eb6..7fd2888d 100644
--- a/MonitorControl/Objects/Display.swift
+++ b/MonitorControl/Objects/Display.swift
@@ -58,18 +58,6 @@ class Display {
}
func setBrightness(to value: Int) {
- if prefs.bool(forKey: Utils.PrefKeys.lowerContrast.rawValue) {
- if value == 0 {
- Utils.sendCommand(CONTRAST, toMonitor: identifier, withValue: value)
- if let slider = contrastSliderHandler?.slider {
- slider.intValue = Int32(value)
- }
- } else if prefs.integer(forKey: "\(BRIGHTNESS)-\(identifier)") == 0 {
- let contrastValue = prefs.integer(forKey: "\(CONTRAST)-\(identifier)")
- Utils.sendCommand(CONTRAST, toMonitor: identifier, withValue: contrastValue)
- }
- }
-
Utils.sendCommand(BRIGHTNESS, toMonitor: identifier, withValue: value)
if let slider = brightnessSliderHandler?.slider {
slider.intValue = Int32(value)
@@ -78,15 +66,28 @@ class Display {
saveValue(value, for: BRIGHTNESS)
}
- func calcNewValue(for command: Int32, withRel rel: Int) -> Int {
+ func setContrast(to value: Int) {
+ Utils.sendCommand(CONTRAST, toMonitor: identifier, withValue: value)
+ if let slider = contrastSliderHandler?.slider {
+ slider.intValue = Int32(value)
+ }
+ saveValue(value, for: CONTRAST)
+ }
+
+ func calcNewValue(for command: Int32, withRel rel: Int) -> Int {
+ let maxValue = command == CONTRAST ? 70 : 100
let currentValue = prefs.integer(forKey: "\(command)-\(identifier)")
- return max(0, min(100, currentValue + rel))
+ return max(0, min(maxValue, currentValue + rel))
}
func saveValue(_ value: Int, for command: Int32) {
prefs.set(value, forKey: "\(command)-\(identifier)")
}
+ func readValue(for command: Int32) -> Int {
+ return prefs.integer(forKey: "\(command)-\(identifier)")
+ }
+
private func showOsd(command: Int32, value: Int) {
if let manager = OSDManager.sharedManager() as? OSDManager {
var osdImage: Int64 = 1 // Brightness Image
diff --git a/MonitorControl/Util/Extensions.swift b/MonitorControl/Util/Extensions.swift
index 65cc85cd..18787295 100644
--- a/MonitorControl/Util/Extensions.swift
+++ b/MonitorControl/Util/Extensions.swift
@@ -4,6 +4,7 @@
//
// Created by Joni Van Roost on 15/01/2019.
// Copyright © 2019 Mathew Kurian. All rights reserved.
+// MIT Licensed.
//
import AppKit
diff --git a/MonitorControl/Util/Utils.swift b/MonitorControl/Util/Utils.swift
index 9a62ffe1..95664055 100644
--- a/MonitorControl/Util/Utils.swift
+++ b/MonitorControl/Util/Utils.swift
@@ -9,59 +9,59 @@
import Cocoa
class Utils: NSObject {
- private static func printCommandValue(_ command: Int32, _ value: Int) {
- let cmdString: (Int32) -> String? = {
- switch $0 {
- case BRIGHTNESS:
- return "Brightness"
- case CONTRAST:
- return "Contrast"
- case AUDIO_SPEAKER_VOLUME:
- return "Volume"
- default:
- return nil
- }
- }
-
- print("\(cmdString(command) ?? "N/A") value: \(value)")
- }
-
- // MARK: - DDCCTL
-
- /// Send command to ddcctl
- ///
- /// - Parameters:
- /// - command: The command to send
- /// - monitor: The id of the Monitor to send the command to
- /// - value: the value of the command
- static func sendCommand(_ command: Int32, toMonitor monitor: CGDirectDisplayID, withValue value: Int) {
- var wrcmd = DDCWriteCommand(control_id: UInt8(command), new_value: UInt8(value))
- DDCWrite(monitor, &wrcmd)
-
- #if DEBUG
- printCommandValue(command, value)
- #endif
- }
-
- /// Get current value of ddcctl command
- ///
- /// - Parameters:
- /// - command: The command to send
- /// - monitor: The id of the monitor to send the command to
- /// - Returns: the value of the command
- static func getCommand(_ command: Int32, fromMonitor monitor: CGDirectDisplayID) -> Int? {
- var readCmd = DDCReadCommand()
- readCmd.control_id = UInt8(command)
- readCmd.max_value = 0
- readCmd.current_value = 0
- DDCRead(monitor, &readCmd)
-
- #if DEBUG
- printCommandValue(command, Int(readCmd.current_value))
- #endif
-
- return readCmd.success ? Int(readCmd.current_value) : nil
- }
+ private static func printCommandValue(_ command: Int32, _ value: Int) {
+ let cmdString: (Int32) -> String? = {
+ switch $0 {
+ case BRIGHTNESS:
+ return "Brightness"
+ case CONTRAST:
+ return "Contrast"
+ case AUDIO_SPEAKER_VOLUME:
+ return "Volume"
+ default:
+ return nil
+ }
+ }
+
+ print("\(cmdString(command) ?? "N/A") value: \(value)")
+ }
+
+ // MARK: - DDCCTL
+
+ /// Send command to ddcctl
+ ///
+ /// - Parameters:
+ /// - command: The command to send
+ /// - monitor: The id of the Monitor to send the command to
+ /// - value: the value of the command
+ static func sendCommand(_ command: Int32, toMonitor monitor: CGDirectDisplayID, withValue value: Int) {
+ var wrcmd = DDCWriteCommand(control_id: UInt8(command), new_value: UInt8(value))
+ DDCWrite(monitor, &wrcmd)
+
+ #if DEBUG
+ printCommandValue(command, value)
+ #endif
+ }
+
+ /// Get current value of ddcctl command
+ ///
+ /// - Parameters:
+ /// - command: The command to send
+ /// - monitor: The id of the monitor to send the command to
+ /// - Returns: the value of the command
+ static func getCommand(_ command: Int32, fromMonitor monitor: CGDirectDisplayID) -> Int? {
+ var readCmd = DDCReadCommand()
+ readCmd.control_id = UInt8(command)
+ readCmd.max_value = 0
+ readCmd.current_value = 0
+ DDCRead(monitor, &readCmd)
+
+ #if DEBUG
+ printCommandValue(command, Int(readCmd.current_value))
+ #endif
+
+ return readCmd.success ? Int(readCmd.current_value) : nil
+ }
/// MARK - General
@@ -103,7 +103,6 @@ class Utils: NSObject {
static func updateDockAutohide() {
if let currentDockAutohideState = shell("defaults read com.apple.dock autohide") {
let externalScreenCount = NSScreen.externalScreens().count
-
if externalScreenCount == 0 && currentDockAutohideState == "0" {
#if DEBUG
print("Enable Dock autohide")
@@ -118,200 +117,196 @@ class Utils: NSObject {
}
}
- // MARK: - Menu
-
- /// Create a label
- ///
- /// - Parameters:
- /// - text: The text of the label
- /// - frame: The frame of the label
- /// - Returns: An `NSTextField` label
- static func makeLabel(text: String, frame: NSRect) -> NSTextField {
- let label = NSTextField(frame: frame)
- label.stringValue = text
- label.isBordered = false
- label.isBezeled = false
- label.isEditable = false
- label.drawsBackground = false
- return label
- }
-
- /// Create a slider and add it to the menu
- ///
- /// - Parameters:
- /// - menu: Menu containing the slider
- /// - display: Display to control
- /// - command: Command (Brightness/Volume/...)
- /// - title: Title of the slider
- /// - Returns: An `NSSlider` slider
- static func addSliderMenuItem(toMenu menu: NSMenu, forDisplay display: Display, command: Int32, title: String) -> SliderHandler {
- let item = NSMenuItem()
- let view = NSView(frame: NSRect(x: 0, y: 5, width: 250, height: 40))
- let label = Utils.makeLabel(text: title, frame: NSRect(x: 20, y: 19, width: 130, height: 20))
- let handler = SliderHandler(display: display, command: command)
- let slider = NSSlider(frame: NSRect(x: 20, y: 0, width: 200, height: 19))
- slider.target = handler
- slider.minValue = 0
- slider.maxValue = 100
- slider.action = #selector(SliderHandler.valueChanged)
- handler.slider = slider
-
- view.addSubview(label)
- view.addSubview(slider)
-
- item.view = view
-
- menu.insertItem(item, at: 0)
- menu.insertItem(NSMenuItem.separator(), at: 1)
-
- DispatchQueue.global(qos: .background).async {
- var val: Int?
-
- if let res = getCommand(command, fromMonitor: display.identifier) {
- val = res
+ // MARK: - Menu
+
+ /// Create a label
+ ///
+ /// - Parameters:
+ /// - text: The text of the label
+ /// - frame: The frame of the label
+ /// - Returns: An `NSTextField` label
+ static func makeLabel(text: String, frame: NSRect) -> NSTextField {
+ let label = NSTextField(frame: frame)
+ label.stringValue = text
+ label.isBordered = false
+ label.isBezeled = false
+ label.isEditable = false
+ label.drawsBackground = false
+ return label
+ }
+
+ /// Create a slider and add it to the menu
+ ///
+ /// - Parameters:
+ /// - menu: Menu containing the slider
+ /// - display: Display to control
+ /// - command: Command (Brightness/Volume/...)
+ /// - title: Title of the slider
+ /// - Returns: An `NSSlider` slider
+ static func addSliderMenuItem(toMenu menu: NSMenu, forDisplay display: Display, command: Int32, title: String) -> SliderHandler {
+ let item = NSMenuItem()
+ let view = NSView(frame: NSRect(x: 0, y: 5, width: 250, height: 40))
+ let label = Utils.makeLabel(text: title, frame: NSRect(x: 20, y: 19, width: 130, height: 20))
+ let handler = SliderHandler(display: display, command: command)
+ let slider = NSSlider(frame: NSRect(x: 20, y: 0, width: 200, height: 19))
+ slider.target = handler
+ slider.minValue = 0
+ slider.maxValue = 100
+ slider.action = #selector(SliderHandler.valueChanged)
+ handler.slider = slider
+
+ view.addSubview(label)
+ view.addSubview(slider)
+
+ item.view = view
+
+ menu.insertItem(item, at: 0)
+ menu.insertItem(NSMenuItem.separator(), at: 1)
+
+ var val: Int?
+
+ if let res = getCommand(command, fromMonitor: display.identifier) {
+ val = res
+ }
+
+ if let val = val {
+ display.saveValue(val, for: command)
+ slider.integerValue = val
+ } else {
+ // if unable to read value from display, use last known value
+ slider.integerValue = prefs.integer(forKey: "\(command)-\(display.identifier)")
+ }
+ return handler
+ }
+
+ // MARK: - Utilities
+
+ /// Acquire Privileges (Necessary to listen to keyboard event globally)
+ static func acquirePrivileges() {
+ let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: true]
+ let accessibilityEnabled = AXIsProcessTrustedWithOptions(options)
+
+ if !accessibilityEnabled {
+ let alert = NSAlert()
+ alert.addButton(withTitle: NSLocalizedString("Ok", comment: "Shown in the alert dialog"))
+ alert.messageText = NSLocalizedString("Shortcuts not available", comment: "Shown in the alert dialog")
+ alert.informativeText = NSLocalizedString("You need to enable MonitorControl in System Preferences > Security and Privacy > Accessibility for the keyboard shortcuts to work", comment: "Shown in the alert dialog")
+ alert.alertStyle = .warning
+ alert.runModal()
+ }
+
+ return
+ }
+
+ // MARK: - Display Infos
+
+ /// Get the descriptor text
+ ///
+ /// - Parameter descriptor: the descriptor
+ /// - Returns: a string
+ static func getEdidString(_ descriptor: descriptor) -> String {
+ var result = ""
+ for (_, bitChar) in Mirror(reflecting: descriptor.text.data).children {
+ if let bitChar = bitChar as? Int8 {
+ let char = Character(UnicodeScalar(UInt8(bitPattern: bitChar)))
+ if char == "\0" || char == "\n" {
+ break
+ }
+ result.append(char)
+ }
+ }
+ return result
+ }
+
+ /// Get the descriptors of a display from the Edid
+ ///
+ /// - Parameters:
+ /// - edid: the EDID of a display
+ /// - type: the type of descriptor
+ /// - Returns: a string if type of descriptor is found
+ static func getDescriptorString(_ edid: EDID, _ type: UInt8) -> String? {
+ for (_, descriptor) in Mirror(reflecting: edid.descriptors).children {
+ if let descriptor = descriptor as? descriptor {
+ if descriptor.text.type == UInt8(type) {
+ return getEdidString(descriptor)
+ }
}
+ }
+ return nil
+ }
+
+ /// Get the name of a display
+ ///
+ /// - Parameter edid: the EDID of a display
+ /// - Returns: a string
+ static func getDisplayName(forEdid edid: EDID) -> String {
+ return getDescriptorString(edid, 0xFC) ?? NSLocalizedString("Display", comment: "")
+ }
- if let val = val {
- display.saveValue(val, for: command)
-
- DispatchQueue.main.async {
- slider.integerValue = val
- }
- }
- }
-
- return handler
- }
-
- // MARK: - Utilities
-
- /// Acquire Privileges (Necessary to listen to keyboard event globally)
- static func acquirePrivileges() {
- let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: true]
- let accessibilityEnabled = AXIsProcessTrustedWithOptions(options)
-
- if !accessibilityEnabled {
- let alert = NSAlert()
- alert.addButton(withTitle: NSLocalizedString("Ok", comment: "Shown in the alert dialog"))
- alert.messageText = NSLocalizedString("Shortcuts not available", comment: "Shown in the alert dialog")
- alert.informativeText = NSLocalizedString("You need to enable MonitorControl in System Preferences > Security and Privacy > Accessibility for the keyboard shortcuts to work", comment: "Shown in the alert dialog")
- alert.alertStyle = .warning
- alert.runModal()
- }
-
- return
- }
-
- // MARK: - Display Infos
-
- /// Get the descriptor text
- ///
- /// - Parameter descriptor: the descriptor
- /// - Returns: a string
- static func getEdidString(_ descriptor: descriptor) -> String {
- var result = ""
- for (_, bitChar) in Mirror(reflecting: descriptor.text.data).children {
- if let bitChar = bitChar as? Int8 {
- let char = Character(UnicodeScalar(UInt8(bitPattern: bitChar)))
- if char == "\0" || char == "\n" {
- break
- }
- result.append(char)
- }
- }
- return result
- }
-
- /// Get the descriptors of a display from the Edid
- ///
- /// - Parameters:
- /// - edid: the EDID of a display
- /// - type: the type of descriptor
- /// - Returns: a string if type of descriptor is found
- static func getDescriptorString(_ edid: EDID, _ type: UInt8) -> String? {
- for (_, descriptor) in Mirror(reflecting: edid.descriptors).children {
- if let descriptor = descriptor as? descriptor {
- if descriptor.text.type == UInt8(type) {
- return getEdidString(descriptor)
- }
- }
- }
-
- return nil
- }
-
- /// Get the name of a display
- ///
- /// - Parameter edid: the EDID of a display
- /// - Returns: a string
- static func getDisplayName(forEdid edid: EDID) -> String {
- return getDescriptorString(edid, 0xFC) ?? NSLocalizedString("Display", comment: "")
- }
-
- /// Get the serial of a display
- ///
- /// - Parameter edid: the EDID of a display
- /// - Returns: a string
- static func getDisplaySerial(forEdid edid: EDID) -> String {
- 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
- }
- }
-
- // MARK: - Enums
-
- /// UserDefault Keys for the app prefs
- enum PrefKeys: String {
- /// Was the app launched once
- case appAlreadyLaunched
-
- /// Does the app start at Login
- case startAtLogin
-
- /// Does the app start when plugged to an external monitor
- case startWhenExternal
-
- /// Keys listened for (Brightness/Volume)
- case listenFor
-
- /// Show contrast sliders
- case showContrast
-
- /// Lower contrast after brightness
- case lowerContrast
-
- /// Change Brightness/Volume for all screens
- case allScreens
+ /// Get the serial of a display
+ ///
+ /// - Parameter edid: the EDID of a display
+ /// - Returns: a string
+ static func getDisplaySerial(forEdid edid: EDID) -> String {
+ 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
+ }
+ }
+
+ // MARK: - Enums
+
+ /// UserDefault Keys for the app prefs
+ enum PrefKeys: String {
+ /// Was the app launched once
+ case appAlreadyLaunched
+
+ /// Does the app start at Login
+ case startAtLogin
+
+ /// Does the app start when plugged to an external monitor
+ case startWhenExternal
+
+ /// Keys listened for (Brightness/Volume)
+ case listenFor
+
+ /// Show contrast sliders
+ case showContrast
+
+ /// Lower contrast after brightness
+ case lowerContrast
+
+ /// Change Brightness/Volume for all screens
+ case allScreens
/// Automatically turn on/off autohiding of the Dock if external monitor is connected.
/// external monitor -> Dock autohide disabled
/// internal monitor -> Dock autohide enabled
case intelliDock
- }
+ }
- /// Keys for the value of listenFor option
- enum ListenForKeys: Int {
- /// Listen for Brightness and Volume keys
- case brightnessAndVolumeKeys = 0
+ /// Keys for the value of listenFor option
+ enum ListenForKeys: Int {
+ /// Listen for Brightness and Volume keys
+ case brightnessAndVolumeKeys = 0
- /// Listen for Brightness keys only
- case brightnessOnlyKeys = 1
+ /// Listen for Brightness keys only
+ case brightnessOnlyKeys = 1
- /// Listen for Volume keys only
- case volumeOnlyKeys = 2
- }
+ /// Listen for Volume keys only
+ case volumeOnlyKeys = 2
+ }
}
diff --git a/Podfile.lock b/Podfile.lock
index 1daf432e..cdd0b485 100644
--- a/Podfile.lock
+++ b/Podfile.lock
@@ -20,10 +20,10 @@ EXTERNAL SOURCES:
CHECKOUT OPTIONS:
MASPreferences:
- :commit: 52b15d34b7509436c73d6e89d2b02bf29507df50
+ :commit: aa9cc4ebf8599382a239b96b000112a36c2554d3
:git: https://github.com/JoniVR/MASPreferences.git
MediaKeyTap:
- :commit: a7afe10951d2800d94c04091c2684ec9e978fb3e
+ :commit: ca246d59e8bedeca24440fad67e6a5750ff71ef5
:git: https://github.com/JoniVR/MediaKeyTap.git
SPEC CHECKSUMS:
@@ -33,4 +33,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 947d8968124719d712379b2dbc0a24b1595515fe
-COCOAPODS: 1.5.3
+COCOAPODS: 1.6.0