mirror of
https://github.com/MonitorControl/MonitorControl.git
synced 2026-05-15 06:05:52 -06:00
🔧 Refactoring + preparing v1.2
- Refactoring of the way the slider are created - Read the current value of ddcctl monitor after launching the app, so no more value at 0 for the sliders - When there's only one monitor, display it directly, not in a submenu, closes #10 - Added a "start at login" helper (still need testing) for v1.2 Signed-off-by: Guillaume Broder <iamnotheoneyouseek@gmail.com>
This commit is contained in:
parent
1112380361
commit
087bb132c6
14 changed files with 340 additions and 213 deletions
120
.github/rules.json
vendored
120
.github/rules.json
vendored
|
|
@ -1,120 +0,0 @@
|
|||
{
|
||||
"title": "MonitorControl (@the0neyouseek)",
|
||||
"rules": [
|
||||
{
|
||||
"description": "External Screen brightness [-] (using MonitorControl)",
|
||||
"manipulators": [{
|
||||
"type": "basic",
|
||||
"from": {
|
||||
"key_code": "f1",
|
||||
"modifiers": {
|
||||
"optional": [
|
||||
"any"
|
||||
]
|
||||
}
|
||||
},
|
||||
"to": [{
|
||||
"key_code": "down_arrow",
|
||||
"modifiers": [
|
||||
"left_shift",
|
||||
"left_control",
|
||||
"left_option",
|
||||
"left_command"
|
||||
]
|
||||
}]
|
||||
}]
|
||||
},
|
||||
{
|
||||
"description": "External Screen brightness [+] (using MonitorControl)",
|
||||
"manipulators": [{
|
||||
"type": "basic",
|
||||
"from": {
|
||||
"key_code": "f2",
|
||||
"modifiers": {
|
||||
"optional": [
|
||||
"any"
|
||||
]
|
||||
}
|
||||
},
|
||||
"to": [{
|
||||
"key_code": "up_arrow",
|
||||
"modifiers": [
|
||||
"left_shift",
|
||||
"left_control",
|
||||
"left_option",
|
||||
"left_command"
|
||||
]
|
||||
}]
|
||||
}]
|
||||
},
|
||||
{
|
||||
"description": "External Screen volume [-] (using MonitorControl)",
|
||||
"manipulators": [{
|
||||
"type": "basic",
|
||||
"from": {
|
||||
"key_code": "f11",
|
||||
"modifiers": {
|
||||
"optional": [
|
||||
"any"
|
||||
]
|
||||
}
|
||||
},
|
||||
"to": [{
|
||||
"key_code": "left_arrow",
|
||||
"modifiers": [
|
||||
"left_shift",
|
||||
"left_control",
|
||||
"left_option",
|
||||
"left_command"
|
||||
]
|
||||
}]
|
||||
}]
|
||||
},
|
||||
{
|
||||
"description": "External Screen volume [+] (using MonitorControl)",
|
||||
"manipulators": [{
|
||||
"type": "basic",
|
||||
"from": {
|
||||
"key_code": "f12",
|
||||
"modifiers": {
|
||||
"optional": [
|
||||
"any"
|
||||
]
|
||||
}
|
||||
},
|
||||
"to": [{
|
||||
"key_code": "right_arrow",
|
||||
"modifiers": [
|
||||
"left_shift",
|
||||
"left_control",
|
||||
"left_option",
|
||||
"left_command"
|
||||
]
|
||||
}]
|
||||
}]
|
||||
},
|
||||
{
|
||||
"description": "External Screen volume mute (using MonitorControl)",
|
||||
"manipulators": [{
|
||||
"type": "basic",
|
||||
"from": {
|
||||
"key_code": "f10",
|
||||
"modifiers": {
|
||||
"optional": [
|
||||
"any"
|
||||
]
|
||||
}
|
||||
},
|
||||
"to": [{
|
||||
"key_code": "equal_sign",
|
||||
"modifiers": [
|
||||
"left_shift",
|
||||
"left_control",
|
||||
"left_option",
|
||||
"left_command"
|
||||
]
|
||||
}]
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -19,12 +19,28 @@
|
|||
F0445D40200259C10025AE82 /* DisplayPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0445D3F200259C10025AE82 /* DisplayPrefsViewController.swift */; };
|
||||
F0445D41200282E60025AE82 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F0445D43200282E60025AE82 /* Main.storyboard */; };
|
||||
F0445D4D200294AB0025AE82 /* ButtonCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0445D4C200294AB0025AE82 /* ButtonCellView.swift */; };
|
||||
F06792EA200A73460066C438 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F06792E9200A73460066C438 /* AppDelegate.swift */; };
|
||||
F06792F6200A745F0066C438 /* MonitorControlHelper.app in [Login] Copy Helper to start at Login */ = {isa = PBXBuildFile; fileRef = F06792E7200A73460066C438 /* MonitorControlHelper.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
F091C9B31F6EA6110096FD65 /* SliderHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F091C9B21F6EA6110096FD65 /* SliderHandler.swift */; };
|
||||
F091C9B81F6EA79B0096FD65 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = F091C9B71F6EA79B0096FD65 /* Utils.swift */; };
|
||||
F0A987E81F77B40E009B603D /* OSD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F0A987D61F77B290009B603D /* OSD.framework */; };
|
||||
F0EB972F1F6ED7C800686D2A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F091C9C11F6EB8660096FD65 /* Localizable.strings */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
F06792F5200A73FA0066C438 /* [Login] Copy Helper to start at Login */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = Contents/Library/LoginItems;
|
||||
dstSubfolderSpec = 1;
|
||||
files = (
|
||||
F06792F6200A745F0066C438 /* MonitorControlHelper.app in [Login] Copy Helper to start at Login */,
|
||||
);
|
||||
name = "[Login] Copy Helper to start at Login";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
31E16D90527EBD3F8A12BE0B /* Pods-MonitorControl.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MonitorControl.release.xcconfig"; path = "Pods/Target Support Files/Pods-MonitorControl/Pods-MonitorControl.release.xcconfig"; sourceTree = "<group>"; };
|
||||
398F482D5C8816B29F16AAEB /* Pods_MonitorControl.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MonitorControl.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
|
@ -50,6 +66,10 @@
|
|||
F0445D49200285690025AE82 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/MainMenu.strings; sourceTree = "<group>"; };
|
||||
F0445D4B2002856C0025AE82 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/MainMenu.strings; sourceTree = "<group>"; };
|
||||
F0445D4C200294AB0025AE82 /* ButtonCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonCellView.swift; sourceTree = "<group>"; };
|
||||
F06792E7200A73460066C438 /* MonitorControlHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MonitorControlHelper.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F06792E9200A73460066C438 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
F091C9B21F6EA6110096FD65 /* SliderHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SliderHandler.swift; sourceTree = "<group>"; };
|
||||
F091C9B71F6EA79B0096FD65 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = "<group>"; };
|
||||
F091C9C21F6EB8660096FD65 /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; lineEnding = 0; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
|
|
@ -79,6 +99,13 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
F06792E4200A73460066C438 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
|
|
@ -101,6 +128,7 @@
|
|||
56754EAD1D9A4016007BCDC5 /* MonitorControl */,
|
||||
F0A987D61F77B290009B603D /* OSD.framework */,
|
||||
55359E321E2737EC002671BC /* ddcctl */,
|
||||
F06792E8200A73460066C438 /* MonitorControlHelper */,
|
||||
56754EAC1D9A4016007BCDC5 /* Products */,
|
||||
F0A987D71F77B404009B603D /* Frameworks */,
|
||||
EFFC2F3E35BEC9ACFA754137 /* Pods */,
|
||||
|
|
@ -111,6 +139,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
56754EAB1D9A4016007BCDC5 /* MonitorControl.app */,
|
||||
F06792E7200A73460066C438 /* MonitorControlHelper.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -151,6 +180,16 @@
|
|||
path = Prefs;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F06792E8200A73460066C438 /* MonitorControlHelper */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F06792E9200A73460066C438 /* AppDelegate.swift */,
|
||||
F06792F0200A73470066C438 /* Info.plist */,
|
||||
F06792F1200A73470066C438 /* MonitorControlHelper.entitlements */,
|
||||
);
|
||||
path = MonitorControlHelper;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F091C9B41F6EA6180096FD65 /* Objects */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -208,6 +247,7 @@
|
|||
56754EA91D9A4016007BCDC5 /* Resources */,
|
||||
9DD5968596EFAF0E2EB56496 /* [CP] Embed Pods Frameworks */,
|
||||
3ACE91333FC1E781FB2E44E5 /* [CP] Copy Pods Resources */,
|
||||
F06792F5200A73FA0066C438 /* [Login] Copy Helper to start at Login */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
|
@ -218,13 +258,30 @@
|
|||
productReference = 56754EAB1D9A4016007BCDC5 /* MonitorControl.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
F06792E6200A73460066C438 /* MonitorControlHelper */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = F06792F4200A73470066C438 /* Build configuration list for PBXNativeTarget "MonitorControlHelper" */;
|
||||
buildPhases = (
|
||||
F06792E3200A73460066C438 /* Sources */,
|
||||
F06792E4200A73460066C438 /* Frameworks */,
|
||||
F06792E5200A73460066C438 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = MonitorControlHelper;
|
||||
productName = MonitorControlHelper;
|
||||
productReference = F06792E7200A73460066C438 /* MonitorControlHelper.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
56754EA31D9A4016007BCDC5 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0800;
|
||||
LastSwiftUpdateCheck = 0920;
|
||||
LastUpgradeCheck = 0900;
|
||||
ORGANIZATIONNAME = "Mathew Kurian";
|
||||
TargetAttributes = {
|
||||
|
|
@ -234,6 +291,11 @@
|
|||
LastSwiftMigration = 0900;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
F06792E6200A73460066C438 = {
|
||||
CreatedOnToolsVersion = 9.2;
|
||||
DevelopmentTeam = KGY56RWR9A;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 56754EA61D9A4016007BCDC5 /* Build configuration list for PBXProject "MonitorControl" */;
|
||||
|
|
@ -251,6 +313,7 @@
|
|||
projectRoot = "";
|
||||
targets = (
|
||||
56754EAA1D9A4016007BCDC5 /* MonitorControl */,
|
||||
F06792E6200A73460066C438 /* MonitorControlHelper */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
|
@ -268,6 +331,13 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
F06792E5200A73460066C438 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
|
|
@ -293,11 +363,13 @@
|
|||
);
|
||||
inputPaths = (
|
||||
"${SRCROOT}/Pods/Target Support Files/Pods-MonitorControl/Pods-MonitorControl-frameworks.sh",
|
||||
"${BUILT_PRODUCTS_DIR}/HotKey/HotKey.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/MASPreferences/MASPreferences.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/MediaKeyTap/MediaKeyTap.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HotKey.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MASPreferences.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MediaKeyTap.framework",
|
||||
);
|
||||
|
|
@ -357,6 +429,14 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
F06792E3200A73460066C438 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F06792EA200A73460066C438 /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
|
|
@ -564,6 +644,52 @@
|
|||
};
|
||||
name = Release;
|
||||
};
|
||||
F06792F2200A73470066C438 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = MonitorControlHelper/MonitorControlHelper.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = KGY56RWR9A;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = MonitorControlHelper/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControlHelper;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
F06792F3200A73470066C438 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CODE_SIGN_ENTITLEMENTS = MonitorControlHelper/MonitorControlHelper.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = KGY56RWR9A;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
INFOPLIST_FILE = MonitorControlHelper/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControlHelper;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 4.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
|
|
@ -585,6 +711,15 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
F06792F4200A73470066C438 /* Build configuration list for PBXNativeTarget "MonitorControlHelper" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
F06792F2200A73470066C438 /* Debug */,
|
||||
F06792F3200A73470066C438 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 56754EA31D9A4016007BCDC5 /* Project object */;
|
||||
|
|
|
|||
|
|
@ -35,13 +35,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, MediaKeyTapDelegate {
|
|||
app = self
|
||||
mediaKeyTap = MediaKeyTap.init(delegate: self, forKeys: [.brightnessUp, .brightnessDown, .mute, .volumeUp, .volumeDown], observeBuiltIn: false)
|
||||
let storyboard: NSStoryboard = NSStoryboard.init(name: NSStoryboard.Name(rawValue: "Main"), bundle: Bundle.main)
|
||||
prefsController = MASPreferencesWindowController(viewControllers:
|
||||
[
|
||||
storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "MainPrefsVC")),
|
||||
storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "KeysPrefsVC")),
|
||||
storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "DisplayPrefsVC"))
|
||||
],
|
||||
title: NSLocalizedString("Preferences", comment: "Shown in Preferences window"))
|
||||
let views = [
|
||||
storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "MainPrefsVC")),
|
||||
storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "KeysPrefsVC")),
|
||||
storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "DisplayPrefsVC"))
|
||||
]
|
||||
prefsController = MASPreferencesWindowController(viewControllers: views, title: NSLocalizedString("Preferences", comment: "Shown in Preferences window"))
|
||||
|
||||
statusItem.image = NSImage.init(named: NSImage.Name(rawValue: "status"))
|
||||
statusItem.menu = statusMenu
|
||||
|
|
@ -96,47 +95,33 @@ class AppDelegate: NSObject, NSApplicationDelegate, MediaKeyTapDelegate {
|
|||
clearDisplays()
|
||||
sleep(1)
|
||||
|
||||
for screen in NSScreen.screens {
|
||||
var filteredScreens = NSScreen.screens.filter { screen -> Bool in
|
||||
if let id = screen.deviceDescription[NSDeviceDescriptionKey.init("NSScreenNumber")] as? CGDirectDisplayID {
|
||||
// Is Built In Screen (e.g. MBP/iMac Screen)
|
||||
if CGDisplayIsBuiltin(id) != 0 {
|
||||
continue
|
||||
return false
|
||||
}
|
||||
|
||||
// Does screen support EDID ?
|
||||
var edid = EDID()
|
||||
if !EDIDTest(id, &edid) {
|
||||
continue
|
||||
return false
|
||||
}
|
||||
|
||||
let name = Utils.getDisplayName(forEdid: edid)
|
||||
let serial = Utils.getDisplaySerial(forEdid: edid)
|
||||
|
||||
let display = Display.init(id, name: name, serial: serial)
|
||||
|
||||
let monitorSubMenu = NSMenu()
|
||||
let brightnessSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu,
|
||||
forDisplay: display,
|
||||
command: BRIGHTNESS,
|
||||
title: NSLocalizedString("Brightness", comment: "Shown in menu"))
|
||||
let volumeSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu,
|
||||
forDisplay: display,
|
||||
command: AUDIO_SPEAKER_VOLUME,
|
||||
title: NSLocalizedString("Volume", comment: "Shown in menu"))
|
||||
display.brightnessSliderHandler = brightnessSliderHandler
|
||||
display.volumeSliderHandler = volumeSliderHandler
|
||||
displays.append(display)
|
||||
|
||||
let monitorMenuItem = NSMenuItem()
|
||||
monitorMenuItem.title = "\(name)"
|
||||
monitorMenuItem.submenu = monitorSubMenu
|
||||
|
||||
monitorItems.append(monitorMenuItem)
|
||||
statusMenu.insertItem(monitorMenuItem, at: displays.count - 1)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if displays.count == 0 {
|
||||
if filteredScreens.count == 1 {
|
||||
self.addScreenToMenu(screen: filteredScreens[0], asSubMenu: false)
|
||||
} else {
|
||||
for screen in filteredScreens {
|
||||
self.addScreenToMenu(screen: screen, asSubMenu: true)
|
||||
}
|
||||
}
|
||||
|
||||
if filteredScreens.count == 0 {
|
||||
// If no DDC capable display was detected
|
||||
let item = NSMenuItem()
|
||||
item.title = NSLocalizedString("No supported display found", comment: "Shown in menu")
|
||||
|
|
@ -146,6 +131,46 @@ class AppDelegate: NSObject, NSApplicationDelegate, MediaKeyTapDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
/// Add a screen to the menu
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - screen: The screen to add
|
||||
/// - asSubMenu: Display in a sub menu or directly in menu
|
||||
private func addScreenToMenu(screen: NSScreen, asSubMenu: Bool) {
|
||||
if let id = screen.deviceDescription[NSDeviceDescriptionKey.init("NSScreenNumber")] as? CGDirectDisplayID {
|
||||
|
||||
var edid = EDID()
|
||||
if EDIDTest(id, &edid) {
|
||||
let name = Utils.getDisplayName(forEdid: edid)
|
||||
let serial = Utils.getDisplaySerial(forEdid: edid)
|
||||
|
||||
let display = Display.init(id, name: name, serial: serial)
|
||||
|
||||
let monitorSubMenu: NSMenu = asSubMenu ? NSMenu() : statusMenu
|
||||
let volumeSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu,
|
||||
forDisplay: display,
|
||||
command: AUDIO_SPEAKER_VOLUME,
|
||||
title: NSLocalizedString("Volume", comment: "Shown in menu"))
|
||||
let brightnessSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu,
|
||||
forDisplay: display,
|
||||
command: BRIGHTNESS,
|
||||
title: NSLocalizedString("Brightness", comment: "Shown in menu"))
|
||||
display.volumeSliderHandler = volumeSliderHandler
|
||||
display.brightnessSliderHandler = brightnessSliderHandler
|
||||
displays.append(display)
|
||||
|
||||
let monitorMenuItem = NSMenuItem()
|
||||
monitorMenuItem.title = "\(name)"
|
||||
if asSubMenu {
|
||||
monitorMenuItem.submenu = monitorSubMenu
|
||||
}
|
||||
|
||||
monitorItems.append(monitorMenuItem)
|
||||
statusMenu.insertItem(monitorMenuItem, at: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Media Key Tap delegate
|
||||
|
||||
func handle(mediaKey: MediaKey, event: KeyEvent) {
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@
|
|||
<objects>
|
||||
<viewController storyboardIdentifier="MainPrefsVC" id="HNb-aq-vnV" customClass="MainPrefsViewController" customModule="MonitorControl" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" id="iuQ-z6-BGz">
|
||||
<rect key="frame" x="0.0" y="0.0" width="400" height="117"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="400" height="158"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8KQ-j9-ddv">
|
||||
<rect key="frame" x="18" y="68" width="364" height="29"/>
|
||||
<rect key="frame" x="18" y="109" width="92" height="29"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="General" id="ocE-Cc-2bi">
|
||||
<font key="font" metaFont="systemBold" size="24"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="dZG-M6-fsQ">
|
||||
<rect key="frame" x="18" y="42" width="364" height="18"/>
|
||||
<rect key="frame" x="18" y="83" width="199" height="18"/>
|
||||
<buttonCell key="cell" type="check" title="Start MonitorControl at Login" bezelStyle="regularSquare" imagePosition="left" inset="2" id="UTh-SV-vAQ">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
|
|
@ -32,67 +32,55 @@
|
|||
<action selector="startAtLoginClicked:" target="HNb-aq-vnV" id="OrA-9Y-N8S"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button hidden="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nnZ-LS-lOW">
|
||||
<rect key="frame" x="18" y="-16" width="364" height="18"/>
|
||||
<buttonCell key="cell" type="check" title="Check for updates automatically" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="SCJ-AY-phi">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<button hidden="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="K3V-Ub-wAA">
|
||||
<rect key="frame" x="14" y="-52" width="152" height="32"/>
|
||||
<rect key="frame" x="14" y="13" width="152" height="32"/>
|
||||
<buttonCell key="cell" type="push" title="Check for updates" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Vi8-Ye-W28">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<textField hidden="YES" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="fds-MD-5OJ">
|
||||
<rect key="frame" x="168" y="-43" width="78" height="17"/>
|
||||
<rect key="frame" x="168" y="22" width="78" height="17"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Last check: " id="I3I-EP-Ev8">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="71u-hm-uYt">
|
||||
<rect key="frame" x="18" y="18" width="364" height="18"/>
|
||||
<buttonCell key="cell" type="check" title="Start when plugged to an external monitor" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="WJp-aA-2Af">
|
||||
<button hidden="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nnZ-LS-lOW">
|
||||
<rect key="frame" x="18" y="49" width="218" height="18"/>
|
||||
<buttonCell key="cell" type="check" title="Check for updates automatically" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="SCJ-AY-phi">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="startWhenExternalClicked:" target="HNb-aq-vnV" id="BT0-Ff-bx9"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="fds-MD-5OJ" firstAttribute="centerY" secondItem="K3V-Ub-wAA" secondAttribute="centerY" id="2RB-zz-fOU"/>
|
||||
<constraint firstItem="nnZ-LS-lOW" firstAttribute="top" secondItem="71u-hm-uYt" secondAttribute="bottom" constant="20" id="5IO-Jv-9ZU"/>
|
||||
<constraint firstItem="dZG-M6-fsQ" firstAttribute="leading" secondItem="iuQ-z6-BGz" secondAttribute="leading" constant="20" id="8QT-EO-uBJ"/>
|
||||
<constraint firstItem="K3V-Ub-wAA" firstAttribute="top" secondItem="nnZ-LS-lOW" secondAttribute="bottom" constant="10" id="9DT-6C-dQo"/>
|
||||
<constraint firstItem="8KQ-j9-ddv" firstAttribute="top" secondItem="iuQ-z6-BGz" secondAttribute="top" constant="20" id="Fwh-JQ-1Cx"/>
|
||||
<constraint firstItem="K3V-Ub-wAA" firstAttribute="leading" secondItem="iuQ-z6-BGz" secondAttribute="leading" constant="20" id="RWW-67-dGr"/>
|
||||
<constraint firstItem="71u-hm-uYt" firstAttribute="top" secondItem="dZG-M6-fsQ" secondAttribute="bottom" constant="10" id="Xmr-XF-7lE"/>
|
||||
<constraint firstAttribute="trailing" secondItem="dZG-M6-fsQ" secondAttribute="trailing" constant="20" id="c5h-vI-6Dg"/>
|
||||
<constraint firstItem="nnZ-LS-lOW" firstAttribute="top" secondItem="dZG-M6-fsQ" secondAttribute="bottom" constant="20" id="V4k-4m-OkH"/>
|
||||
<constraint firstAttribute="bottom" secondItem="K3V-Ub-wAA" secondAttribute="bottom" constant="20" id="bFh-Xa-GoP"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="dZG-M6-fsQ" secondAttribute="trailing" constant="20" id="c5h-vI-6Dg"/>
|
||||
<constraint firstItem="dZG-M6-fsQ" firstAttribute="top" secondItem="8KQ-j9-ddv" secondAttribute="bottom" constant="10" id="dPJ-ev-Y3O"/>
|
||||
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="dZG-M6-fsQ" secondAttribute="bottom" constant="20" id="gVa-4Q-fPP"/>
|
||||
<constraint firstItem="8KQ-j9-ddv" firstAttribute="leading" secondItem="iuQ-z6-BGz" secondAttribute="leading" constant="20" id="ii0-uV-Ylg"/>
|
||||
<constraint firstItem="71u-hm-uYt" firstAttribute="leading" secondItem="iuQ-z6-BGz" secondAttribute="leading" constant="20" id="jsn-2a-Hse"/>
|
||||
<constraint firstAttribute="trailing" secondItem="nnZ-LS-lOW" secondAttribute="trailing" constant="20" id="kgN-1K-yxh"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="nnZ-LS-lOW" secondAttribute="trailing" constant="20" id="kgN-1K-yxh"/>
|
||||
<constraint firstItem="nnZ-LS-lOW" firstAttribute="leading" secondItem="iuQ-z6-BGz" secondAttribute="leading" constant="20" id="kqS-g2-YV5"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="fds-MD-5OJ" secondAttribute="trailing" constant="20" id="mfJ-HC-8ie"/>
|
||||
<constraint firstAttribute="trailing" secondItem="8KQ-j9-ddv" secondAttribute="trailing" constant="20" id="qVn-hz-dRV"/>
|
||||
<constraint firstAttribute="trailing" secondItem="71u-hm-uYt" secondAttribute="trailing" constant="20" id="sIC-PJ-9gQ"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="8KQ-j9-ddv" secondAttribute="trailing" constant="20" id="qVn-hz-dRV"/>
|
||||
<constraint firstItem="fds-MD-5OJ" firstAttribute="leading" secondItem="K3V-Ub-wAA" secondAttribute="trailing" constant="10" id="xuV-jB-am4"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="startAtLogin" destination="dZG-M6-fsQ" id="Rwg-dp-vIj"/>
|
||||
<outlet property="startWhenExternal" destination="71u-hm-uYt" id="l02-Xi-74S"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="ALN-AB-CU5" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="116" y="172.5"/>
|
||||
<point key="canvasLocation" x="116" y="285"/>
|
||||
</scene>
|
||||
<!--Keys Prefs View Controller-->
|
||||
<scene sceneID="DmR-ia-4qL">
|
||||
|
|
@ -162,7 +150,7 @@
|
|||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Uti-Vm-YwB">
|
||||
<rect key="frame" x="18" y="80" width="364" height="29"/>
|
||||
<rect key="frame" x="18" y="80" width="59" height="29"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Keys" id="Dcz-GG-1li">
|
||||
<font key="font" metaFont="systemBold" size="24"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
|
|
@ -179,8 +167,9 @@
|
|||
<constraint firstItem="Uti-Vm-YwB" firstAttribute="leading" secondItem="nfK-n0-xN4" secondAttribute="leading" constant="20" id="Mfl-NR-mVk"/>
|
||||
<constraint firstItem="Uti-Vm-YwB" firstAttribute="top" secondItem="nfK-n0-xN4" secondAttribute="top" constant="20" id="ReX-zz-skV"/>
|
||||
<constraint firstItem="fUf-UM-yW3" firstAttribute="leading" secondItem="jFY-ug-0KQ" secondAttribute="trailing" constant="10" id="Tic-nC-Oax"/>
|
||||
<constraint firstAttribute="bottom" secondItem="AeW-b4-XNc" secondAttribute="bottom" constant="20" id="ULA-RM-25S"/>
|
||||
<constraint firstItem="AeW-b4-XNc" firstAttribute="top" secondItem="fUf-UM-yW3" secondAttribute="bottom" constant="10" id="Zd8-nU-IPw"/>
|
||||
<constraint firstAttribute="trailing" secondItem="Uti-Vm-YwB" secondAttribute="trailing" constant="20" id="ctI-eo-jEw"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Uti-Vm-YwB" secondAttribute="trailing" constant="20" id="ctI-eo-jEw"/>
|
||||
<constraint firstItem="AeW-b4-XNc" firstAttribute="leading" secondItem="VNO-n0-6Y1" secondAttribute="trailing" constant="10" id="dkl-ho-D2N"/>
|
||||
<constraint firstItem="jFY-ug-0KQ" firstAttribute="top" secondItem="Uti-Vm-YwB" secondAttribute="bottom" constant="10" id="t7Y-Pv-HlI"/>
|
||||
<constraint firstItem="jFY-ug-0KQ" firstAttribute="leading" secondItem="nfK-n0-xN4" secondAttribute="leading" constant="20" id="xCB-fT-tMo"/>
|
||||
|
|
@ -193,7 +182,7 @@
|
|||
</viewController>
|
||||
<customObject id="hVj-0D-6XC" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="618" y="178.5"/>
|
||||
<point key="canvasLocation" x="624" y="179"/>
|
||||
</scene>
|
||||
<!--Display Prefs View Controller-->
|
||||
<scene sceneID="kdt-oj-Qke">
|
||||
|
|
@ -204,7 +193,7 @@
|
|||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="uXD-ZY-N3H">
|
||||
<rect key="frame" x="18" y="191" width="364" height="29"/>
|
||||
<rect key="frame" x="18" y="191" width="88" height="29"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Display" id="ExD-7P-6XI">
|
||||
<font key="font" metaFont="systemBold" size="24"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
|
|
@ -214,7 +203,7 @@
|
|||
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="B5k-we-kuP">
|
||||
<rect key="frame" x="20" y="20" width="360" height="137"/>
|
||||
<clipView key="contentView" id="4ot-Jo-X5O">
|
||||
<rect key="frame" x="1" y="23" width="358" height="113"/>
|
||||
<rect key="frame" x="1" y="0.0" width="358" height="136"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnResizing="NO" multipleSelection="NO" emptySelection="NO" autosaveColumns="NO" typeSelect="NO" rowSizeStyle="automatic" headerView="ckY-Px-mJn" viewBased="YES" id="dyo-uY-pMe">
|
||||
|
|
@ -343,7 +332,7 @@
|
|||
</tableHeaderView>
|
||||
</scrollView>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Y48-gQ-uJi">
|
||||
<rect key="frame" x="18" y="165" width="364" height="18"/>
|
||||
<rect key="frame" x="18" y="165" width="275" height="18"/>
|
||||
<buttonCell key="cell" type="check" title="Change Brightness/Volume for all screens" bezelStyle="regularSquare" imagePosition="left" inset="2" id="0Z7-PQ-Bl8">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
|
|
@ -354,9 +343,9 @@
|
|||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="Y48-gQ-uJi" secondAttribute="trailing" constant="20" id="24u-jX-VqD"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="Y48-gQ-uJi" secondAttribute="trailing" constant="20" id="24u-jX-VqD"/>
|
||||
<constraint firstItem="Y48-gQ-uJi" firstAttribute="leading" secondItem="EBf-qN-KaN" secondAttribute="leading" constant="20" id="Ct2-ah-W0a"/>
|
||||
<constraint firstAttribute="trailing" secondItem="uXD-ZY-N3H" secondAttribute="trailing" constant="20" id="Qwk-xy-tL4"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="uXD-ZY-N3H" secondAttribute="trailing" constant="20" id="Qwk-xy-tL4"/>
|
||||
<constraint firstAttribute="trailing" secondItem="B5k-we-kuP" secondAttribute="trailing" constant="20" id="SgW-60-zGH"/>
|
||||
<constraint firstItem="Y48-gQ-uJi" firstAttribute="top" secondItem="uXD-ZY-N3H" secondAttribute="bottom" constant="10" id="WSd-oq-oD7"/>
|
||||
<constraint firstItem="B5k-we-kuP" firstAttribute="top" secondItem="Y48-gQ-uJi" secondAttribute="bottom" constant="10" id="YIT-MK-KKw"/>
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.1.1</string>
|
||||
<string>1.2.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>32</string>
|
||||
<string>40</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class ButtonCellView: NSTableCellView {
|
|||
break
|
||||
}
|
||||
// TODO: Toggle enabled display state
|
||||
print("Toggle enabled display state -> \(sender.state)")
|
||||
print("Toggle enabled display state -> \(sender.state == .on ? "on" : "off")")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ class Display {
|
|||
var brightnessSliderHandler: SliderHandler?
|
||||
var volumeSliderHandler: SliderHandler?
|
||||
|
||||
private let prefs = UserDefaults.standard
|
||||
|
||||
init(_ identifier: CGDirectDisplayID, name: String, serial: String, isEnabled: Bool = true) {
|
||||
self.identifier = identifier
|
||||
self.name = name
|
||||
|
|
@ -28,13 +30,13 @@ class Display {
|
|||
func mute() {
|
||||
var value = 0
|
||||
if isMuted {
|
||||
value = UserDefaults.standard.integer(forKey: "\(AUDIO_SPEAKER_VOLUME)-\(identifier)")
|
||||
value = prefs.integer(forKey: "\(AUDIO_SPEAKER_VOLUME)-\(identifier)")
|
||||
isMuted = false
|
||||
} else {
|
||||
isMuted = true
|
||||
}
|
||||
|
||||
Utils.ddcctl(monitor: identifier, command: AUDIO_SPEAKER_VOLUME, value: value)
|
||||
Utils.sendCommand(AUDIO_SPEAKER_VOLUME, toMonitor: identifier, withValue: value)
|
||||
if let slider = volumeSliderHandler?.slider {
|
||||
slider.intValue = Int32(value)
|
||||
}
|
||||
|
|
@ -46,7 +48,7 @@ class Display {
|
|||
isMuted = false
|
||||
}
|
||||
|
||||
Utils.ddcctl(monitor: identifier, command: AUDIO_SPEAKER_VOLUME, value: value)
|
||||
Utils.sendCommand(AUDIO_SPEAKER_VOLUME, toMonitor: identifier, withValue: value)
|
||||
if let slider = volumeSliderHandler?.slider {
|
||||
slider.intValue = Int32(value)
|
||||
}
|
||||
|
|
@ -55,7 +57,7 @@ class Display {
|
|||
}
|
||||
|
||||
func setBrightness(to value: Int) {
|
||||
Utils.ddcctl(monitor: identifier, command: BRIGHTNESS, value: value)
|
||||
Utils.sendCommand(BRIGHTNESS, toMonitor: identifier, withValue: value)
|
||||
if let slider = brightnessSliderHandler?.slider {
|
||||
slider.intValue = Int32(value)
|
||||
}
|
||||
|
|
@ -64,12 +66,12 @@ class Display {
|
|||
}
|
||||
|
||||
func calcNewValue(for command: Int32, withRel rel: Int) -> Int {
|
||||
let currentValue = UserDefaults.standard.integer(forKey: "\(command)-\(identifier)")
|
||||
let currentValue = prefs.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)")
|
||||
prefs.set(value, forKey: "\(command)-\(identifier)")
|
||||
}
|
||||
|
||||
private func showOsd(command: Int32, value: Int) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class SliderHandler {
|
|||
slider.integerValue = value
|
||||
}
|
||||
|
||||
Utils.ddcctl(monitor: display.identifier, command: command, value: value)
|
||||
prefs.setValue(value, forKey: "\(command)-\(display.identifier)")
|
||||
Utils.sendCommand(command, toMonitor: display.identifier, withValue: value)
|
||||
display.saveValue(value, for: command)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class DisplayPrefsViewController: NSViewController, MASPreferencesViewController
|
|||
default: break
|
||||
}
|
||||
// TODO: Toggle allScreens state
|
||||
print("Toggle allScreens state -> \(sender.state)")
|
||||
print("Toggle allScreens state -> \(sender.state == .on ? "on" : "off")")
|
||||
}
|
||||
|
||||
// MARK: - Table datasource
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
import Cocoa
|
||||
import MASPreferences
|
||||
import ServiceManagement
|
||||
|
||||
class MainPrefsViewController: NSViewController, MASPreferencesViewController {
|
||||
|
||||
|
|
@ -27,15 +28,17 @@ class MainPrefsViewController: NSViewController, MASPreferencesViewController {
|
|||
}
|
||||
|
||||
@IBAction func startAtLoginClicked(_ sender: NSButton) {
|
||||
let identifier = "me.guillaumeb.MonitorControlHelper" as CFString
|
||||
switch sender.state {
|
||||
case .on:
|
||||
prefs.set(true, forKey: Utils.PrefKeys.startAtLogin.rawValue)
|
||||
SMLoginItemSetEnabled(identifier, true)
|
||||
case .off:
|
||||
prefs.set(false, forKey: Utils.PrefKeys.startAtLogin.rawValue)
|
||||
SMLoginItemSetEnabled(identifier, false)
|
||||
default: break
|
||||
}
|
||||
// TODO: Toggle start at login state
|
||||
print("Toggle start at login state -> \(sender.state)")
|
||||
print("Toggle start at login state -> \(sender.state == .on ? "on" : "off")")
|
||||
}
|
||||
|
||||
@IBAction func startWhenExternalClicked(_ sender: NSButton) {
|
||||
|
|
@ -47,6 +50,6 @@ class MainPrefsViewController: NSViewController, MASPreferencesViewController {
|
|||
default: break
|
||||
}
|
||||
// TODO: Toggle start when external plugged in state
|
||||
print("Toggle start when external plugged in state -> \(sender.state)")
|
||||
print("Toggle start when external plugged in state -> \(sender.state == .on ? "on" : "off")")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,13 +15,29 @@ class Utils: NSObject {
|
|||
/// Send command to ddcctl
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - monitor: The id of the Monitor to send the command to
|
||||
/// - command: The command to send
|
||||
/// - monitor: The id of the Monitor to send the command to
|
||||
/// - value: the value of the command
|
||||
static func ddcctl(monitor: CGDirectDisplayID, command: Int32, value: Int) {
|
||||
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)
|
||||
print(value)
|
||||
print("\(command == BRIGHTNESS ? "Brightness" : "Volume") value : \(value)")
|
||||
}
|
||||
|
||||
/// 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)
|
||||
print("\(command == BRIGHTNESS ? "Brightness" : "Volume") value : \(readCmd.current_value)")
|
||||
return Int(readCmd.current_value)
|
||||
}
|
||||
|
||||
// MARK: - Menu
|
||||
|
|
@ -59,17 +75,18 @@ class Utils: NSObject {
|
|||
slider.target = handler
|
||||
slider.minValue = 0
|
||||
slider.maxValue = 100
|
||||
slider.integerValue = prefs.integer(forKey: "\(command)-\(display.serial)")
|
||||
slider.integerValue = getCommand(command, fromMonitor: display.identifier)
|
||||
slider.action = #selector(SliderHandler.valueChanged)
|
||||
handler.slider = slider
|
||||
display.saveValue(slider.integerValue, for: command)
|
||||
|
||||
view.addSubview(label)
|
||||
view.addSubview(slider)
|
||||
|
||||
item.view = view
|
||||
|
||||
menu.addItem(item)
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
menu.insertItem(item, at: 0)
|
||||
menu.insertItem(NSMenuItem.separator(), at: 1)
|
||||
|
||||
return handler
|
||||
}
|
||||
|
|
|
|||
32
MonitorControlHelper/AppDelegate.swift
Normal file
32
MonitorControlHelper/AppDelegate.swift
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// AppDelegate.swift
|
||||
// MonitorControlHelper
|
||||
//
|
||||
// Created by Guillaume BRODER on 13/01/2018.
|
||||
// Copyright © 2018 Mathew Kurian. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
@NSApplicationMain
|
||||
class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
|
||||
@IBOutlet weak var window: NSWindow!
|
||||
|
||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||
let bundlePath = Bundle.main.bundlePath as NSString
|
||||
var pathComponents = bundlePath.pathComponents
|
||||
for _ in 0...4 {
|
||||
pathComponents.removeLast()
|
||||
}
|
||||
|
||||
let path = NSString.path(withComponents: pathComponents)
|
||||
NSWorkspace.shared.launchApplication(path)
|
||||
NSApp.terminate(nil)
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ aNotification: Notification) {
|
||||
// Insert code here to tear down your application
|
||||
}
|
||||
|
||||
}
|
||||
34
MonitorControlHelper/Info.plist
Normal file
34
MonitorControlHelper/Info.plist
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSBackgroundOnly</key>
|
||||
<true/>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>MIT Licensed. 2018.</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
10
MonitorControlHelper/MonitorControlHelper.entitlements
Normal file
10
MonitorControlHelper/MonitorControlHelper.entitlements
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
Loading…
Add table
Add a link
Reference in a new issue