diff --git a/.github/menulet.png b/.github/menulet.png new file mode 100644 index 0000000..36ab2c1 Binary files /dev/null and b/.github/menulet.png differ diff --git a/.github/osd.png b/.github/osd.png new file mode 100644 index 0000000..584ad26 Binary files /dev/null and b/.github/osd.png differ diff --git a/License.txt b/License.txt new file mode 100644 index 0000000..f9e5824 --- /dev/null +++ b/License.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright © 2017 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/MonitorControl.OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/MonitorControl.OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index ac9a2f9..0000000 --- a/MonitorControl.OSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - 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 0000000..44e7552 Binary files /dev/null and b/MonitorControl/Assets.xcassets/status.imageset/status.png differ diff --git a/MonitorControl/Assets.xcassets/status.imageset/status@2x.png b/MonitorControl/Assets.xcassets/status.imageset/status@2x.png new file mode 100644 index 0000000..cd07318 Binary files /dev/null and b/MonitorControl/Assets.xcassets/status.imageset/status@2x.png differ diff --git a/MonitorControl.OSX/Base.lproj/MainMenu.xib b/MonitorControl/Base.lproj/MainMenu.xib similarity index 83% rename from MonitorControl.OSX/Base.lproj/MainMenu.xib rename to MonitorControl/Base.lproj/MainMenu.xib index 4aaf92c..d55f9e9 100644 --- a/MonitorControl.OSX/Base.lproj/MainMenu.xib +++ b/MonitorControl/Base.lproj/MainMenu.xib @@ -1,8 +1,8 @@ - - + + - + @@ -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 0000000..02e8298 Binary files /dev/null and b/MonitorControl/en.lproj/Localizable.strings differ 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 0000000..61c7556 Binary files /dev/null and b/MonitorControl/fr.lproj/Localizable.strings differ 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 0000000..58813ae Binary files /dev/null and b/OSD.framework/Versions/A/OSD differ diff --git a/OSD.framework/Versions/A/Resources/Info.plist b/OSD.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..824b8c0 --- /dev/null +++ b/OSD.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,46 @@ + + + + + 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