From 036a29d4bccbf5fe790aedb47783719f4a669d0a Mon Sep 17 00:00:00 2001 From: Guillaume Broder Date: Sun, 24 Sep 2017 15:25:46 +0200 Subject: [PATCH] :tada: 1.0 - Code rework - Native OSD - Change default shortcuts for problems with apps - Codesign app Signed-off-by: Guillaume Broder --- .github/menulet.png | Bin 0 -> 23623 bytes .github/osd.png | Bin 0 -> 2367 bytes License.txt | 21 ++ .../contents.xcworkspacedata | 7 - .../xcschemes/xcschememanagement.plist | 22 --- MonitorControl.OSX/Bridging-Header.h | 2 - .../project.pbxproj | 186 +++++++++++++++--- .../AppDelegate.swift | 169 ++++++++-------- .../AppIcon.appiconset/Contents.json | 0 MonitorControl/Assets.xcassets/Contents.json | 6 + .../status.imageset/Contents.json | 25 +++ .../status.imageset/status.png | Bin 0 -> 1312 bytes .../status.imageset/status@2x.png | Bin 0 -> 1592 bytes .../Base.lproj/MainMenu.xib | 8 +- MonitorControl/Bridging-Header.h | 16 ++ .../Info.plist | 8 +- MonitorControl/Objects/SliderHandler.swift | 37 ++++ MonitorControl/Utils.swift | 55 ++++++ MonitorControl/en.lproj/Localizable.strings | Bin 0 -> 1360 bytes MonitorControl/en.lproj/MainMenu.strings | 3 + MonitorControl/fr.lproj/Localizable.strings | Bin 0 -> 1448 bytes MonitorControl/fr.lproj/MainMenu.strings | 3 + OSD.framework/Headers/OSDManager.h | 21 ++ OSD.framework/Headers/OSDUIHelperProtocol.h | 11 ++ OSD.framework/OSD | 1 + OSD.framework/Resources | 1 + OSD.framework/Versions/A/OSD | Bin 0 -> 24992 bytes OSD.framework/Versions/A/Resources/Info.plist | 46 +++++ .../Versions/A/Resources/version.plist | 18 ++ .../Versions/A/_CodeSignature/CodeResources | 139 +++++++++++++ OSD.framework/Versions/Current | 1 + OSD.framework/XPCServices | 1 + README.md | 40 +++- 33 files changed, 689 insertions(+), 158 deletions(-) create mode 100644 .github/menulet.png create mode 100644 .github/osd.png create mode 100644 License.txt delete mode 100644 MonitorControl.OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 MonitorControl.OSX.xcodeproj/xcuserdata/mkurian.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 MonitorControl.OSX/Bridging-Header.h rename {MonitorControl.OSX.xcodeproj => MonitorControl.xcodeproj}/project.pbxproj (55%) rename {MonitorControl.OSX => MonitorControl}/AppDelegate.swift (61%) rename {MonitorControl.OSX => MonitorControl}/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) create mode 100644 MonitorControl/Assets.xcassets/Contents.json create mode 100644 MonitorControl/Assets.xcassets/status.imageset/Contents.json create mode 100644 MonitorControl/Assets.xcassets/status.imageset/status.png create mode 100644 MonitorControl/Assets.xcassets/status.imageset/status@2x.png rename {MonitorControl.OSX => MonitorControl}/Base.lproj/MainMenu.xib (83%) create mode 100644 MonitorControl/Bridging-Header.h rename {MonitorControl.OSX => MonitorControl}/Info.plist (88%) create mode 100644 MonitorControl/Objects/SliderHandler.swift create mode 100644 MonitorControl/Utils.swift create mode 100644 MonitorControl/en.lproj/Localizable.strings create mode 100644 MonitorControl/en.lproj/MainMenu.strings create mode 100644 MonitorControl/fr.lproj/Localizable.strings create mode 100644 MonitorControl/fr.lproj/MainMenu.strings create mode 100644 OSD.framework/Headers/OSDManager.h create mode 100644 OSD.framework/Headers/OSDUIHelperProtocol.h create mode 120000 OSD.framework/OSD create mode 120000 OSD.framework/Resources create mode 100755 OSD.framework/Versions/A/OSD create mode 100644 OSD.framework/Versions/A/Resources/Info.plist create mode 100644 OSD.framework/Versions/A/Resources/version.plist create mode 100644 OSD.framework/Versions/A/_CodeSignature/CodeResources create mode 120000 OSD.framework/Versions/Current create mode 120000 OSD.framework/XPCServices diff --git a/.github/menulet.png b/.github/menulet.png new file mode 100644 index 0000000000000000000000000000000000000000..36ab2c1e3e82040dddd92e2ce2eaf64dd184fc3a GIT binary patch literal 23623 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 - - - - diff --git a/MonitorControl.OSX.xcodeproj/xcuserdata/mkurian.xcuserdatad/xcschemes/xcschememanagement.plist b/MonitorControl.OSX.xcodeproj/xcuserdata/mkurian.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index cfd5bfa..0000000 --- a/MonitorControl.OSX.xcodeproj/xcuserdata/mkurian.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - SchemeUserState - - MonitorControl.OSX.xcscheme - - orderHint - 0 - - - SuppressBuildableAutocreation - - 56754EAA1D9A4016007BCDC5 - - primary - - - - - diff --git a/MonitorControl.OSX/Bridging-Header.h b/MonitorControl.OSX/Bridging-Header.h deleted file mode 100644 index 8c4e0fa..0000000 --- a/MonitorControl.OSX/Bridging-Header.h +++ /dev/null @@ -1,2 +0,0 @@ -#import -#include "../ddcctl/DDC.h" diff --git a/MonitorControl.OSX.xcodeproj/project.pbxproj b/MonitorControl.xcodeproj/project.pbxproj similarity index 55% rename from MonitorControl.OSX.xcodeproj/project.pbxproj rename to MonitorControl.xcodeproj/project.pbxproj index 31fe48a..d4d679e 100644 --- a/MonitorControl.OSX.xcodeproj/project.pbxproj +++ b/MonitorControl.xcodeproj/project.pbxproj @@ -12,6 +12,10 @@ 56754EAF1D9A4016007BCDC5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56754EAE1D9A4016007BCDC5 /* AppDelegate.swift */; }; 56754EB11D9A4016007BCDC5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 56754EB01D9A4016007BCDC5 /* Assets.xcassets */; }; 56754EB41D9A4016007BCDC5 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 56754EB21D9A4016007BCDC5 /* MainMenu.xib */; }; + 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 PBXFileReference section */ @@ -21,12 +25,30 @@ 55359E361E2737EC002671BC /* ddcctl.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = ddcctl.sh; sourceTree = ""; }; 55359E371E2737EC002671BC /* Makefile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; 55359E381E2737EC002671BC /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - 55359E3E1E27380B002671BC /* Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = ""; }; - 56754EAB1D9A4016007BCDC5 /* MonitorControl.OSX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MonitorControl.OSX.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 56754EAE1D9A4016007BCDC5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 56754EAB1D9A4016007BCDC5 /* MonitorControl.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MonitorControl.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 56754EAE1D9A4016007BCDC5 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AppDelegate.swift; sourceTree = ""; }; 56754EB01D9A4016007BCDC5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 56754EB31D9A4016007BCDC5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 56754EB51D9A4016007BCDC5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F091C9B21F6EA6110096FD65 /* SliderHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SliderHandler.swift; sourceTree = ""; }; + F091C9B71F6EA79B0096FD65 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; + F091C9B91F6EB43B0096FD65 /* fr */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; lineEnding = 0; name = fr; path = fr.lproj/MainMenu.strings; sourceTree = ""; }; + F091C9C21F6EB8660096FD65 /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; lineEnding = 0; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; + F091C9C31F6EB8720096FD65 /* fr */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; lineEnding = 0; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; + F091C9C41F6EBA5A0096FD65 /* Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = ""; }; + F0A987D51F77A823009B603D /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; lineEnding = 0; name = en; path = en.lproj/MainMenu.strings; sourceTree = ""; }; + F0A987D61F77B290009B603D /* OSD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OSD.framework; sourceTree = ""; }; + F0A987DA1F77B404009B603D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/MainMenu.strings; sourceTree = ""; }; + F0A987DC1F77B404009B603D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; + F0A987DD1F77B404009B603D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + F0A987DF1F77B404009B603D /* SliderHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SliderHandler.swift; sourceTree = ""; }; + F0A987E11F77B404009B603D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + F0A987E21F77B404009B603D /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; + F0A987E31F77B404009B603D /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/MainMenu.strings; sourceTree = ""; }; + F0A987E41F77B404009B603D /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; + F0A987E51F77B404009B603D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + F0A987E61F77B404009B603D /* Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = ""; }; + F0A987E71F77B404009B603D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -34,6 +56,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F0A987E81F77B40E009B603D /* OSD.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -56,38 +79,83 @@ 56754EA21D9A4016007BCDC5 = { isa = PBXGroup; children = ( - 56754EAD1D9A4016007BCDC5 /* MonitorControl.OSX */, + 56754EAD1D9A4016007BCDC5 /* MonitorControl */, + F0A987D61F77B290009B603D /* OSD.framework */, 55359E321E2737EC002671BC /* ddcctl */, 56754EAC1D9A4016007BCDC5 /* Products */, + F0A987D71F77B404009B603D /* Frameworks */, ); sourceTree = ""; }; 56754EAC1D9A4016007BCDC5 /* Products */ = { isa = PBXGroup; children = ( - 56754EAB1D9A4016007BCDC5 /* MonitorControl.OSX.app */, + 56754EAB1D9A4016007BCDC5 /* MonitorControl.app */, ); name = Products; sourceTree = ""; }; - 56754EAD1D9A4016007BCDC5 /* MonitorControl.OSX */ = { + 56754EAD1D9A4016007BCDC5 /* MonitorControl */ = { isa = PBXGroup; children = ( 56754EAE1D9A4016007BCDC5 /* AppDelegate.swift */, + F091C9B71F6EA79B0096FD65 /* Utils.swift */, + F091C9B41F6EA6180096FD65 /* Objects */, + F091C9C41F6EBA5A0096FD65 /* Bridging-Header.h */, 56754EB01D9A4016007BCDC5 /* Assets.xcassets */, 56754EB21D9A4016007BCDC5 /* MainMenu.xib */, + F091C9C11F6EB8660096FD65 /* Localizable.strings */, 56754EB51D9A4016007BCDC5 /* Info.plist */, - 55359E3E1E27380B002671BC /* Bridging-Header.h */, ); - path = MonitorControl.OSX; + path = MonitorControl; + sourceTree = ""; + }; + F091C9B41F6EA6180096FD65 /* Objects */ = { + isa = PBXGroup; + children = ( + F091C9B21F6EA6110096FD65 /* SliderHandler.swift */, + ); + path = Objects; + sourceTree = ""; + }; + F0A987D71F77B404009B603D /* Frameworks */ = { + isa = PBXGroup; + children = ( + F0A987D81F77B404009B603D /* MonitorControl */, + ); + name = Frameworks; + sourceTree = ""; + }; + F0A987D81F77B404009B603D /* MonitorControl */ = { + isa = PBXGroup; + children = ( + F0A987D91F77B404009B603D /* MainMenu.strings */, + F0A987DB1F77B404009B603D /* Localizable.strings */, + F0A987DD1F77B404009B603D /* Assets.xcassets */, + F0A987DE1F77B404009B603D /* Objects */, + F0A987E01F77B404009B603D /* MainMenu.xib */, + F0A987E21F77B404009B603D /* Utils.swift */, + F0A987E51F77B404009B603D /* AppDelegate.swift */, + F0A987E61F77B404009B603D /* Bridging-Header.h */, + F0A987E71F77B404009B603D /* Info.plist */, + ); + path = MonitorControl; + sourceTree = ""; + }; + F0A987DE1F77B404009B603D /* Objects */ = { + isa = PBXGroup; + children = ( + F0A987DF1F77B404009B603D /* SliderHandler.swift */, + ); + path = Objects; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 56754EAA1D9A4016007BCDC5 /* MonitorControl.OSX */ = { + 56754EAA1D9A4016007BCDC5 /* MonitorControl */ = { isa = PBXNativeTarget; - buildConfigurationList = 56754EB81D9A4016007BCDC5 /* Build configuration list for PBXNativeTarget "MonitorControl.OSX" */; + buildConfigurationList = 56754EB81D9A4016007BCDC5 /* Build configuration list for PBXNativeTarget "MonitorControl" */; buildPhases = ( 56754EA71D9A4016007BCDC5 /* Sources */, 56754EA81D9A4016007BCDC5 /* Frameworks */, @@ -97,9 +165,9 @@ ); dependencies = ( ); - name = MonitorControl.OSX; + name = MonitorControl; productName = MonitorControl.OSX; - productReference = 56754EAB1D9A4016007BCDC5 /* MonitorControl.OSX.app */; + productReference = 56754EAB1D9A4016007BCDC5 /* MonitorControl.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -109,29 +177,31 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0800; - LastUpgradeCheck = 0820; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = "Mathew Kurian"; TargetAttributes = { 56754EAA1D9A4016007BCDC5 = { CreatedOnToolsVersion = 8.0; + LastSwiftMigration = 0900; ProvisioningStyle = Automatic; }; }; }; - buildConfigurationList = 56754EA61D9A4016007BCDC5 /* Build configuration list for PBXProject "MonitorControl.OSX" */; + buildConfigurationList = 56754EA61D9A4016007BCDC5 /* Build configuration list for PBXProject "MonitorControl" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, + fr, ); mainGroup = 56754EA21D9A4016007BCDC5; productRefGroup = 56754EAC1D9A4016007BCDC5 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( - 56754EAA1D9A4016007BCDC5 /* MonitorControl.OSX */, + 56754EAA1D9A4016007BCDC5 /* MonitorControl */, ); }; /* End PBXProject section */ @@ -142,6 +212,7 @@ buildActionMask = 2147483647; files = ( 56754EB11D9A4016007BCDC5 /* Assets.xcassets in Resources */, + F0EB972F1F6ED7C800686D2A /* Localizable.strings in Resources */, 55359E3B1E2737EC002671BC /* ddcctl.sh in Resources */, 56754EB41D9A4016007BCDC5 /* MainMenu.xib in Resources */, ); @@ -154,8 +225,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + F091C9B31F6EA6110096FD65 /* SliderHandler.swift in Sources */, 56754EAF1D9A4016007BCDC5 /* AppDelegate.swift in Sources */, 55359E391E2737EC002671BC /* DDC.c in Sources */, + F091C9B81F6EA79B0096FD65 /* Utils.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -166,6 +239,43 @@ isa = PBXVariantGroup; children = ( 56754EB31D9A4016007BCDC5 /* Base */, + F091C9B91F6EB43B0096FD65 /* fr */, + F0A987D51F77A823009B603D /* en */, + ); + name = MainMenu.xib; + sourceTree = ""; + }; + F091C9C11F6EB8660096FD65 /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + F091C9C21F6EB8660096FD65 /* en */, + F091C9C31F6EB8720096FD65 /* fr */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + F0A987D91F77B404009B603D /* MainMenu.strings */ = { + isa = PBXVariantGroup; + children = ( + F0A987DA1F77B404009B603D /* en */, + F0A987E31F77B404009B603D /* fr */, + ); + name = MainMenu.strings; + sourceTree = ""; + }; + F0A987DB1F77B404009B603D /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + F0A987DC1F77B404009B603D /* en */, + F0A987E41F77B404009B603D /* fr */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + F0A987E01F77B404009B603D /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + F0A987E11F77B404009B603D /* Base */, ); name = MainMenu.xib; sourceTree = ""; @@ -177,12 +287,15 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -190,7 +303,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; @@ -200,6 +317,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/**"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -227,12 +345,15 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; @@ -240,7 +361,11 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; @@ -250,6 +375,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/**"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -269,13 +395,18 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = MonitorControl.OSX/Info.plist; + DEVELOPMENT_TEAM = ""; + FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/**"; + INFOPLIST_FILE = "$(SRCROOT)/MonitorControl/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "bluejamesbond.MonitorControl-OSX"; + PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControl; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "MonitorControl.OSX/Bridging-Header.h"; - SWIFT_VERSION = 3.0; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = "MonitorControl/Bridging-Header.h"; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -283,20 +414,25 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = MonitorControl.OSX/Info.plist; + DEVELOPMENT_TEAM = ""; + FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/**"; + INFOPLIST_FILE = "$(SRCROOT)/MonitorControl/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "bluejamesbond.MonitorControl-OSX"; + PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControl; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "MonitorControl.OSX/Bridging-Header.h"; - SWIFT_VERSION = 3.0; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = "MonitorControl/Bridging-Header.h"; + SWIFT_VERSION = 4.0; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 56754EA61D9A4016007BCDC5 /* Build configuration list for PBXProject "MonitorControl.OSX" */ = { + 56754EA61D9A4016007BCDC5 /* Build configuration list for PBXProject "MonitorControl" */ = { isa = XCConfigurationList; buildConfigurations = ( 56754EB61D9A4016007BCDC5 /* Debug */, @@ -305,7 +441,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 56754EB81D9A4016007BCDC5 /* Build configuration list for PBXNativeTarget "MonitorControl.OSX" */ = { + 56754EB81D9A4016007BCDC5 /* Build configuration list for PBXNativeTarget "MonitorControl" */ = { isa = XCConfigurationList; buildConfigurations = ( 56754EB91D9A4016007BCDC5 /* Debug */, diff --git a/MonitorControl.OSX/AppDelegate.swift b/MonitorControl/AppDelegate.swift similarity index 61% rename from MonitorControl.OSX/AppDelegate.swift rename to MonitorControl/AppDelegate.swift index 6a2d692..ccce703 100644 --- a/MonitorControl.OSX/AppDelegate.swift +++ b/MonitorControl/AppDelegate.swift @@ -1,9 +1,10 @@ // // AppDelegate.swift -// MonitorControl.OSX +// MonitorControl // // Created by Mathew Kurian on 9/26/16. -// Copyright © 2016 Mathew Kurian. All rights reserved. +// Last edited by Guillaume Broder on 9/17/2017 +// MIT Licensed. 2017. // import Cocoa @@ -18,47 +19,13 @@ struct Display { var app: AppDelegate! = nil let prefs = UserDefaults.standard -func ddcctl(monitor: CGDirectDisplayID, command: Int32, value: Int) { - var wrcmd = DDCWriteCommand(control_id: UInt8(command), new_value: UInt8(value)) - DDCWrite(monitor, &wrcmd) - print(value) -} - -class SliderHandler : NSObject { - var display : Display - var command : Int32 = 0 - - public init(display: Display, command: Int32) { - self.display = display - self.command = command - } - - func valueChanged(slider: NSSlider) { - let snapInterval = 25 - let snapThreshold = 3 - - var value = slider.integerValue - - let closest = (value + snapInterval / 2) / snapInterval * snapInterval - if abs(closest - value) <= snapThreshold { - value = closest - slider.integerValue = value - } - - ddcctl(monitor: display.id, command: command, value: value) - - prefs.setValue(value, forKey: "\(command)-\(display.serial)") - prefs.synchronize() - } -} - @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { @IBOutlet weak var statusMenu: NSMenu! @IBOutlet weak var window: NSWindow! - let statusItem = NSStatusBar.system().statusItem(withLength: NSVariableStatusItemLength) + let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) var monitorItems: [NSMenuItem] = [] var displays: [Display] = [] @@ -68,14 +35,16 @@ class AppDelegate: NSObject, NSApplicationDelegate { var defaultBrightnessSlider: NSSlider! = nil var defaultVolumeSlider: NSSlider! = nil + let step = 100/16; + @IBAction func quitClicked(_ sender: AnyObject) { - NSApplication.shared().terminate(self) + NSApplication.shared.terminate(self) } func applicationDidFinishLaunching(_ aNotification: Notification) { app = self - statusItem.title = "♨" + statusItem.image = NSImage.init(named: NSImage.Name(rawValue: "status")) statusItem.menu = statusMenu acquirePrivileges() @@ -84,39 +53,63 @@ class AppDelegate: NSObject, NSApplicationDelegate { updateDisplays() NSEvent.addGlobalMonitorForEvents( - matching: NSEventMask.keyDown, handler: {(event: NSEvent) in + matching: NSEvent.EventTypeMask.keyDown, handler: {(event: NSEvent) in if self.defaultDisplay == nil { return } - let modifiers = NSEventModifierFlags.init(rawValue: NSEventModifierFlags.command.rawValue | - NSEventModifierFlags.control.rawValue | - NSEventModifierFlags.option.rawValue | - NSEventModifierFlags.shift.rawValue) - var flags = event.modifierFlags.intersection(modifiers) + // Keyboard shortcut only for main screen + let currentDisplayId = NSScreen.main?.deviceDescription[NSDeviceDescriptionKey.init("NSScreenNumber")] as! CGDirectDisplayID + if (self.defaultDisplay.id != currentDisplayId) { + return + } - if !flags.contains(NSEventModifierFlags.command) { - return - } - flags.subtract(NSEventModifierFlags.command) + // Brightness -> Shift + Control + Alt + Command + (Up/Down) + // Volume -> Shift + Control + Alt + Command + (Left/Right) + // Mute -> Minus - var rel = 0 - if event.keyCode == 27 { - rel = -5 - } else if event.keyCode == 24 { - rel = +5 - } else { + // Capture keys + let modifiers = NSEvent.ModifierFlags.init(rawValue: NSEvent.ModifierFlags.shift.rawValue | NSEvent.ModifierFlags.command.rawValue | NSEvent.ModifierFlags.control.rawValue | NSEvent.ModifierFlags.option.rawValue) + let flags = event.modifierFlags.intersection(modifiers) + + // Only do something if all modifiers are active + if !flags.contains(NSEvent.ModifierFlags.shift) || !flags.contains(NSEvent.ModifierFlags.command) || !flags.contains(NSEvent.ModifierFlags.control) || !flags.contains(NSEvent.ModifierFlags.option) { + return + } + + var brightnessRel = 0 + var volumeRel = 0 + var rel = 0 + + // Down key + if event.keyCode == Utils.key.keyDownArrow.rawValue { + brightnessRel = -self.step + // Up key + } else if event.keyCode == Utils.key.keyUpArrow.rawValue { + brightnessRel = +self.step + // Left key + } else if event.keyCode == Utils.key.keyLeftArrow.rawValue { + volumeRel = -self.step + // Right key + } else if event.keyCode == Utils.key.keyRightArrow.rawValue { + volumeRel = +self.step + // M key + } else if event.keyCode == Utils.key.keyMute.rawValue { + volumeRel = -100 + } else { return } var command = Int32() var slider: NSSlider! = nil - if flags == NSEventModifierFlags.option { + if brightnessRel == 0 { command = AUDIO_SPEAKER_VOLUME slider = self.defaultVolumeSlider - } else if flags == NSEventModifierFlags.shift { + rel = volumeRel + } else if volumeRel == 0 { command = BRIGHTNESS slider = self.defaultBrightnessSlider + rel = brightnessRel } else { return } @@ -128,30 +121,27 @@ class AppDelegate: NSObject, NSApplicationDelegate { prefs.synchronize() slider.intValue = Int32(value) - ddcctl(monitor: self.defaultDisplay.id, command: command, value: value) + Utils.ddcctl(monitor: self.defaultDisplay.id, command: command, value: value) + + // OSD + let manager : OSDManager = OSDManager.sharedManager() as! OSDManager + var osdImage : Int = 1 // Brightness Image + if brightnessRel == 0 { + osdImage = 3 // Speaker image + if value == 0 { + osdImage = 4 // Mute speaker + } + } + manager.showImage(Int64(osdImage), onDisplayID: self.defaultDisplay.id, priority: 0x1f4, msecUntilFade: 2000, filledChiclets: UInt32(value/self.step), totalChiclets: UInt32(100/self.step), locked: false) }) } - 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 - } - - func addSliderItem(menu: NSMenu, isDefaultDisplay: Bool, display: Display, command: Int32, title: String, shortcut: String) -> NSSlider { + func addSliderItem(menu: NSMenu, isDefaultDisplay: Bool, display: Display, command: Int32, title: String) -> NSSlider { let item = NSMenuItem() let view = NSView(frame: NSRect(x: 0, y: 5, width: 250, height: 40)) - let label = makeLabel(text: title, frame: NSRect(x: 20, y: 19, width: 130, height: 20)) - - let labelKeyCode = makeLabel(text: shortcut, frame: NSRect(x: 120, y: 19, width: 100, height: 20)) - labelKeyCode.isHidden = !isDefaultDisplay - labelKeyCode.alignment = NSTextAlignment.right + let label = Utils.makeLabel(text: title, frame: NSRect(x: 20, y: 19, width: 130, height: 20)) let handler = SliderHandler(display: display, command: command) sliderHandlers.append(handler) @@ -161,14 +151,13 @@ class AppDelegate: NSObject, NSApplicationDelegate { slider.minValue = 0 slider.maxValue = 100 slider.integerValue = prefs.integer(forKey: "\(command)-\(display.serial)") - slider.action = #selector(SliderHandler.valueChanged) + slider.action = #selector(SliderHandler.valueChanged) view.addSubview(label) - view.addSubview(labelKeyCode) view.addSubview(slider) item.view = view - + menu.addItem(item) menu.addItem(NSMenuItem.separator()) @@ -183,14 +172,15 @@ class AppDelegate: NSObject, NSApplicationDelegate { for m in monitorItems { statusMenu.removeItem(m) } + monitorItems = [] displays = [] sliderHandlers = [] sleep(1) - for s in NSScreen.screens()! { - let id = s.deviceDescription["NSScreenNumber"] as! CGDirectDisplayID + for s in NSScreen.screens { + let id = s.deviceDescription[NSDeviceDescriptionKey.init("NSScreenNumber")] as! CGDirectDisplayID if CGDisplayIsBuiltin(id) != 0 { continue } @@ -211,17 +201,16 @@ class AppDelegate: NSObject, NSApplicationDelegate { let monitorMenuItem = NSMenuItem() let monitorSubMenu = NSMenu() - let brightnessSlider = addSliderItem(menu: monitorSubMenu, isDefaultDisplay: isDefaultDisplay, display: d, command: BRIGHTNESS, title: "Brightness", shortcut: "⇧⌘- / ⇧⌘+") - let _ = addSliderItem(menu: monitorSubMenu, isDefaultDisplay: isDefaultDisplay, display: d, command: CONTRAST, title: "Contrast", shortcut: "") - let volumeSlider = addSliderItem(menu: monitorSubMenu, isDefaultDisplay: isDefaultDisplay, display: d, command: AUDIO_SPEAKER_VOLUME, title: "Volume", shortcut: "⌥⌘- / ⌥⌘+") - + let brightnessSlider = addSliderItem(menu: monitorSubMenu, isDefaultDisplay: isDefaultDisplay, display: d, command: BRIGHTNESS, title: NSLocalizedString("Brightness", comment: "Sown in menu")) + let _ = addSliderItem(menu: monitorSubMenu, isDefaultDisplay: isDefaultDisplay, display: d, command: CONTRAST, title: NSLocalizedString("Contrast", comment: "Shown in menu")) + let volumeSlider = addSliderItem(menu: monitorSubMenu, isDefaultDisplay: isDefaultDisplay, display: d, command: AUDIO_SPEAKER_VOLUME, title: NSLocalizedString("Volume", comment: "Shown in menu")) let defaultMonitorItem = NSMenuItem() let defaultMonitorView = NSView(frame: NSRect(x: 0, y: 5, width: 250, height: 25)) let defaultMonitorSelectButtom = NSButton(frame: NSRect(x: 25, y: 0, width: 200, height: 25)) - defaultMonitorSelectButtom.title = isDefaultDisplay ? "Default" : "Set as default" - defaultMonitorSelectButtom.bezelStyle = NSRoundRectBezelStyle + 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 defaultMonitorView.addSubview(defaultMonitorSelectButtom) @@ -246,19 +235,19 @@ class AppDelegate: NSObject, NSApplicationDelegate { if defaultDisplay == nil { // If no DDC capable display was detected let item = NSMenuItem() - item.title = "No supported display found" + item.title = NSLocalizedString("No supported display found", comment: "Shown in menu") item.isEnabled = false monitorItems.append(item) statusMenu.insertItem(item, at: 0) } } - + func acquirePrivileges() { let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: true] let accessibilityEnabled = AXIsProcessTrustedWithOptions(options) if !accessibilityEnabled { - print("You need to enable the keylogger in the System Prefrences") + print(NSLocalizedString("You need to enable the keylogger in the System Prefrences for the keyboard shortcuts to work", comment: "")) } return @@ -293,10 +282,10 @@ class AppDelegate: NSObject, NSApplicationDelegate { } func getDisplayName(_ edid: EDID) -> String { - return getDescriptorString(edid, 0xFC) ?? "Display" + return getDescriptorString(edid, 0xFC) ?? NSLocalizedString("Display", comment: "") } func getDisplaySerial(_ edid: EDID) -> String { - return getDescriptorString(edid, 0xFF) ?? "Unknown" + return getDescriptorString(edid, 0xFF) ?? NSLocalizedString("Unknown", comment: "") } } diff --git a/MonitorControl.OSX/Assets.xcassets/AppIcon.appiconset/Contents.json b/MonitorControl/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from MonitorControl.OSX/Assets.xcassets/AppIcon.appiconset/Contents.json rename to MonitorControl/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/MonitorControl/Assets.xcassets/Contents.json b/MonitorControl/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/MonitorControl/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MonitorControl/Assets.xcassets/status.imageset/Contents.json b/MonitorControl/Assets.xcassets/status.imageset/Contents.json new file mode 100644 index 0000000..719188e --- /dev/null +++ b/MonitorControl/Assets.xcassets/status.imageset/Contents.json @@ -0,0 +1,25 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "status.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "status@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/MonitorControl/Assets.xcassets/status.imageset/status.png b/MonitorControl/Assets.xcassets/status.imageset/status.png new file mode 100644 index 0000000000000000000000000000000000000000..44e755220926d8a353d5e5bf87eda719bab14aa8 GIT binary patch literal 1312 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 - + + - + @@ -12,7 +12,7 @@ - + diff --git a/MonitorControl/Bridging-Header.h b/MonitorControl/Bridging-Header.h new file mode 100644 index 0000000..7d73d33 --- /dev/null +++ b/MonitorControl/Bridging-Header.h @@ -0,0 +1,16 @@ +// +// Bridging-Header.h +// MonitorControl +// +// Created by Guillaume BRODER on 17/09/2017. +// MIT Licensed. 2017. +// + +#ifndef Bridging_Header_h +#define Bridging_Header_h + +#import +#include "../ddcctl/DDC.h" +#import + +#endif /* Bridging_Header_h */ diff --git a/MonitorControl.OSX/Info.plist b/MonitorControl/Info.plist similarity index 88% rename from MonitorControl.OSX/Info.plist rename to MonitorControl/Info.plist index 814050e..2fe6225 100644 --- a/MonitorControl.OSX/Info.plist +++ b/MonitorControl/Info.plist @@ -20,15 +20,17 @@ 1.0 CFBundleVersion 1 + LSApplicationCategoryType + public.app-category.utilities LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) + LSUIElement + NSHumanReadableCopyright - Copyright © 2016 Mathew Kurian. All rights reserved. + MIT Licensed. 2017. NSMainNibFile MainMenu NSPrincipalClass NSApplication - LSUIElement - diff --git a/MonitorControl/Objects/SliderHandler.swift b/MonitorControl/Objects/SliderHandler.swift new file mode 100644 index 0000000..c470e8e --- /dev/null +++ b/MonitorControl/Objects/SliderHandler.swift @@ -0,0 +1,37 @@ +// +// SliderHandler.swift +// MonitorControl +// +// Created by Guillaume BRODER on 9/17/2017. +// MIT Licensed. 2017. +// + +import Cocoa + +class SliderHandler: NSObject { + var display : Display + var command : Int32 = 0 + + public init(display: Display, command: Int32) { + self.display = display + self.command = command + } + + @objc func valueChanged(slider: NSSlider) { + let snapInterval = 25 + let snapThreshold = 3 + + var value = slider.integerValue + + let closest = (value + snapInterval / 2) / snapInterval * snapInterval + if abs(closest - value) <= snapThreshold { + value = closest + slider.integerValue = value + } + + Utils.ddcctl(monitor: display.id, command: command, value: value) + + prefs.setValue(value, forKey: "\(command)-\(display.serial)") + prefs.synchronize() + } +} diff --git a/MonitorControl/Utils.swift b/MonitorControl/Utils.swift new file mode 100644 index 0000000..15ad8db --- /dev/null +++ b/MonitorControl/Utils.swift @@ -0,0 +1,55 @@ +// +// Utils.swift +// MonitorControl +// +// Created by Guillaume BRODER on 9/17/2017. +// MIT Licensed. +// + +import Cocoa + +class Utils: NSObject { + + /// Send command to ddcctl + /// + /// - Parameters: + /// - monitor: The id of the Monitor to send the command to + /// - command: The command to send + /// - value: the value of the command + static func ddcctl(monitor: CGDirectDisplayID, command: Int32, value: Int) { + var wrcmd = DDCWriteCommand(control_id: UInt8(command), new_value: UInt8(value)) + DDCWrite(monitor, &wrcmd) + print(value) + } + + /// 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 + } + + + /// Enum for hardware independent keyCode + /// + /// - keyLeftArrow: keyCode for the left arrow + /// - keyRightArrow: keyCode for the right arrow + /// - keyDownArrow: keyCode for the down arrow + /// - keyUpArrow: keyCode for the up arrow + enum key : Int { + case keyLeftArrow = 123 + case keyRightArrow = 124 + case keyDownArrow = 125 + case keyUpArrow = 126 + case keyMute = 24 + } +} diff --git a/MonitorControl/en.lproj/Localizable.strings b/MonitorControl/en.lproj/Localizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..02e829876785dc3febdba109dccdbab82a83ffe7 GIT binary patch literal 1360 zcmdUvO;3YB5QgX6U$N=22m1p|FWR#)A)0uk1;La;1KT$IdG(oH2@8JInqJI?Wtoq6 zX5N|Q?R73QF%n57M=3eIxP2=r?>*l$naf0`aw9dmOmeYkQfXLI^b4NvwAXk}@b?k& zlQC|wD8a8K2HghupEc)VFUk2C+`SY7#s*Hawo?o|myajQ*RhJc3xjw$4nCI+TW(m#gT> zb=gpp&Y;ewMdD{OW=;#FD$Ct_!`>pRnA?nVjn3cy<puH!-CaBllS7Ez-T@Ug%%I oPnLRiJ|1-iYK*1k(6~v~*<8blbzVNNBUUv%=vn%|6=+A_0ax?hxc~qF literal 0 HcmV?d00001 diff --git a/MonitorControl/en.lproj/MainMenu.strings b/MonitorControl/en.lproj/MainMenu.strings new file mode 100644 index 0000000..bcd1e86 --- /dev/null +++ b/MonitorControl/en.lproj/MainMenu.strings @@ -0,0 +1,3 @@ + +/* Class = "NSMenuItem"; title = "Quit"; ObjectID = "JTa-2I-AsI"; */ +"JTa-2I-AsI.title" = "Quit"; diff --git a/MonitorControl/fr.lproj/Localizable.strings b/MonitorControl/fr.lproj/Localizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..61c7556676794d7d9b7eca911e69ad4884c0f98d GIT binary patch literal 1448 zcmc(fOG*Pl5Qb}=Qw&*Vp$8BbYFr2+LNMSm$xI$3nThjAh&S{m<`U}nciYS)1Ofq( zX1aUo)qmAr-QQoA*0IQXmf6Nqb~86GEn%(r@7SfatZlcJqnp^&N;HWTj5hjfzP3GL zyL7%8@)^bbdLKHQC3=VkAS`GD|;kwMp3Lc7ZHZwTryq#06(= z8~J_^T~$aAPVQ0vQ%reu1^KKP8F9*AJn`OX5!q!}rC_a@yg@Q@(un*6iU^d=csp_s zPx4=%#dQx%s+yQqt&eka54s$k>Zgv-Ufk5Rk2wGT_MoSMdRvFs6*^3=aGF zF7Q-$)lv7Qf76k#j?)O->Q;4eiNtsDfR5Hpk!N!q!J>y=%q8R! z*|TGC>}FL+?}+b1c?KUJbx2g*L}4gg->Z|=o2B#exHeejaIjyc%2}wZ)_m_o7~olg zP5(N}=Wz^wjBV=tWg~n-t+!yus@oiJhul6LPyX%DjZpkIR#hs*&}|+uynX}{b+PWf SUJQ>(_fgS>)Avqz=Y9Z0t@UOA literal 0 HcmV?d00001 diff --git a/MonitorControl/fr.lproj/MainMenu.strings b/MonitorControl/fr.lproj/MainMenu.strings new file mode 100644 index 0000000..41b2039 --- /dev/null +++ b/MonitorControl/fr.lproj/MainMenu.strings @@ -0,0 +1,3 @@ + +/* Class = "NSMenuItem"; title = "Quit"; ObjectID = "JTa-2I-AsI"; */ +"JTa-2I-AsI.title" = "Quitter"; diff --git a/OSD.framework/Headers/OSDManager.h b/OSD.framework/Headers/OSDManager.h new file mode 100644 index 0000000..a067a8d --- /dev/null +++ b/OSD.framework/Headers/OSDManager.h @@ -0,0 +1,21 @@ +#import "OSDUIHelperProtocol.h" + +@class NSXPCConnection; + +@interface OSDManager : NSObject +{ + id _proxyObject; + NSXPCConnection *connection; +} + ++ (id)sharedManager; +@property(retain) NSXPCConnection *connection; // @synthesize connection; +- (void)showFullScreenImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecToAnimate:(unsigned int)arg4; +- (void)fadeClassicImageOnDisplay:(unsigned int)arg1; +- (void)showImageAtPath:(id)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 withText:(id)arg5; +- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 filledChiclets:(unsigned int)arg5 totalChiclets:(unsigned int)arg6 locked:(BOOL)arg7; +- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 withText:(id)arg5; +- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4; +@property(readonly) id remoteObjectProxy; // @dynamic remoteObjectProxy; + +@end diff --git a/OSD.framework/Headers/OSDUIHelperProtocol.h b/OSD.framework/Headers/OSDUIHelperProtocol.h new file mode 100644 index 0000000..a1246c0 --- /dev/null +++ b/OSD.framework/Headers/OSDUIHelperProtocol.h @@ -0,0 +1,11 @@ +@class NSString; + +@protocol OSDUIHelperProtocol +- (void)showFullScreenImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecToAnimate:(unsigned int)arg4; +- (void)fadeClassicImageOnDisplay:(unsigned int)arg1; +- (void)showImageAtPath:(NSString *)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 withText:(NSString *)arg5; +- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 filledChiclets:(unsigned int)arg5 totalChiclets:(unsigned int)arg6 locked:(BOOL)arg7; +- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4 withText:(NSString *)arg5; +- (void)showImage:(long long)arg1 onDisplayID:(unsigned int)arg2 priority:(unsigned int)arg3 msecUntilFade:(unsigned int)arg4; +@end + diff --git a/OSD.framework/OSD b/OSD.framework/OSD new file mode 120000 index 0000000..ee6bfa0 --- /dev/null +++ b/OSD.framework/OSD @@ -0,0 +1 @@ +Versions/Current/OSD \ No newline at end of file diff --git a/OSD.framework/Resources b/OSD.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/OSD.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/OSD.framework/Versions/A/OSD b/OSD.framework/Versions/A/OSD new file mode 100755 index 0000000000000000000000000000000000000000..58813ae02f8e810bdd823728d5e8d94f93c53464 GIT binary patch literal 24992 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 + + + + BuildMachineOSBuild + 16B2657 + CFBundleDevelopmentRegion + en + CFBundleExecutable + OSD + CFBundleIdentifier + com.apple.OSD + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + OSD + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 9L173x + DTPlatformVersion + GM + DTSDKBuild + 17A317 + DTSDKName + macosx10.13internal + DTXcode + 0900 + DTXcodeBuild + 9L173x + NSHumanReadableCopyright + Copyright © 2015 Apple Inc. All rights reserved. + + diff --git a/OSD.framework/Versions/A/Resources/version.plist b/OSD.framework/Versions/A/Resources/version.plist new file mode 100644 index 0000000..a387863 --- /dev/null +++ b/OSD.framework/Versions/A/Resources/version.plist @@ -0,0 +1,18 @@ + + + + + BuildAliasOf + OSDFramework + BuildVersion + 487 + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + ProjectName + OSDFramework + SourceVersion + 27000000000000 + + diff --git a/OSD.framework/Versions/A/_CodeSignature/CodeResources b/OSD.framework/Versions/A/_CodeSignature/CodeResources new file mode 100644 index 0000000..cd4347d --- /dev/null +++ b/OSD.framework/Versions/A/_CodeSignature/CodeResources @@ -0,0 +1,139 @@ + + + + + files + + Resources/Info.plist + + bTy7OXKIr2tY7ToPw28ekz1xUXU= + + Resources/version.plist + + d0I/dBV8v16urCBanZt9RaZvG1E= + + + files2 + + Resources/Info.plist + + hash2 + + uEmRq0D23jBsIWK+0+UH3bCcn16eQdAwKWglrQbTfQc= + + + Resources/version.plist + + hash2 + + f4xR2tymy1G7xEyxX1+yXJmSgOrrndsypu67avrQ8Ss= + + + + rules + + ^Resources/ + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ + + nested + + weight + 10 + + ^.* + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^Resources/ + + weight + 20 + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^[^/]+$ + + nested + + weight + 10 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/OSD.framework/Versions/Current b/OSD.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/OSD.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/OSD.framework/XPCServices b/OSD.framework/XPCServices new file mode 120000 index 0000000..99c46ea --- /dev/null +++ b/OSD.framework/XPCServices @@ -0,0 +1 @@ +Versions/Current/XPCServices \ No newline at end of file diff --git a/README.md b/README.md index 2371d87..fa9ae5f 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,40 @@ -# MonitorControl.OSX -A menu let to control your monitor (brightness, contrast, volume) +# MonitorControl -![image](https://cloud.githubusercontent.com/assets/376453/18903896/5a8ad950-8510-11e6-85d0-c95170a76fb8.png) +Control your external monitor brightness, contrast or volume directly from a menulet or with keyboard shortcuts : -Compatible with most Dell monitors and LG including 27UD68 +- Brightness: `⇧` + `⌃` + `⌥` + `⌘` + `↑/↓` (Shift + Control + Alt + Command + Up/Down arrows) +- Volume: `⇧` + `⌃` + `⌥` + `⌘` + `←/→` (Shift + Control + Alt + Command + Left/Right arrows) +- Mute: `⇧` + `⌃` + `⌥` + `⌘` + `-` (Shift + Control + Alt + Command + Minus) + +(Ps. The keyboard shortcut only work for the default screen) + +![MonitorControl menulet](./.github/menulet.png) + +## Download + +Go to [Release](./) and download the latest `.dmg` + +## Brightness/Volume default key +You can use [Karabiner Elements](https://github.com/tekezo/Karabiner-Elements/) to use the default mac key (`F1`, `F2` for brightness and `F10`, `F11`, `F12` for volume) with this set of custom rules : [Karabiner rules for MonitorControl](karabiner://karabiner/assets/complex_modifications/import?url=https%3A%2F%2Fraw.githubusercontent.com%2Fthe0neyouseek%2FMonitorControl%2Fmaster%2F.github%2Frules.json) --- -Powered by [@kfix/ddcctl](https://github.com/kfix/ddcctl) +Bonus: Using keyboard shortcuts display the native osd : + +![MonitorControl OSD](./.github/osd.png) + +## TODO + +- [ ] Hande multiple screen for keyboard shortcut (Possibly the choice to have all screen brightness/volume increase/decrease at the same time or separatly) +- [ ] Skip Karabiner use for keyboard shortcut +- [ ] Option to start app at login +- [ ] Add [SwiftLint](https://github.com/realm/SwiftLint) + +## Support +- macOS Sierra (`10.12`) and up. +- Works with monitors comptaible with [@kfix/ddcctl](https://github.com/kfix/ddcctl) + +## Thanks +- @bluejamesbond (Original developer) +- @Tyilo (Fork) +- @Bensge - (Used some code from his project [NativeDisplayBrightness](https://github.com/Bensge/NativeDisplayBrightness)) \ No newline at end of file