Add Apple Silicon support & major revamp (3.0.0) (#520)

Co-authored-by: Joni Van Roost <joni.VR@hotmail.com>
Co-authored-by: Rayan Khan <rayankhan04@iCloud.com>
Co-authored-by: Guillaume B <the0neyouseek@users.noreply.github.com>
This commit is contained in:
waydabber 2021-08-21 13:18:54 +02:00 committed by GitHub
parent fd142cb7e0
commit d46c429c07
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
91 changed files with 3994 additions and 2653 deletions

View file

@ -1,5 +1,5 @@
[update]
tasks = ["interfaces", "code", "transform", "normalize"]
tasks = ["interfaces", "code", "normalize"]
[update.interfaces]
paths = ["."]

BIN
.github/Icon-1024.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 KiB

BIN
.github/MonitorControl Icon.fig vendored Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 KiB

BIN
.github/menukeys.png vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

BIN
.github/menulet.png vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

BIN
.github/osd.jpg vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

BIN
.github/screenshot.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

View file

@ -13,35 +13,33 @@
28D1DDF3227FC8C6004CB494 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 56754EB01D9A4016007BCDC5 /* Assets.xcassets */; };
56754EAF1D9A4016007BCDC5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56754EAE1D9A4016007BCDC5 /* AppDelegate.swift */; };
56754EB11D9A4016007BCDC5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 56754EB01D9A4016007BCDC5 /* Assets.xcassets */; };
6C0CCB26228F4F720037D2C5 /* AdvancedPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C0CCB25228F4F720037D2C5 /* AdvancedPrefsViewController.swift */; };
6C20466C23153E4F00859767 /* Display+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C20466B23153E4F00859767 /* Display+Extension.swift */; };
6C2EA1CD228F644B00060E3F /* OnlyIntegerValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2EA1CC228F644B00060E3F /* OnlyIntegerValueFormatter.swift */; };
6C2EA1CF228F7DFB00060E3F /* PollingMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C2EA1CE228F7DFB00060E3F /* PollingMode.swift */; };
6C85EFDA22C941B000227EA1 /* DisplayManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C85EFD922C941B000227EA1 /* DisplayManager.swift */; };
6C85EFDD22CBAA8F00227EA1 /* PollingModeCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C85EFDC22CBAA8F00227EA1 /* PollingModeCellView.swift */; };
6C85EFDF22CBB54100227EA1 /* PollingCountCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C85EFDE22CBB54100227EA1 /* PollingCountCellView.swift */; };
6C85EFE122CC00AD00227EA1 /* NSNotification+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C85EFE022CC00AD00227EA1 /* NSNotification+Extension.swift */; };
6CB2B64B263EDA6600F0E0EF /* OSD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F0A987D61F77B290009B603D /* OSD.framework */; };
6CBFE27A23DB266000D1BC41 /* Display.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CBFE27923DB266000D1BC41 /* Display.swift */; };
6CBFE27C23DB27A200D1BC41 /* InternalDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CBFE27B23DB27A200D1BC41 /* InternalDisplay.swift */; };
6CC260F6256AD8F900613714 /* Preferences+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CC260F5256AD8F900613714 /* Preferences+Extension.swift */; };
6CCB278622D5315200619B05 /* HideOsdCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CCB278522D5315200619B05 /* HideOsdCellView.swift */; };
6CD35F53264FFFC6001F1344 /* SimplyCoreAudio in Frameworks */ = {isa = PBXBuildFile; productRef = 6CD35F52264FFFC6001F1344 /* SimplyCoreAudio */; };
6CD35F5626500008001F1344 /* MediaKeyTap in Frameworks */ = {isa = PBXBuildFile; productRef = 6CD35F5526500008001F1344 /* MediaKeyTap */; };
6CD35F592650002E001F1344 /* DDC in Frameworks */ = {isa = PBXBuildFile; productRef = 6CD35F582650002E001F1344 /* DDC */; };
6CD35F5C2650003F001F1344 /* Preferences in Frameworks */ = {isa = PBXBuildFile; productRef = 6CD35F5B2650003F001F1344 /* Preferences */; };
6CD444C322D4FBB8005BFD3D /* LongerDelayCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CD444C222D4FBB8005BFD3D /* LongerDelayCellView.swift */; };
6CDA0FCF26485A8300F52125 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6CDA0FCD26485A8300F52125 /* Main.storyboard */; };
AA062E8A26C9A039007E628C /* DisplaysPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA062E8926C9A039007E628C /* DisplaysPrefsViewController.swift */; };
AA062E8E26CA7BE5007E628C /* DisplaysPrefsCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA062E8D26CA7BE5007E628C /* DisplaysPrefsCellView.swift */; };
AA16139B26BE772E00DCF027 /* Arm64DDCUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA16139A26BE772E00DCF027 /* Arm64DDCUtils.swift */; };
AA3B4A2826AE103C00B74CD2 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = AA3B4A2726AE103C00B74CD2 /* README.md */; };
AA665A5D26C5892800FEF2C1 /* AboutPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA665A5C26C5892800FEF2C1 /* AboutPrefsViewController.swift */; };
AA9AE86F26B5BF3D00B6CA65 /* OSD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA9AE86E26B5BF3D00B6CA65 /* OSD.framework */; };
AA9AE87126B5BFB700B6CA65 /* CoreDisplay.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA9AE87026B5BFB700B6CA65 /* CoreDisplay.framework */; };
AADB625A26BC196900DFFAA5 /* DisplayServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AADB625926BC196900DFFAA5 /* DisplayServices.framework */; };
F01B0699228221B7008E64DB /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F01B0680228221B6008E64DB /* Localizable.strings */; };
F01B069A228221B7008E64DB /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = F01B0683228221B6008E64DB /* Utils.swift */; };
F01B069E228221B7008E64DB /* ButtonCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F01B068E228221B6008E64DB /* ButtonCellView.swift */; };
F01B069F228221B7008E64DB /* SliderHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F01B068F228221B7008E64DB /* SliderHandler.swift */; };
F01B06A1228221B7008E64DB /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = F01B0692228221B7008E64DB /* MainMenu.xib */; };
F03A8DF21FFBAA6F0034DC27 /* ExternalDisplay.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03A8DF11FFBAA6F0034DC27 /* ExternalDisplay.swift */; };
F03FE4C0228DF62B001F59A4 /* FriendlyNameCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F03FE4BF228DF62A001F59A4 /* FriendlyNameCellView.swift */; };
F0445D3820023E710025AE82 /* MainPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0445D3720023E710025AE82 /* MainPrefsViewController.swift */; };
F0445D3D200254FA0025AE82 /* KeysPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0445D3B200254FA0025AE82 /* KeysPrefsViewController.swift */; };
F0445D40200259C10025AE82 /* DisplayPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0445D3F200259C10025AE82 /* DisplayPrefsViewController.swift */; };
F06792EA200A73460066C438 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = F06792E9200A73460066C438 /* main.swift */; };
F06792F6200A745F0066C438 /* MonitorControlHelper.app in [Login] Copy Helper to start at Login */ = {isa = PBXBuildFile; fileRef = F06792E7200A73460066C438 /* MonitorControlHelper.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
FE4E0896249D584C003A50BB /* OSDUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE4E0895249D584C003A50BB /* OSDUtils.swift */; };
@ -65,16 +63,8 @@
1E7ECF3F22A4552400E4E701 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
1E7ECF4122A4553000E4E701 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/MainMenu.strings; sourceTree = "<group>"; };
2894D9B72280B30500DF58DA /* CGDirectDisplayID+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGDirectDisplayID+Extension.swift"; sourceTree = "<group>"; };
28D1DDE2227FB7D0004CB494 /* MediaKeyTap.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaKeyTap.framework; path = Carthage/Build/Mac/MediaKeyTap.framework; sourceTree = "<group>"; };
28D1DDE3227FB7D0004CB494 /* AMCoreAudio.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AMCoreAudio.framework; path = Carthage/Build/Mac/AMCoreAudio.framework; sourceTree = "<group>"; };
28D1DDE4227FB7D0004CB494 /* MASPreferences.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MASPreferences.framework; path = Carthage/Build/Mac/MASPreferences.framework; sourceTree = "<group>"; };
28D1DDEC227FB8F2004CB494 /* EDID+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EDID+Extension.swift"; sourceTree = "<group>"; };
28D1DDED227FB944004CB494 /* DDC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DDC.framework; path = Carthage/Build/Mac/DDC.framework; sourceTree = "<group>"; };
28D1DDF1227FBE71004CB494 /* NSScreen+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSScreen+Extension.swift"; sourceTree = "<group>"; };
28D1DE0E227FD005004CB494 /* MASPreferences.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = MASPreferences.framework.dSYM; path = Carthage/Build/Mac/MASPreferences.framework.dSYM; sourceTree = "<group>"; };
28D1DE0F227FD006004CB494 /* MediaKeyTap.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = MediaKeyTap.framework.dSYM; path = Carthage/Build/Mac/MediaKeyTap.framework.dSYM; sourceTree = "<group>"; };
28D1DE10227FD006004CB494 /* AMCoreAudio.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = AMCoreAudio.framework.dSYM; path = Carthage/Build/Mac/AMCoreAudio.framework.dSYM; sourceTree = "<group>"; };
28D1DE11227FD006004CB494 /* DDC.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = DDC.framework.dSYM; path = Carthage/Build/Mac/DDC.framework.dSYM; sourceTree = "<group>"; };
2EAA5B7E24BF9E9A00937821 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/MainMenu.strings; sourceTree = "<group>"; };
2EAA5B7F24BF9E9A00937821 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
3CCA5F962442EFF800B4DB84 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/MainMenu.strings; sourceTree = "<group>"; };
@ -84,23 +74,16 @@
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 = "<group>"; };
56754EB01D9A4016007BCDC5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
6C0CCB25228F4F720037D2C5 /* AdvancedPrefsViewController.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = AdvancedPrefsViewController.swift; sourceTree = "<group>"; tabWidth = 4; };
6C20466B23153E4F00859767 /* Display+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Display+Extension.swift"; sourceTree = "<group>"; };
6C2EA1CC228F644B00060E3F /* OnlyIntegerValueFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnlyIntegerValueFormatter.swift; sourceTree = "<group>"; };
6C2EA1CE228F7DFB00060E3F /* PollingMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollingMode.swift; sourceTree = "<group>"; };
6C85EFD922C941B000227EA1 /* DisplayManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisplayManager.swift; sourceTree = "<group>"; };
6C85EFDC22CBAA8F00227EA1 /* PollingModeCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollingModeCellView.swift; sourceTree = "<group>"; };
6C85EFDE22CBB54100227EA1 /* PollingCountCellView.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = PollingCountCellView.swift; sourceTree = "<group>"; tabWidth = 4; };
6C85EFE022CC00AD00227EA1 /* NSNotification+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSNotification+Extension.swift"; sourceTree = "<group>"; };
6CAD134F23624CC1009BD53F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/MainMenu.strings; sourceTree = "<group>"; };
6CAD135023624CC1009BD53F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
6CBFE27923DB266000D1BC41 /* Display.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Display.swift; sourceTree = "<group>"; };
6CBFE27B23DB27A200D1BC41 /* InternalDisplay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternalDisplay.swift; sourceTree = "<group>"; };
6CC260F5256AD8F900613714 /* Preferences+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Preferences+Extension.swift"; sourceTree = "<group>"; };
6CC260F9256ADA7400613714 /* Preferences.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Preferences.framework; path = Carthage/Build/Mac/Preferences.framework; sourceTree = "<group>"; };
6CCB278522D5315200619B05 /* HideOsdCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HideOsdCellView.swift; sourceTree = "<group>"; };
6CD444C222D4FBB8005BFD3D /* LongerDelayCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LongerDelayCellView.swift; sourceTree = "<group>"; };
6CDA0FCB26485A7600F52125 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = MonitorControl/UI/Base.lproj/Main.storyboard; sourceTree = SOURCE_ROOT; };
6CDA0FCE26485A8300F52125 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
6CDA0FD026485AA100F52125 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Main.strings; sourceTree = "<group>"; };
6CDA0FD126485AA300F52125 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Main.strings"; sourceTree = "<group>"; };
@ -111,6 +94,17 @@
6CDA0FD626485AAC00F52125 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Main.strings; sourceTree = "<group>"; };
6CDA0FD726485AAC00F52125 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Main.strings; sourceTree = "<group>"; };
6CDA0FD826485AAE00F52125 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Main.strings; sourceTree = "<group>"; };
AA062E8926C9A039007E628C /* DisplaysPrefsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplaysPrefsViewController.swift; sourceTree = "<group>"; };
AA062E8D26CA7BE5007E628C /* DisplaysPrefsCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplaysPrefsCellView.swift; sourceTree = "<group>"; };
AA16139A26BE772E00DCF027 /* Arm64DDCUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arm64DDCUtils.swift; sourceTree = "<group>"; };
AA3B4A2726AE103C00B74CD2 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
AA665A5C26C5892800FEF2C1 /* AboutPrefsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutPrefsViewController.swift; sourceTree = "<group>"; };
AA6686F026B8172E00AF74A2 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Main.strings; sourceTree = "<group>"; };
AA6686F126B8172E00AF74A2 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/MainMenu.strings; sourceTree = "<group>"; };
AA6686F226B8172E00AF74A2 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = "<group>"; };
AA9AE86E26B5BF3D00B6CA65 /* OSD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OSD.framework; path = ../../../../../System/Library/PrivateFrameworks/OSD.framework; sourceTree = "<group>"; };
AA9AE87026B5BFB700B6CA65 /* CoreDisplay.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreDisplay.framework; path = ../../../../../System/Library/Frameworks/CoreDisplay.framework; sourceTree = "<group>"; };
AADB625926BC196900DFFAA5 /* DisplayServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DisplayServices.framework; path = ../../../../../System/Library/PrivateFrameworks/DisplayServices.framework; sourceTree = "<group>"; };
B0C4810623357CE500053F91 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
B0C4810823357CE500053F91 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/MainMenu.strings; sourceTree = "<group>"; };
F01B0681228221B6008E64DB /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
@ -119,22 +113,17 @@
F01B0684228221B6008E64DB /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
F01B0685228221B6008E64DB /* Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = "<group>"; };
F01B0686228221B6008E64DB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
F01B068E228221B6008E64DB /* ButtonCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonCellView.swift; sourceTree = "<group>"; };
F01B068F228221B7008E64DB /* SliderHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SliderHandler.swift; sourceTree = "<group>"; };
F01B0693228221B7008E64DB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
F01B06A222822208008E64DB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/MainMenu.strings; sourceTree = "<group>"; };
F01B06A32282220A008E64DB /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/MainMenu.strings; sourceTree = "<group>"; };
F01B06A42282220D008E64DB /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/MainMenu.strings; sourceTree = "<group>"; };
F03A8DF11FFBAA6F0034DC27 /* ExternalDisplay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalDisplay.swift; sourceTree = "<group>"; };
F03FE4BF228DF62A001F59A4 /* FriendlyNameCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FriendlyNameCellView.swift; sourceTree = "<group>"; };
F0445D3720023E710025AE82 /* MainPrefsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainPrefsViewController.swift; sourceTree = "<group>"; };
F0445D3B200254FA0025AE82 /* KeysPrefsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeysPrefsViewController.swift; sourceTree = "<group>"; };
F0445D3F200259C10025AE82 /* DisplayPrefsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayPrefsViewController.swift; sourceTree = "<group>"; };
F06792E7200A73460066C438 /* MonitorControlHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MonitorControlHelper.app; sourceTree = BUILT_PRODUCTS_DIR; };
F06792E9200A73460066C438 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
F06792F0200A73470066C438 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
F06792F1200A73470066C438 /* MonitorControlHelper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MonitorControlHelper.entitlements; sourceTree = "<group>"; };
F0A987D61F77B290009B603D /* OSD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OSD.framework; sourceTree = "<group>"; };
FE4E0895249D584C003A50BB /* OSDUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OSDUtils.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -143,11 +132,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
AA9AE87126B5BFB700B6CA65 /* CoreDisplay.framework in Frameworks */,
6CD35F53264FFFC6001F1344 /* SimplyCoreAudio in Frameworks */,
6CD35F5626500008001F1344 /* MediaKeyTap in Frameworks */,
6CB2B64B263EDA6600F0E0EF /* OSD.framework in Frameworks */,
6CD35F592650002E001F1344 /* DDC in Frameworks */,
AA9AE86F26B5BF3D00B6CA65 /* OSD.framework in Frameworks */,
6CD35F5C2650003F001F1344 /* Preferences in Frameworks */,
AADB625A26BC196900DFFAA5 /* DisplayServices.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -164,16 +155,9 @@
28D1DDD1227FB759004CB494 /* Frameworks */ = {
isa = PBXGroup;
children = (
6CC260F9256ADA7400613714 /* Preferences.framework */,
28D1DDE3227FB7D0004CB494 /* AMCoreAudio.framework */,
28D1DE10227FD006004CB494 /* AMCoreAudio.framework.dSYM */,
28D1DDED227FB944004CB494 /* DDC.framework */,
28D1DE11227FD006004CB494 /* DDC.framework.dSYM */,
28D1DDE4227FB7D0004CB494 /* MASPreferences.framework */,
28D1DE0E227FD005004CB494 /* MASPreferences.framework.dSYM */,
28D1DDE2227FB7D0004CB494 /* MediaKeyTap.framework */,
28D1DE0F227FD006004CB494 /* MediaKeyTap.framework.dSYM */,
F0A987D61F77B290009B603D /* OSD.framework */,
AA9AE86E26B5BF3D00B6CA65 /* OSD.framework */,
AA9AE87026B5BFB700B6CA65 /* CoreDisplay.framework */,
AADB625926BC196900DFFAA5 /* DisplayServices.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -194,6 +178,7 @@
56754EA21D9A4016007BCDC5 = {
isa = PBXGroup;
children = (
AA3B4A2726AE103C00B74CD2 /* README.md */,
28D1DDD1227FB759004CB494 /* Frameworks */,
56754EAD1D9A4016007BCDC5 /* MonitorControl */,
F06792E8200A73460066C438 /* MonitorControlHelper */,
@ -245,20 +230,6 @@
path = Manager;
sourceTree = "<group>";
};
6C85EFDB22CBA77600227EA1 /* Cells */ = {
isa = PBXGroup;
children = (
6CDA0FCA26485A7600F52125 /* Main.storyboard */,
F03FE4BF228DF62A001F59A4 /* FriendlyNameCellView.swift */,
F01B068E228221B6008E64DB /* ButtonCellView.swift */,
6C85EFDC22CBAA8F00227EA1 /* PollingModeCellView.swift */,
6C85EFDE22CBB54100227EA1 /* PollingCountCellView.swift */,
6CD444C222D4FBB8005BFD3D /* LongerDelayCellView.swift */,
6CCB278522D5315200619B05 /* HideOsdCellView.swift */,
);
path = Cells;
sourceTree = "<group>";
};
F01B067F228221B6008E64DB /* Support */ = {
isa = PBXGroup;
children = (
@ -268,6 +239,7 @@
6C2EA1CC228F644B00060E3F /* OnlyIntegerValueFormatter.swift */,
6C2EA1CE228F7DFB00060E3F /* PollingMode.swift */,
FE4E0895249D584C003A50BB /* OSDUtils.swift */,
AA16139A26BE772E00DCF027 /* Arm64DDCUtils.swift */,
);
path = Support;
sourceTree = "<group>";
@ -275,7 +247,6 @@
F01B0687228221B6008E64DB /* UI */ = {
isa = PBXGroup;
children = (
6C85EFDB22CBA77600227EA1 /* Cells */,
6CDA0FCD26485A8300F52125 /* Main.storyboard */,
F01B0692228221B7008E64DB /* MainMenu.xib */,
F01B068F228221B7008E64DB /* SliderHandler.swift */,
@ -286,10 +257,10 @@
F0445D3620023D5B0025AE82 /* View Controllers */ = {
isa = PBXGroup;
children = (
F0445D3F200259C10025AE82 /* DisplayPrefsViewController.swift */,
F0445D3B200254FA0025AE82 /* KeysPrefsViewController.swift */,
F0445D3720023E710025AE82 /* MainPrefsViewController.swift */,
6C0CCB25228F4F720037D2C5 /* AdvancedPrefsViewController.swift */,
AA665A5C26C5892800FEF2C1 /* AboutPrefsViewController.swift */,
AA062E8926C9A039007E628C /* DisplaysPrefsViewController.swift */,
AA062E8D26CA7BE5007E628C /* DisplaysPrefsCellView.swift */,
);
path = "View Controllers";
sourceTree = "<group>";
@ -390,6 +361,7 @@
it,
ja,
pl,
hu,
);
mainGroup = 56754EA21D9A4016007BCDC5;
packageReferences = (
@ -415,6 +387,7 @@
files = (
56754EB11D9A4016007BCDC5 /* Assets.xcassets in Resources */,
6CDA0FCF26485A8300F52125 /* Main.storyboard in Resources */,
AA3B4A2826AE103C00B74CD2 /* README.md in Resources */,
F01B0699228221B7008E64DB /* Localizable.strings in Resources */,
F01B06A1228221B7008E64DB /* MainMenu.xib in Resources */,
);
@ -526,25 +499,20 @@
files = (
56754EAF1D9A4016007BCDC5 /* AppDelegate.swift in Sources */,
6C85EFE122CC00AD00227EA1 /* NSNotification+Extension.swift in Sources */,
6C85EFDF22CBB54100227EA1 /* PollingCountCellView.swift in Sources */,
6C0CCB26228F4F720037D2C5 /* AdvancedPrefsViewController.swift in Sources */,
F01B069E228221B7008E64DB /* ButtonCellView.swift in Sources */,
AA062E8A26C9A039007E628C /* DisplaysPrefsViewController.swift in Sources */,
6C2EA1CD228F644B00060E3F /* OnlyIntegerValueFormatter.swift in Sources */,
2894D9B82280B30500DF58DA /* CGDirectDisplayID+Extension.swift in Sources */,
6CCB278622D5315200619B05 /* HideOsdCellView.swift in Sources */,
6CC260F6256AD8F900613714 /* Preferences+Extension.swift in Sources */,
6CD444C322D4FBB8005BFD3D /* LongerDelayCellView.swift in Sources */,
F03FE4C0228DF62B001F59A4 /* FriendlyNameCellView.swift in Sources */,
AA665A5D26C5892800FEF2C1 /* AboutPrefsViewController.swift in Sources */,
6C2EA1CF228F7DFB00060E3F /* PollingMode.swift in Sources */,
6CBFE27C23DB27A200D1BC41 /* InternalDisplay.swift in Sources */,
AA062E8E26CA7BE5007E628C /* DisplaysPrefsCellView.swift in Sources */,
FE4E0896249D584C003A50BB /* OSDUtils.swift in Sources */,
6CBFE27A23DB266000D1BC41 /* Display.swift in Sources */,
F03A8DF21FFBAA6F0034DC27 /* ExternalDisplay.swift in Sources */,
F0445D40200259C10025AE82 /* DisplayPrefsViewController.swift in Sources */,
28D1DDF0227FBD99004CB494 /* EDID+Extension.swift in Sources */,
6C85EFDD22CBAA8F00227EA1 /* PollingModeCellView.swift in Sources */,
F0445D3D200254FA0025AE82 /* KeysPrefsViewController.swift in Sources */,
6C20466C23153E4F00859767 /* Display+Extension.swift in Sources */,
AA16139B26BE772E00DCF027 /* Arm64DDCUtils.swift in Sources */,
F0445D3820023E710025AE82 /* MainPrefsViewController.swift in Sources */,
28D1DDF2227FBE71004CB494 /* NSScreen+Extension.swift in Sources */,
F01B069F228221B7008E64DB /* SliderHandler.swift in Sources */,
@ -564,14 +532,6 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
6CDA0FCA26485A7600F52125 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
6CDA0FCB26485A7600F52125 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
6CDA0FCD26485A8300F52125 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
@ -585,6 +545,7 @@
6CDA0FD626485AAC00F52125 /* pl */,
6CDA0FD726485AAC00F52125 /* ru */,
6CDA0FD826485AAE00F52125 /* uk */,
AA6686F026B8172E00AF74A2 /* hu */,
);
name = Main.storyboard;
sourceTree = "<group>";
@ -601,6 +562,7 @@
6CAD135023624CC1009BD53F /* it */,
3CCA5F972442EFF800B4DB84 /* ja */,
2EAA5B7F24BF9E9A00937821 /* pl */,
AA6686F226B8172E00AF74A2 /* hu */,
);
name = Localizable.strings;
sourceTree = "<group>";
@ -618,6 +580,7 @@
6CAD134F23624CC1009BD53F /* it */,
3CCA5F962442EFF800B4DB84 /* ja */,
2EAA5B7E24BF9E9A00937821 /* pl */,
AA6686F126B8172E00AF74A2 /* hu */,
);
name = MainMenu.xib;
sourceTree = "<group>";
@ -747,20 +710,29 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 631;
CURRENT_PROJECT_VERSION = 1179;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(PROJECT_DIR)/**",
"/System/Library/PrivateFrameworks/**",
);
INFOPLIST_FILE = MonitorControl/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 2.2.0;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MARKETING_VERSION = 3.0.0;
PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControl;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "MonitorControl/Support/Bridging-Header.h";
SWIFT_VERSION = 5.0;
SYSTEM_FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
);
};
name = Debug;
};
@ -769,23 +741,32 @@
buildSettings = {
ARCHS = x86_64;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 631;
DEVELOPMENT_TEAM = CYC8C8R4K9;
CURRENT_PROJECT_VERSION = 1179;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(PROJECT_DIR)/**",
"/System/Library/PrivateFrameworks/**",
);
INFOPLIST_FILE = MonitorControl/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 2.2.0;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MARKETING_VERSION = 3.0.0;
PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControl;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "MonitorControl/Support/Bridging-Header.h";
SWIFT_VERSION = 5.0;
SYSTEM_FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
);
};
name = Release;
};
@ -809,7 +790,8 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 2.1.0;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MARKETING_VERSION = 3.0.0;
PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControlHelper;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@ -825,11 +807,11 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = MonitorControlHelper/MonitorControlHelper.entitlements;
CODE_SIGN_IDENTITY = "Mac Developer";
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 631;
DEVELOPMENT_TEAM = CYC8C8R4K9;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = MonitorControlHelper/Info.plist;
@ -837,7 +819,8 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 2.1.0;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MARKETING_VERSION = 3.0.0;
PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControlHelper;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;

View file

@ -1,5 +1,4 @@
import Cocoa
import DDC
import Foundation
import MediaKeyTap
import os.log
@ -12,30 +11,27 @@ let prefs = UserDefaults.standard
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet var statusMenu: NSMenu!
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
var monitorItems: [NSMenuItem] = []
var mediaKeyTap: MediaKeyTap?
var keyRepeatTimers: [MediaKey: Timer] = [:]
let coreAudio = SimplyCoreAudio()
var accessibilityObserver: NSObjectProtocol!
var reconfigureID: Int = 0 // dispatched reconfigure command ID
var sleepID: Int = 0 // Don't reconfigure display as the system or display is sleeping or wake just recently.
let debugSw: Bool = false
lazy var preferencesWindowController: PreferencesWindowController = {
let storyboard = NSStoryboard(name: "Main", bundle: Bundle.main)
let mainPrefsVc = storyboard.instantiateController(withIdentifier: "MainPrefsVC") as? MainPrefsViewController
let keyPrefsVc = storyboard.instantiateController(withIdentifier: "KeysPrefsVC") as? KeysPrefsViewController
let displayPrefsVc = storyboard.instantiateController(withIdentifier: "DisplayPrefsVC") as? DisplayPrefsViewController
let advancedPrefsVc = storyboard.instantiateController(withIdentifier: "AdvancedPrefsVC") as? AdvancedPrefsViewController
let displaysPrefsVc = storyboard.instantiateController(withIdentifier: "DisplaysPrefsVC") as? DisplaysPrefsViewController
let aboutPrefsVc = storyboard.instantiateController(withIdentifier: "AboutPrefsVC") as? AboutPrefsViewController
return PreferencesWindowController(
preferencePanes: [
mainPrefsVc!,
keyPrefsVc!,
displayPrefsVc!,
advancedPrefsVc!,
displaysPrefsVc!,
aboutPrefsVc!,
],
animated: false // causes glitchy animations
animated: true
)
}()
@ -43,12 +39,27 @@ class AppDelegate: NSObject, NSApplicationDelegate {
app = self
self.subscribeEventListeners()
self.setDefaultPrefs()
self.updateMediaKeyTap()
self.statusItem.image = NSImage(named: "status")
if #available(macOS 11.0, *) {
self.statusItem.button?.image = NSImage(systemSymbolName: "sun.max", accessibilityDescription: "MonitorControl")
} else {
self.statusItem.button?.image = NSImage(named: "status")
}
self.statusItem.isVisible = prefs.bool(forKey: Utils.PrefKeys.hideMenuIcon.rawValue) ? false : true
self.statusItem.menu = self.statusMenu
self.checkPermissions()
CGDisplayRegisterReconfigurationCallback({ _, _, _ in app.updateDisplays() }, nil)
self.updateDisplays()
CGDisplayRegisterReconfigurationCallback({ _, _, _ in app.displayReconfigured() }, nil)
self.updateDisplays(firstrun: true)
}
func applicationShouldHandleReopen(_: NSApplication, hasVisibleWindows _: Bool) -> Bool {
self.prefsClicked(self)
return true
}
func applicationWillTerminate(_: Notification) {
os_log("Goodbye!", type: .info)
DisplayManager.shared.resetSwBrightnessForAllDisplays()
self.statusItem.isVisible = true
}
@IBAction func quitClicked(_: AnyObject) {
@ -59,19 +70,19 @@ class AppDelegate: NSObject, NSApplicationDelegate {
self.preferencesWindowController.show()
}
/// Set the default prefs of the app
func setDefaultPrefs() {
if !prefs.bool(forKey: Utils.PrefKeys.appAlreadyLaunched.rawValue) {
prefs.set(true, forKey: Utils.PrefKeys.appAlreadyLaunched.rawValue)
prefs.set(false, forKey: Utils.PrefKeys.showContrast.rawValue)
prefs.set(false, forKey: Utils.PrefKeys.lowerContrast.rawValue)
prefs.set(true, forKey: Utils.PrefKeys.showVolume.rawValue)
prefs.set(false, forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue)
prefs.set(true, forKey: Utils.PrefKeys.fallbackSw.rawValue)
prefs.set(false, forKey: Utils.PrefKeys.hideMenuIcon.rawValue)
prefs.set(false, forKey: Utils.PrefKeys.showAdvancedDisplays.rawValue)
}
}
// MARK: - Menu
func clearDisplays() {
func clearMenu() {
if self.statusMenu.items.count > 2 {
var items: [NSMenuItem] = []
for i in 0 ..< self.statusMenu.items.count - 2 {
@ -82,35 +93,50 @@ class AppDelegate: NSObject, NSApplicationDelegate {
self.statusMenu.removeItem(item)
}
}
self.monitorItems = []
DisplayManager.shared.clearDisplays()
}
func updateDisplays() {
self.clearDisplays()
for screen in NSScreen.screens {
let name: String
if #available(OSX 10.15, *) {
name = screen.localizedName
} else {
name = screen.displayName ?? NSLocalizedString("Unknown", comment: "Unknown display name")
func updateArm64AVServices() {
if Arm64DDCUtils.isArm64 {
os_log("arm64 AVService update requested", type: .info)
var displayIDs: [CGDirectDisplayID] = []
for externalDisplay in DisplayManager.shared.getExternalDisplays() {
displayIDs.append(externalDisplay.identifier)
}
let id = screen.displayID
let vendorNumber = screen.vendorNumber
let modelNumber = screen.modelNumber
let display: Display
if screen.isBuiltin {
display = InternalDisplay(id, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber)
} else {
display = ExternalDisplay(id, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber)
for serviceMatch in Arm64DDCUtils.getServiceMatches(displayIDs: displayIDs) {
for externalDisplay in DisplayManager.shared.getExternalDisplays() where externalDisplay.identifier == serviceMatch.displayID && serviceMatch.service != nil {
externalDisplay.arm64avService = serviceMatch.service
os_log("Display service match successful for display %{public}@", type: .info, String(serviceMatch.displayID))
if !serviceMatch.isDiscouraged {
externalDisplay.arm64ddc = !debugSw ? true : false // MARK: (point of interest when testing)
}
}
}
DisplayManager.shared.addDisplay(display: display)
os_log("AVService update done", type: .info)
}
}
let ddcDisplays = DisplayManager.shared.getDdcCapableDisplays()
if ddcDisplays.count == 0 {
func displayReconfigured() {
self.reconfigureID += 1
os_log("Bumping reconfigureID to %{public}@", type: .info, String(self.reconfigureID))
if self.sleepID == 0 {
let dispatchedReconfigureID = self.reconfigureID
os_log("Display to be reconfigured with reconfigureID %{public}@", type: .info, String(dispatchedReconfigureID))
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.updateDisplays(dispatchedReconfigureID: dispatchedReconfigureID)
}
}
}
func updateMenus() {
self.clearMenu()
var controllableExternalDisplays: [ExternalDisplay] = []
if prefs.bool(forKey: Utils.PrefKeys.fallbackSw.rawValue) {
controllableExternalDisplays = DisplayManager.shared.getNonVirtualExternalDisplays()
} else {
controllableExternalDisplays = DisplayManager.shared.getDdcCapableDisplays()
}
if controllableExternalDisplays.count == 0 {
let item = NSMenuItem()
item.title = NSLocalizedString("No supported display found", comment: "Shown in menu")
item.isEnabled = false
@ -118,41 +144,97 @@ class AppDelegate: NSObject, NSApplicationDelegate {
self.statusMenu.insertItem(item, at: 0)
self.statusMenu.insertItem(NSMenuItem.separator(), at: 1)
} else {
for display in ddcDisplays {
for display in controllableExternalDisplays {
os_log("Supported display found: %{public}@", type: .info, "\(display.name) (Vendor: \(display.vendorNumber ?? 0), Model: \(display.modelNumber ?? 0))")
self.addDisplayToMenu(display: display, asSubMenu: ddcDisplays.count > 1)
let asSubmenu: Bool = controllableExternalDisplays.count > 2 ? true : false
if asSubmenu {
self.statusMenu.insertItem(NSMenuItem.separator(), at: 0)
}
self.addDisplayToMenu(display: display, asSubMenu: asSubmenu)
}
}
}
func updateDisplays(dispatchedReconfigureID: Int = 0, firstrun: Bool = false) {
guard self.sleepID == 0, dispatchedReconfigureID == self.reconfigureID else {
return
}
os_log("Request for updateDisplay with reconfigreID %{public}@", type: .info, String(dispatchedReconfigureID))
self.reconfigureID = 0
DisplayManager.shared.clearDisplays()
var onlineDisplayIDs = [CGDirectDisplayID](repeating: 0, count: 16)
var displayCount: UInt32 = 0
guard CGGetOnlineDisplayList(10, &onlineDisplayIDs, &displayCount) == .success else {
os_log("Unable to get display list.", type: .info)
return
}
for onlineDisplayID in onlineDisplayIDs where onlineDisplayID != 0 {
let name = DisplayManager.shared.getDisplayNameByID(displayID: onlineDisplayID)
let id = onlineDisplayID
let vendorNumber = CGDisplayVendorNumber(onlineDisplayID)
let modelNumber = CGDisplayVendorNumber(onlineDisplayID)
let display: Display
var isVirtual: Bool = false
if #available(macOS 11.0, *) {
if let dictionary = ((CoreDisplay_DisplayCreateInfoDictionary(onlineDisplayID))?.takeRetainedValue() as NSDictionary?) {
let isVirtualDevice = dictionary["kCGDisplayIsVirtualDevice"] as? Bool
let displayIsAirplay = dictionary["kCGDisplayIsAirPlay"] as? Bool
if isVirtualDevice ?? displayIsAirplay ?? false {
isVirtual = true
}
}
}
if !debugSw, CGDisplayIsBuiltin(onlineDisplayID) != 0 { // MARK: (point of interest for testing)
display = InternalDisplay(id, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual)
} else {
display = ExternalDisplay(id, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual)
}
DisplayManager.shared.addDisplay(display: display)
}
self.updateArm64AVServices()
if firstrun {
DisplayManager.shared.resetSwBrightnessForAllDisplays(settingsOnly: true)
}
NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.displayListUpdate.rawValue), object: nil)
self.updateMenus()
if !firstrun {
if prefs.bool(forKey: Utils.PrefKeys.fallbackSw.rawValue) || prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) {
DisplayManager.shared.restoreSwBrightnessForAllDisplays(async: true)
}
}
updateMediaKeyTap()
}
private func addDisplayToMenu(display: ExternalDisplay, asSubMenu: Bool) {
if !asSubMenu {
self.statusMenu.insertItem(NSMenuItem.separator(), at: 0)
}
let monitorSubMenu: NSMenu = asSubMenu ? NSMenu() : self.statusMenu
self.statusMenu.insertItem(NSMenuItem.separator(), at: 0)
let volumeSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu,
forDisplay: display,
command: .audioSpeakerVolume,
title: NSLocalizedString("Volume", comment: "Shown in menu"))
let brightnessSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu,
forDisplay: display,
command: .brightness,
title: NSLocalizedString("Brightness", comment: "Shown in menu"))
if prefs.bool(forKey: Utils.PrefKeys.showContrast.rawValue) {
let contrastSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu,
forDisplay: display,
command: .contrast,
title: NSLocalizedString("Contrast", comment: "Shown in menu"))
display.contrastSliderHandler = contrastSliderHandler
if !display.isSw() {
if prefs.bool(forKey: Utils.PrefKeys.showVolume.rawValue) {
let volumeSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu, forDisplay: display, command: .audioSpeakerVolume, title: NSLocalizedString("Volume", comment: "Shown in menu"))
display.volumeSliderHandler = volumeSliderHandler
}
if prefs.bool(forKey: Utils.PrefKeys.showContrast.rawValue) {
let contrastSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu, forDisplay: display, command: .contrast, title: NSLocalizedString("Contrast", comment: "Shown in menu"))
display.contrastSliderHandler = contrastSliderHandler
}
}
display.volumeSliderHandler = volumeSliderHandler
var numOfTickMarks = 0
if !display.isSw(), prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) {
numOfTickMarks = 0 // 1 - I disabled this because tickmarks are buggy in dark mode on Monterey (probably Big Sur as well).
}
let brightnessSliderHandler = Utils.addSliderMenuItem(toMenu: monitorSubMenu, forDisplay: display, command: .brightness, title: NSLocalizedString("Brightness", comment: "Shown in menu"), numOfTickMarks: numOfTickMarks)
display.brightnessSliderHandler = brightnessSliderHandler
let monitorMenuItem = NSMenuItem()
monitorMenuItem.title = "\(display.getFriendlyName())"
if asSubMenu {
monitorMenuItem.title = "\(display.getFriendlyName())"
monitorMenuItem.submenu = monitorSubMenu
} else {
let attrs: [NSAttributedString.Key: Any] = [.foregroundColor: NSColor.systemGray, .font: NSFont.boldSystemFont(ofSize: 12)]
monitorMenuItem.attributedTitle = NSAttributedString(string: "\(display.getFriendlyName())", attributes: attrs)
}
self.monitorItems.append(monitorMenuItem)
@ -167,19 +249,44 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
private func subscribeEventListeners() {
// subscribe KeyTap event listener
NotificationCenter.default.addObserver(self, selector: #selector(handleListenForChanged), name: .listenFor, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleShowContrastChanged), name: .showContrast, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleListenForChanged), name: .listenFor, object: nil) // subscribe KeyTap event listeners
NotificationCenter.default.addObserver(self, selector: #selector(handleFriendlyNameChanged), name: .friendlyName, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handlePreferenceReset), name: .preferenceReset, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(audioDeviceChanged), name: Notification.Name.defaultOutputDeviceChanged, object: nil) // subscribe Audio output detector (SimplyCoreAudio)
DistributedNotificationCenter.default.addObserver(self, selector: #selector(colorSyncSettingsChanged), name: NSNotification.Name(rawValue: kColorSyncDisplayDeviceProfilesNotification.takeRetainedValue() as String), object: nil) // ColorSync change
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.sleepNotification), name: NSWorkspace.screensDidSleepNotification, object: nil) // sleep and wake listeners
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.wakeNotofication), name: NSWorkspace.screensDidWakeNotification, object: nil)
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.sleepNotification), name: NSWorkspace.willSleepNotification, object: nil)
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(self.wakeNotofication), name: NSWorkspace.didWakeNotification, object: nil)
_ = DistributedNotificationCenter.default().addObserver(forName: .accessibilityApi, object: nil, queue: nil) { _ in DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.updateMediaKeyTap() // listen for accessibility status changes
}
}
}
// subscribe Audio output detector (SimplyCoreAudio)
NotificationCenter.default.addObserver(self, selector: #selector(audioDeviceChanged), name: Notification.Name.defaultOutputDeviceChanged, object: nil)
@objc private func sleepNotification() {
self.sleepID += 1
os_log("Sleeping with sleep %{public}@", type: .info, String(self.sleepID))
}
// listen for accessibility status changes
_ = DistributedNotificationCenter.default().addObserver(forName: .accessibilityApi, object: nil, queue: nil) { _ in
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.updateMediaKeyTap()
@objc private func wakeNotofication() {
if self.sleepID != 0 {
os_log("Waking up from sleep %{public}@", type: .info, String(self.sleepID))
let dispatchedSleepID = self.sleepID
DispatchQueue.main.asyncAfter(deadline: .now() + 6.0) { // Some displays take time to recover...
self.soberNow(dispatchedSleepID: dispatchedSleepID)
}
}
}
private func soberNow(dispatchedSleepID: Int) {
if self.sleepID == dispatchedSleepID {
os_log("Sober from sleep %{public}@", type: .info, String(self.sleepID))
self.sleepID = 0
if self.reconfigureID != 0 {
let dispatchedReconfigureID = self.reconfigureID
os_log("Display needs reconfig after sober with reconfigureID %{public}@", type: .info, String(dispatchedReconfigureID))
self.updateDisplays(dispatchedReconfigureID: dispatchedReconfigureID)
}
}
}
@ -217,16 +324,21 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
}
// MARK: - Media Key Tap delegate
extension AppDelegate: MediaKeyTapDelegate {
func handle(mediaKey: MediaKey, event: KeyEvent?, modifiers: NSEvent.ModifierFlags?) {
guard self.sleepID == 0, self.reconfigureID == 0 else {
if [.brightnessUp, .brightnessDown].contains(mediaKey) {
OSDUtils.showOSDLockOnAllDisplays(osdImage: 1)
}
if [.volumeUp, .volumeDown, .mute].contains(mediaKey) {
OSDUtils.showOSDLockOnAllDisplays(osdImage: 3)
}
return
}
if self.handleOpenPrefPane(mediaKey: mediaKey, event: event, modifiers: modifiers) {
return
}
let isSmallIncrement = modifiers?.isSuperset(of: NSEvent.ModifierFlags([.shift, .option])) ?? false
// control internal display when holding ctrl modifier
let isControlModifier = modifiers?.isSuperset(of: NSEvent.ModifierFlags([.control])) ?? false
if isControlModifier, mediaKey == .brightnessUp || mediaKey == .brightnessDown {
@ -235,10 +347,8 @@ extension AppDelegate: MediaKeyTapDelegate {
return
}
}
let oppositeKey: MediaKey? = self.oppositeMediaKey(mediaKey: mediaKey)
let isRepeat = event?.keyRepeat ?? false
// If the opposite key to the one being held has an active timer, cancel it - we'll be going in the opposite direction
if let oppositeKey = oppositeKey, let oppositeKeyTimer = self.keyRepeatTimers[oppositeKey], oppositeKeyTimer.isValid {
oppositeKeyTimer.invalidate()
@ -252,65 +362,90 @@ extension AppDelegate: MediaKeyTapDelegate {
self.sendDisplayCommand(mediaKey: mediaKey, isRepeat: isRepeat, isSmallIncrement: isSmallIncrement)
}
private func sendDisplayCommand(mediaKey: MediaKey, isRepeat: Bool, isSmallIncrement: Bool) {
let displays = DisplayManager.shared.getAllDisplays()
guard let currentDisplay = DisplayManager.shared.getCurrentDisplay() else { return }
let allDisplays = prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) ? displays : [currentDisplay]
// Introduce a small delay to handle the media key being held down
let delay = isRepeat ? 0.05 : 0
self.keyRepeatTimers[mediaKey] = Timer.scheduledTimer(withTimeInterval: delay, repeats: false, block: { _ in
for display in allDisplays where display.isEnabled {
switch mediaKey {
case .brightnessUp, .brightnessDown:
display.stepBrightness(isUp: mediaKey == .brightnessUp, isSmallIncrement: isSmallIncrement)
case .mute:
// The mute key should not respond to press + hold
if !isRepeat {
// mute only matters for external displays
if let display = display as? ExternalDisplay {
display.toggleMute()
}
}
case .volumeUp, .volumeDown:
// volume only matters for external displays
if let display = display as? ExternalDisplay {
display.stepVolume(isUp: mediaKey == .volumeUp, isSmallIncrement: isSmallIncrement)
}
default:
return
private func getAffectedDisplays() -> [Display]? {
var affectedDisplays: [Display]
let allDisplays = DisplayManager.shared.getAllNonVirtualDisplays()
guard let currentDisplay = DisplayManager.shared.getCurrentDisplay() else {
return nil
}
// let allDisplays = prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) ? displays : [currentDisplay]
if prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) {
affectedDisplays = allDisplays
} else {
affectedDisplays = [currentDisplay]
if CGDisplayIsInHWMirrorSet(currentDisplay.identifier) != 0 || CGDisplayIsInMirrorSet(currentDisplay.identifier) != 0, CGDisplayMirrorsDisplay(currentDisplay.identifier) == 0 {
for display in allDisplays where CGDisplayMirrorsDisplay(display.identifier) == currentDisplay.identifier {
affectedDisplays.append(display)
}
}
})
}
return affectedDisplays
}
// MARK: - Prefs notification
private func sendDisplayCommand(mediaKey: MediaKey, isRepeat: Bool, isSmallIncrement: Bool) {
guard self.sleepID == 0, self.reconfigureID == 0, let affectedDisplays = self.getAffectedDisplays() else {
return
}
var isAnyDisplayInSwAfterBrightnessMode: Bool = false
for display in affectedDisplays where ((display as? ExternalDisplay)?.isSwBrightnessNotDefault() ?? false) && !((display as? ExternalDisplay)?.isSw() ?? false) {
isAnyDisplayInSwAfterBrightnessMode = true
}
// let delay = isRepeat ? 0.05 : 0 // Introduce a small delay to handle the media key being held down - Update: it is not clear why this is needed but it blocks the media keys working when the menu is open and also it doesn't seem to affect external bluetooth keyboards but slows down internal keyboards for some reason. Things seem to work better this being disabled.
// self.keyRepeatTimers[mediaKey] = Timer.scheduledTimer(withTimeInterval: delay, repeats: false, block: { _ in
for display in affectedDisplays where display.isEnabled && !display.isVirtual {
switch mediaKey {
case .brightnessUp:
if !(isAnyDisplayInSwAfterBrightnessMode && !(((display as? ExternalDisplay)?.isSwBrightnessNotDefault() ?? false) && !((display as? ExternalDisplay)?.isSw() ?? false))) {
display.stepBrightness(isUp: mediaKey == .brightnessUp, isSmallIncrement: isSmallIncrement)
}
case .brightnessDown:
display.stepBrightness(isUp: mediaKey == .brightnessUp, isSmallIncrement: isSmallIncrement)
case .mute:
// The mute key should not respond to press + hold
if !isRepeat {
// mute only matters for external displays
if let display = display as? ExternalDisplay {
display.toggleMute()
}
}
case .volumeUp, .volumeDown:
// volume only matters for external displays
if let display = display as? ExternalDisplay {
display.stepVolume(isUp: mediaKey == .volumeUp, isSmallIncrement: isSmallIncrement)
}
default:
return
}
}
// })
}
@objc func handleListenForChanged() {
self.checkPermissions()
self.updateMediaKeyTap()
}
@objc func handleShowContrastChanged() {
self.updateDisplays()
}
@objc func handleFriendlyNameChanged() {
self.updateDisplays()
self.updateMenus()
}
@objc func handlePreferenceReset() {
os_log("Resetting all preferences.")
if prefs.bool(forKey: Utils.PrefKeys.fallbackSw.rawValue) || prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) {
DisplayManager.shared.resetSwBrightnessForAllDisplays()
}
if let bundleID = Bundle.main.bundleIdentifier {
UserDefaults.standard.removePersistentDomain(forName: bundleID)
}
app.statusItem.isVisible = true
self.setDefaultPrefs()
self.updateDisplays()
self.checkPermissions()
self.updateMediaKeyTap()
self.updateDisplays(firstrun: true)
}
private func updateMediaKeyTap() {
var keys: [MediaKey]
switch prefs.integer(forKey: Utils.PrefKeys.listenFor.rawValue) {
case Utils.ListenForKeys.brightnessOnlyKeys.rawValue:
keys = [.brightnessUp, .brightnessDown]
@ -321,13 +456,20 @@ extension AppDelegate: MediaKeyTapDelegate {
default:
keys = [.brightnessUp, .brightnessDown, .mute, .volumeUp, .volumeDown]
}
// Remove keys if no external displays are connected
var isInternalDisplayOnly = true
for display in DisplayManager.shared.getAllDisplays() where display is ExternalDisplay {
isInternalDisplayOnly = false
}
if isInternalDisplayOnly {
let keysToDelete: [MediaKey] = [.volumeUp, .volumeDown, .mute, .brightnessUp, .brightnessDown]
keys.removeAll { keysToDelete.contains($0) }
}
// Remove volume related keys if audio device is controllable
if self.coreAudio.defaultOutputDevice?.canSetVirtualMasterVolume(scope: .output) == true {
// Remove volume related keys.
let keysToDelete: [MediaKey] = [.volumeUp, .volumeDown, .mute]
keys.removeAll { keysToDelete.contains($0) }
}
self.mediaKeyTap?.stop()
// returning an empty array listens for all mediakeys in MediaKeyTap
if keys.count > 0 {
@ -345,4 +487,9 @@ extension AppDelegate: MediaKeyTapDelegate {
#endif
self.updateMediaKeyTap()
}
@objc private func colorSyncSettingsChanged() {
CGDisplayRestoreColorSyncSettings()
self.displayReconfigured()
}
}

View file

@ -1,68 +1,68 @@
{
"images" : [
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "Icon-16.png",
"scale" : "1x"
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "Icon-33.png",
"scale" : "2x"
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "Icon-32.png",
"scale" : "1x"
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "Icon-64.png",
"scale" : "2x"
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "Icon-128.png",
"scale" : "1x"
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "Icon-257.png",
"scale" : "2x"
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "Icon-256.png",
"scale" : "1x"
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "Icon-513.png",
"scale" : "2x"
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "Icon-512.png",
"scale" : "1x"
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "Icon-1024.png",
"scale" : "2x"
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 986 KiB

After

Width:  |  Height:  |  Size: 609 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 754 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 KiB

After

Width:  |  Height:  |  Size: 164 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 KiB

After

Width:  |  Height:  |  Size: 164 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Before After
Before After

View file

@ -1,6 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}

View file

@ -1,23 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "Keyboard-32.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "Keyboard-64.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "Keyboard-96.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -3,7 +3,6 @@ import Cocoa
extension NSNotification.Name {
static let accessibilityApi = NSNotification.Name(rawValue: "com.apple.accessibility.api")
static let listenFor = NSNotification.Name(rawValue: Utils.PrefKeys.listenFor.rawValue)
static let showContrast = NSNotification.Name(rawValue: Utils.PrefKeys.showContrast.rawValue)
static let friendlyName = NSNotification.Name(rawValue: Utils.PrefKeys.friendlyName.rawValue)
static let preferenceReset = NSNotification.Name(rawValue: Utils.PrefKeys.preferenceReset.rawValue)
static let displayListUpdate = NSNotification.Name(rawValue: Utils.PrefKeys.displayListUpdate.rawValue)

View file

@ -47,13 +47,8 @@ public extension NSScreen {
while case let object = IOIteratorNext(servicePortIterator), object != 0 {
let dict = (IODisplayCreateInfoDictionary(object, UInt32(kIODisplayOnlyPreferredName)).takeRetainedValue() as NSDictionary as? [String: AnyObject])!
if dict[kDisplayVendorID] as? UInt32 == self.vendorNumber,
dict[kDisplayProductID] as? UInt32 == self.modelNumber,
dict[kDisplaySerialNumber] as? UInt32 == self.serialNumber
{
if let productName = dict["DisplayProductName"] as? [String: String],
let firstKey = Array(productName.keys).first
{
if dict[kDisplayVendorID] as? UInt32 == self.vendorNumber, dict[kDisplayProductID] as? UInt32 == self.modelNumber, dict[kDisplaySerialNumber] as? UInt32 == self.serialNumber {
if let productName = dict["DisplayProductName"] as? [String: String], let firstKey = Array(productName.keys).first {
return productName[firstKey]!
}
}

View file

@ -10,7 +10,6 @@ import Preferences
extension Preferences.PaneIdentifier {
static let main = Self("Main")
static let keys = Self("Keys")
static let advanced = Self("Advanced")
static let display = Self("Display")
static let displays = Self("Displays")
static let about = Self("About")
}

View file

@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>947</string>
<string>2866</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>

View file

@ -1,13 +1,10 @@
import Cocoa
import DDC
class DisplayManager {
public static let shared = DisplayManager()
private var displays: [Display] {
didSet {
NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.displayListUpdate.rawValue), object: nil)
}
}
private var displays: [Display]
init() {
self.displays = []
@ -17,13 +14,33 @@ class DisplayManager {
self.displays = displays
}
func getExternalDisplays() -> [ExternalDisplay] {
return self.displays.compactMap { $0 as? ExternalDisplay }
}
func getAllDisplays() -> [Display] {
return self.displays
}
func getAllNonVirtualDisplays() -> [Display] {
return self.displays.compactMap { display -> Display? in
if !display.isVirtual {
return display
} else { return nil }
}
}
func getDdcCapableDisplays() -> [ExternalDisplay] {
return self.displays.compactMap { display -> ExternalDisplay? in
if let externalDisplay = display as? ExternalDisplay, externalDisplay.ddc != nil {
if let externalDisplay = display as? ExternalDisplay, !externalDisplay.isSw(), !externalDisplay.isVirtual {
return externalDisplay
} else { return nil }
}
}
func getNonVirtualExternalDisplays() -> [ExternalDisplay] {
return self.displays.compactMap { display -> ExternalDisplay? in
if let externalDisplay = display as? ExternalDisplay, !externalDisplay.isVirtual {
return externalDisplay
} else { return nil }
}
@ -34,10 +51,12 @@ class DisplayManager {
}
func getCurrentDisplay() -> Display? {
guard let mainDisplayID = NSScreen.main?.displayID else {
return nil
let mouseLocation = NSEvent.mouseLocation
let screens = NSScreen.screens
if let screenWithMouse = (screens.first { NSMouseInRect(mouseLocation, $0.frame, false) }) {
return self.displays.first { $0.identifier == screenWithMouse.displayID }
}
return self.displays.first { $0.identifier == mainDisplayID }
return nil
}
func addDisplay(display: Display) {
@ -53,4 +72,83 @@ class DisplayManager {
func clearDisplays() {
self.displays = []
}
func resetSwBrightnessForAllDisplays(settingsOnly: Bool = false, async: Bool = false) {
for externalDisplay in self.getNonVirtualExternalDisplays() {
if !settingsOnly {
_ = externalDisplay.setSwBrightness(value: externalDisplay.getSwMaxBrightness(), smooth: async)
} else {
externalDisplay.saveSwBirghtnessPrefValue(Int(externalDisplay.getSwMaxBrightness()))
}
if externalDisplay.isSw() {
externalDisplay.saveValue(Int(externalDisplay.getSwMaxBrightness()), for: .brightness)
}
}
}
func setBrightnessSliderValue(externalDisplay: ExternalDisplay, value: Int32) {
if let slider = externalDisplay.brightnessSliderHandler?.slider {
slider.intValue = value
}
}
func getBrightnessSliderMaxValue(externalDisplay: ExternalDisplay) -> Double {
if let slider = externalDisplay.brightnessSliderHandler?.slider {
return slider.maxValue
}
return 0
}
func restoreSwBrightnessForAllDisplays(async: Bool = false) {
for externalDisplay in self.getExternalDisplays() {
let sliderMax = self.getBrightnessSliderMaxValue(externalDisplay: externalDisplay)
if externalDisplay.getValue(for: .brightness) == 0 || externalDisplay.isSw() {
let savedPrefValue = externalDisplay.getSwBrightnessPrefValue()
if externalDisplay.getSwBrightness() != savedPrefValue {
if let manager = OSDManager.sharedManager() as? OSDManager { // This will give the user a hint why is the brightness suddenly changes and also give screen activity to counter the 'no gamma change when there is no screen activity' issue on some macs
manager.showImage(OSDImage.brightness.rawValue, onDisplayID: externalDisplay.identifier, priority: 0x1F4, msecUntilFade: 0)
}
}
externalDisplay.saveSwBirghtnessPrefValue(Int(externalDisplay.getSwBrightness()))
_ = externalDisplay.setSwBrightness(value: UInt8(savedPrefValue), smooth: async)
if !externalDisplay.isSw(), prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) {
if savedPrefValue < externalDisplay.getSwMaxBrightness() {
self.setBrightnessSliderValue(externalDisplay: externalDisplay, value: Int32(Float(sliderMax / 2) * (Float(savedPrefValue) / Float(externalDisplay.getSwMaxBrightness()))))
} else {
self.setBrightnessSliderValue(externalDisplay: externalDisplay, value: Int32(sliderMax / 2) + Int32(externalDisplay.getValue(for: DDC.Command.brightness)))
}
} else if externalDisplay.isSw() {
self.setBrightnessSliderValue(externalDisplay: externalDisplay, value: Int32(Float(sliderMax) * (Float(savedPrefValue) / Float(externalDisplay.getSwMaxBrightness()))))
}
} else {
_ = externalDisplay.setSwBrightness(value: externalDisplay.getSwMaxBrightness())
if externalDisplay.isSw() {
self.setBrightnessSliderValue(externalDisplay: externalDisplay, value: Int32(sliderMax))
}
}
}
}
func getDisplayNameByID(displayID: CGDirectDisplayID) -> String {
let defaultName: String = NSLocalizedString("Unknown", comment: "Unknown display name")
if #available(macOS 11.0, *) {
if let dictionary = ((CoreDisplay_DisplayCreateInfoDictionary(displayID))?.takeRetainedValue() as NSDictionary?), let nameList = dictionary["DisplayProductName"] as? [String: String], var name = nameList[Locale.current.identifier] ?? nameList["en_US"] ?? nameList.first?.value {
if CGDisplayIsInHWMirrorSet(displayID) != 0 || CGDisplayIsInMirrorSet(displayID) != 0 {
let mirroredDisplayID = CGDisplayMirrorsDisplay(displayID)
if mirroredDisplayID != 0, let dictionary = ((CoreDisplay_DisplayCreateInfoDictionary(mirroredDisplayID))?.takeRetainedValue() as NSDictionary?), let nameList = dictionary["DisplayProductName"] as? [String: String], let mirroredName = nameList[Locale.current.identifier] ?? nameList["en_US"] ?? nameList.first?.value {
name.append("~" + mirroredName)
}
}
return name
}
}
if let screen = NSScreen.getByDisplayID(displayID: displayID) {
if #available(OSX 10.15, *) {
return screen.localizedName
} else {
return screen.displayName ?? defaultName
}
}
return defaultName
}
}

View file

@ -10,7 +10,7 @@ import DDC
import Foundation
import os.log
private enum OSDImage: Int64 {
enum OSDImage: Int64 {
case brightness = 1
case audioSpeaker = 3
case audioSpeakerMuted = 4
@ -23,20 +23,40 @@ class Display {
internal var modelNumber: UInt32?
internal var isEnabled: Bool {
get {
return self.prefs.object(forKey: "\(self.identifier)-state") as? Bool ?? true
self.prefs.object(forKey: "\(self.identifier)-state") as? Bool ?? true
}
set {
self.prefs.set(newValue, forKey: "\(self.identifier)-state")
}
}
var forceSw: Bool {
get {
return self.prefs.bool(forKey: "forceSw-\(self.identifier)")
}
set {
self.prefs.set(newValue, forKey: "forceSw-\(self.identifier)")
os_log("Set `forceSw` to: %{public}@", type: .info, String(newValue))
}
}
var isVirtual: Bool = false
var defaultGammaTableRed = [CGGammaValue](repeating: 0, count: 256)
var defaultGammaTableGreen = [CGGammaValue](repeating: 0, count: 256)
var defaultGammaTableBlue = [CGGammaValue](repeating: 0, count: 256)
var defaultGammaTableSampleCount: UInt32 = 0
var defaultGammaTablePeak: Float = 1
private let prefs = UserDefaults.standard
internal init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?) {
internal init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?, isVirtual: Bool = false) {
self.identifier = identifier
self.name = name
self.vendorNumber = vendorNumber
self.modelNumber = modelNumber
self.isVirtual = isVirtual
self.swUpdateDefaultGammaTable()
}
func stepBrightness(isUp _: Bool, isSmallIncrement _: Bool) {}
@ -49,7 +69,118 @@ class Display {
return self.prefs.string(forKey: "friendlyName-\(self.identifier)") ?? self.name
}
func showOsd(command: DDC.Command, value: Int, maxValue: Int = 100, roundChiclet: Bool = false) {
func getShowOsdDisplayId() -> CGDirectDisplayID {
if CGDisplayIsInHWMirrorSet(self.identifier) != 0 || CGDisplayIsInMirrorSet(self.identifier) != 0, CGDisplayMirrorsDisplay(self.identifier) != 0 {
for mirrorMaestro in DisplayManager.shared.getAllNonVirtualDisplays() where CGDisplayMirrorsDisplay(self.identifier) == mirrorMaestro.identifier {
if let externalMirrorMaestro = mirrorMaestro as? ExternalDisplay, externalMirrorMaestro.isSw() {
var thereAreOthers = false
for mirrorMember in DisplayManager.shared.getAllNonVirtualDisplays() where CGDisplayMirrorsDisplay(mirrorMember.identifier) == CGDisplayMirrorsDisplay(self.identifier) && mirrorMember.identifier != self.identifier {
thereAreOthers = true
}
if !thereAreOthers {
return externalMirrorMaestro.identifier
}
}
}
}
return self.identifier
}
func swUpdateDefaultGammaTable() {
CGGetDisplayTransferByTable(self.identifier, 256, &self.defaultGammaTableRed, &self.defaultGammaTableGreen, &self.defaultGammaTableBlue, &self.defaultGammaTableSampleCount)
let redPeak = self.defaultGammaTableRed.max() ?? 0
let greenPeak = self.defaultGammaTableGreen.max() ?? 0
let bluePeak = self.defaultGammaTableBlue.max() ?? 0
self.defaultGammaTablePeak = max(redPeak, greenPeak, bluePeak)
}
func swBrightnessTransform(value: Float, reverse: Bool = false) -> Float {
let lowTreshold: Float = 0.1 // We don't allow decrease lower than 5% for safety reasons and because some displays blank off after a while on full black screen due to energy saving settings
if !reverse {
return value * (1 - lowTreshold) + lowTreshold
} else {
return (value - lowTreshold) / (1 - lowTreshold)
}
}
let swBrightnessSemaphore = DispatchSemaphore(value: 1)
func setSwBrightness(value: UInt8, smooth: Bool = false) -> Bool {
let brightnessValue: UInt8 = min(getSwMaxBrightness(), value)
var currentValue = Float(self.getSwBrightnessPrefValue()) / Float(self.getSwMaxBrightness())
self.saveSwBirghtnessPrefValue(Int(brightnessValue))
var newValue = Float(Float(brightnessValue)) / Float(self.getSwMaxBrightness())
currentValue = self.swBrightnessTransform(value: currentValue)
newValue = self.swBrightnessTransform(value: newValue)
os_log("setting software brightness to: %{public}@", type: .debug, String(newValue))
if smooth {
DispatchQueue.global(qos: .userInteractive).async {
self.swBrightnessSemaphore.wait()
for transientValue in stride(from: currentValue, to: newValue, by: 0.005 * (currentValue > newValue ? -1 : 1)) {
let gammaTableRed = self.defaultGammaTableRed.map { $0 * transientValue }
let gammaTableGreen = self.defaultGammaTableGreen.map { $0 * transientValue }
let gammaTableBlue = self.defaultGammaTableBlue.map { $0 * transientValue }
guard app.reconfigureID == 0 else {
return
}
CGSetDisplayTransferByTable(self.identifier, self.defaultGammaTableSampleCount, gammaTableRed, gammaTableGreen, gammaTableBlue)
Thread.sleep(forTimeInterval: 0.001) // Let's make things quick if not performed in the background
}
self.swBrightnessSemaphore.signal()
}
} else {
let gammaTableRed = self.defaultGammaTableRed.map { $0 * /* transientValue */ newValue }
let gammaTableGreen = self.defaultGammaTableGreen.map { $0 * /* transientValue */ newValue }
let gammaTableBlue = self.defaultGammaTableBlue.map { $0 * /* transientValue */ newValue }
CGSetDisplayTransferByTable(self.identifier, self.defaultGammaTableSampleCount, gammaTableRed, gammaTableGreen, gammaTableBlue)
}
return true
}
func getSwBrightness() -> UInt8 {
var gammaTableRed = [CGGammaValue](repeating: 0, count: 256)
var gammaTableGreen = [CGGammaValue](repeating: 0, count: 256)
var gammaTableBlue = [CGGammaValue](repeating: 0, count: 256)
var gammaTableSampleCount: UInt32 = 0
if CGGetDisplayTransferByTable(self.identifier, 256, &gammaTableRed, &gammaTableGreen, &gammaTableBlue, &gammaTableSampleCount) == CGError.success {
let redPeak = gammaTableRed.max() ?? 0
let greenPeak = gammaTableGreen.max() ?? 0
let bluePeak = gammaTableBlue.max() ?? 0
let gammaTablePeak = max(redPeak, greenPeak, bluePeak)
let peakRatio = gammaTablePeak / self.defaultGammaTablePeak
let brightnessValue = UInt8(round(self.swBrightnessTransform(value: peakRatio, reverse: true) * Float(self.getSwMaxBrightness())))
os_log("Current software gammatable brightness is: %{public}@", type: .debug, String(brightnessValue))
return brightnessValue
}
return self.getSwMaxBrightness()
}
func resetSwBrightness() -> Bool {
return self.setSwBrightness(value: self.getSwMaxBrightness())
}
func saveSwBirghtnessPrefValue(_ value: Int) {
self.prefs.set(value, forKey: "SwBrightness-\(self.identifier)")
}
func getSwBrightnessPrefValue() -> Int {
return self.prefs.integer(forKey: "SwBrightness-\(self.identifier)")
}
func getSwMaxBrightness() -> UInt8 {
return 100
}
func isSwBrightnessNotDefault() -> Bool {
guard !self.isVirtual else {
return false
}
if self.getSwBrightness() < self.getSwMaxBrightness() {
return true
}
return false
}
func showOsd(command: DDC.Command, value: Int, maxValue: Int = 100, roundChiclet: Bool = false, lock: Bool = false) {
guard let manager = OSDManager.sharedManager() as? OSDManager else {
return
}
@ -78,11 +209,11 @@ class Display {
}
manager.showImage(osdImage.rawValue,
onDisplayID: self.identifier,
onDisplayID: self.getShowOsdDisplayId(),
priority: 0x1F4,
msecUntilFade: 1000,
filledChiclets: UInt32(filledChiclets),
totalChiclets: UInt32(totalChiclets),
locked: false)
locked: lock)
}
}

View file

@ -1,6 +1,7 @@
import AVFoundation
import Cocoa
import DDC
import IOKit
import os.log
class ExternalDisplay: Display {
@ -8,9 +9,23 @@ class ExternalDisplay: Display {
var volumeSliderHandler: SliderHandler?
var contrastSliderHandler: SliderHandler?
var ddc: DDC?
var arm64ddc: Bool = false
var arm64avService: IOAVService?
let DDC_HARD_MAX_LIMIT: Int = 100
private let prefs = UserDefaults.standard
var enableMuteUnmute: Bool {
get {
return self.prefs.bool(forKey: "enableMuteUnmute-\(self.identifier)")
}
set {
self.prefs.set(newValue, forKey: "enableMuteUnmute-\(self.identifier)")
os_log("Set `enableMuteUnmute` for %{private}@ to: %{public}@", type: .info, String(self.identifier), String(newValue))
}
}
var hideOsd: Bool {
get {
return self.prefs.bool(forKey: "hideOsd-\(self.identifier)")
@ -33,20 +48,11 @@ class ExternalDisplay: Display {
private var audioPlayer: AVAudioPlayer?
override init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?) {
super.init(identifier, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber)
self.ddc = DDC(for: identifier)
}
override init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?, isVirtual: Bool = false) {
super.init(identifier, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual)
// On some displays, the display's OSD overlaps the macOS OSD,
// calling the OSD command with 1 seems to hide it.
func hideDisplayOsd() {
guard self.hideOsd else {
return
}
for _ in 0 ..< 20 {
_ = self.ddc?.write(command: .osd, value: UInt16(1), errorRecoveryWaitTime: 2000)
if !isVirtual, !Arm64DDCUtils.isArm64 {
self.ddc = DDC(for: identifier)
}
}
@ -75,12 +81,12 @@ class ExternalDisplay: Display {
let volumeDDCValue = UInt16(volumeOSDValue)
guard self.ddc?.write(command: .audioSpeakerVolume, value: volumeDDCValue) == true else {
guard self.writeDDCValues(command: .audioSpeakerVolume, value: volumeDDCValue) == true else {
return
}
if self.supportsMuteCommand() {
guard self.ddc?.write(command: .audioMuteScreenBlank, value: UInt16(muteValue)) == true else {
if self.enableMuteUnmute {
guard self.writeDDCValues(command: .audioMuteScreenBlank, value: UInt16(muteValue)) == true else {
return
}
}
@ -88,8 +94,9 @@ class ExternalDisplay: Display {
self.saveValue(muteValue, for: .audioMuteScreenBlank)
if !fromVolumeSlider {
self.hideDisplayOsd()
self.showOsd(command: volumeOSDValue > 0 ? .audioSpeakerVolume : .audioMuteScreenBlank, value: volumeOSDValue, roundChiclet: true)
if !self.hideOsd {
self.showOsd(command: volumeOSDValue > 0 ? .audioSpeakerVolume : .audioMuteScreenBlank, value: volumeOSDValue, roundChiclet: true)
}
if volumeOSDValue > 0 {
self.playVolumeChangedSound()
@ -103,7 +110,9 @@ class ExternalDisplay: Display {
func stepVolume(isUp: Bool, isSmallIncrement: Bool) {
var muteValue: Int?
let volumeOSDValue = self.calcNewValue(for: .audioSpeakerVolume, isUp: isUp, isSmallIncrement: isSmallIncrement)
let currentValue = self.getValue(for: .audioSpeakerVolume)
let maxValue = self.getMaxValue(for: .audioSpeakerVolume)
let volumeOSDValue = self.calcNewValue(currentValue: currentValue, maxValue: maxValue, isUp: isUp, isSmallIncrement: isSmallIncrement)
let volumeDDCValue = UInt16(volumeOSDValue)
if self.isMuted(), volumeOSDValue > 0 {
muteValue = 2
@ -113,24 +122,22 @@ class ExternalDisplay: Display {
let isAlreadySet = volumeOSDValue == self.getValue(for: .audioSpeakerVolume)
if !isAlreadySet {
guard self.ddc?.write(command: .audioSpeakerVolume, value: volumeDDCValue) == true else {
return
}
guard self.writeDDCValues(command: .audioSpeakerVolume, value: volumeDDCValue) == true else {
return
}
if let muteValue = muteValue {
// If the mute command is supported, set its value accordingly
if self.supportsMuteCommand() {
guard self.ddc?.write(command: .audioMuteScreenBlank, value: UInt16(muteValue)) == true else {
if self.enableMuteUnmute {
guard self.writeDDCValues(command: .audioMuteScreenBlank, value: UInt16(muteValue)) == true else {
return
}
}
self.saveValue(muteValue, for: .audioMuteScreenBlank)
}
self.hideDisplayOsd()
self.showOsd(command: .audioSpeakerVolume, value: volumeOSDValue, roundChiclet: !isSmallIncrement)
if !self.hideOsd {
self.showOsd(command: .audioSpeakerVolume, value: volumeOSDValue, roundChiclet: !isSmallIncrement)
}
if !isAlreadySet {
self.saveValue(volumeOSDValue, for: .audioSpeakerVolume)
@ -145,86 +152,168 @@ class ExternalDisplay: Display {
}
}
override func stepBrightness(isUp: Bool, isSmallIncrement: Bool) {
let osdValue = Int(self.calcNewValue(for: .brightness, isUp: isUp, isSmallIncrement: isSmallIncrement))
let isAlreadySet = osdValue == self.getValue(for: .brightness)
let ddcValue = UInt16(osdValue)
func isSwOnly() -> Bool {
return (!self.arm64ddc && self.ddc == nil && !self.isVirtual)
}
// Set the contrast value according to the brightness, if necessary
if !isAlreadySet {
self.setContrastValueForBrightness(osdValue)
}
if !isAlreadySet {
guard self.ddc?.write(command: .brightness, value: ddcValue) == true else {
return
}
}
self.showOsd(command: .brightness, value: osdValue, roundChiclet: !isSmallIncrement)
if !isAlreadySet {
if let slider = self.brightnessSliderHandler?.slider {
slider.intValue = Int32(ddcValue)
}
self.saveValue(osdValue, for: .brightness)
func isSw() -> Bool {
if self.prefs.bool(forKey: "forceSw-\(self.identifier)") || self.isSwOnly() {
return true
} else {
return false
}
}
func setContrastValueForBrightness(_ brightness: Int) {
var contrastValue: Int?
if brightness == 0 {
contrastValue = 0
// Save the current DDC value for contrast so it can be restored, even across app restarts
if self.getRestoreValue(for: .contrast) == 0 {
self.setRestoreValue(self.getValue(for: .contrast), for: .contrast)
let swAfterOsdAnimationSemaphore = DispatchSemaphore(value: 1)
var lastAnimationStartedTime: CFTimeInterval = CACurrentMediaTime()
func doSwAfterOsdAnimation() {
self.lastAnimationStartedTime = CACurrentMediaTime()
DispatchQueue.global(qos: .userInteractive).async {
self.swAfterOsdAnimationSemaphore.wait()
guard CACurrentMediaTime() < self.lastAnimationStartedTime + 0.05 else {
self.swAfterOsdAnimationSemaphore.signal()
return
}
} else if self.getValue(for: .brightness) == 0, brightness > 0 {
contrastValue = self.getRestoreValue(for: .contrast)
for value: Int in stride(from: 1, to: 6, by: 1) {
guard self.getValue(for: .brightness) == 0 else {
self.swAfterOsdAnimationSemaphore.signal()
return
}
self.showOsd(command: .brightness, value: value, roundChiclet: false)
Thread.sleep(forTimeInterval: Double(value * 2) / 300)
}
for value: Int in stride(from: 5, to: 0, by: -1) {
guard self.getValue(for: .brightness) == 0 else {
self.swAfterOsdAnimationSemaphore.signal()
return
}
self.showOsd(command: .brightness, value: value, roundChiclet: false)
Thread.sleep(forTimeInterval: Double(value * 2) / 300)
}
self.showOsd(command: .brightness, value: 0, roundChiclet: true)
self.swAfterOsdAnimationSemaphore.signal()
}
}
func stepBrightnessPart(osdValue: Int, isSmallIncrement: Bool) -> Bool {
if self.isSw(), self.prefs.bool(forKey: Utils.PrefKeys.fallbackSw.rawValue) {
if self.setSwBrightness(value: UInt8(osdValue), smooth: true) {
self.showOsd(command: .brightness, value: osdValue, roundChiclet: !isSmallIncrement)
self.saveValue(osdValue, for: .brightness)
if let slider = brightnessSliderHandler?.slider {
slider.intValue = Int32(osdValue)
}
}
return true
}
return false
}
func stepBrightnessswAfterBirghtnessMode(osdValue: Int, isUp: Bool, isSmallIncrement: Bool) -> Bool {
let isAlreadySet = osdValue == self.getValue(for: .brightness)
var swAfterBirghtnessMode: Bool = isSwBrightnessNotDefault()
if isAlreadySet, !isUp, !swAfterBirghtnessMode, self.prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) {
swAfterBirghtnessMode = true
}
// Only write the new contrast value if lowering contrast after brightness is enabled
if let contrastValue = contrastValue, self.prefs.bool(forKey: Utils.PrefKeys.lowerContrast.rawValue) {
_ = self.ddc?.write(command: .contrast, value: UInt16(contrastValue))
self.saveValue(contrastValue, for: .contrast)
if let slider = contrastSliderHandler?.slider {
slider.intValue = Int32(contrastValue)
if swAfterBirghtnessMode {
let currentSwBrightness = UInt8(self.getSwBrightnessPrefValue())
var swBirghtnessValue = self.calcNewValue(currentValue: Int(currentSwBrightness), maxValue: Int(getSwMaxBrightness()), isUp: isUp, isSmallIncrement: isSmallIncrement)
if swBirghtnessValue >= Int(getSwMaxBrightness()) {
swBirghtnessValue = Int(getSwMaxBrightness())
swAfterBirghtnessMode = false
}
if self.setSwBrightness(value: UInt8(swBirghtnessValue)) {
if let slider = brightnessSliderHandler?.slider {
slider.intValue = Int32(Float(slider.maxValue / 2) * (Float(swBirghtnessValue) / Float(getSwMaxBrightness())))
}
self.doSwAfterOsdAnimation()
}
}
return swAfterBirghtnessMode
}
override func stepBrightness(isUp: Bool, isSmallIncrement: Bool) {
let currentValue = self.getValue(for: .brightness)
let maxValue = self.isSw() ? Int(self.getSwMaxBrightness()) : self.getMaxValue(for: .brightness)
let osdValue = self.calcNewValue(currentValue: currentValue, maxValue: maxValue, isUp: isUp, isSmallIncrement: isSmallIncrement)
if self.stepBrightnessPart(osdValue: osdValue, isSmallIncrement: isSmallIncrement) {
return
}
if self.stepBrightnessswAfterBirghtnessMode(osdValue: osdValue, isUp: isUp, isSmallIncrement: isSmallIncrement) {
return
}
let ddcValue = UInt16(osdValue)
guard self.writeDDCValues(command: .brightness, value: ddcValue) == true else {
return
}
if let slider = brightnessSliderHandler?.slider {
if !self.isSw(), self.prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) {
slider.intValue = Int32(slider.maxValue / 2) + Int32(ddcValue)
} else {
slider.intValue = Int32(ddcValue)
}
}
self.showOsd(command: .brightness, value: osdValue, roundChiclet: !isSmallIncrement)
self.saveValue(osdValue, for: .brightness)
}
public func writeDDCValues(command: DDC.Command, value: UInt16, errorRecoveryWaitTime _: UInt32? = nil) -> Bool? {
guard app.sleepID == 0, app.reconfigureID == 0, !self.forceSw else {
return false
}
if Arm64DDCUtils.isArm64 {
guard self.arm64ddc else {
return false
}
return Arm64DDCUtils.write(service: self.arm64avService, command: command.rawValue, value: value)
} else {
return self.ddc?.write(command: command, value: value, errorRecoveryWaitTime: 2000) ?? false
}
}
func readDDCValues(for command: DDC.Command, tries: UInt, minReplyDelay delay: UInt64?) -> (current: UInt16, max: UInt16)? {
var values: (UInt16, UInt16)?
if self.ddc?.supported(minReplyDelay: delay) == true {
os_log("Display supports DDC.", type: .debug)
} else {
os_log("Display does not support DDC.", type: .debug)
guard app.sleepID == 0, app.reconfigureID == 0, !self.forceSw else {
return values
}
if self.ddc?.enableAppReport() == true {
os_log("Display supports enabling DDC application report.", type: .debug)
if Arm64DDCUtils.isArm64 {
guard self.arm64ddc else {
return nil
}
if let unwrappedDelay = delay {
values = Arm64DDCUtils.read(service: self.arm64avService, command: command.rawValue, tries: UInt8(min(tries, 255)), minReplyDelay: UInt32(unwrappedDelay / 1000))
} else {
values = Arm64DDCUtils.read(service: self.arm64avService, command: command.rawValue, tries: UInt8(min(tries, 255)))
}
} else {
os_log("Display does not support enabling DDC application report.", type: .debug)
}
if self.ddc?.supported(minReplyDelay: delay) == true {
os_log("Display supports DDC.", type: .debug)
} else {
os_log("Display does not support DDC.", type: .debug)
}
values = self.ddc?.read(command: command, tries: tries, minReplyDelay: delay)
if self.ddc?.enableAppReport() == true {
os_log("Display supports enabling DDC application report.", type: .debug)
} else {
os_log("Display does not support enabling DDC application report.", type: .debug)
}
values = self.ddc?.read(command: command, tries: tries, minReplyDelay: delay)
}
return values
}
func calcNewValue(for command: DDC.Command, isUp: Bool, isSmallIncrement: Bool) -> Int {
let currentValue = self.getValue(for: command)
func calcNewValue(currentValue: Int, maxValue: Int, isUp: Bool, isSmallIncrement: Bool) -> Int {
let nextValue: Int
let maxValue = Float(self.getMaxValue(for: command))
if isSmallIncrement {
nextValue = currentValue + (isUp ? 1 : -1)
} else {
let osdChicletFromValue = OSDUtils.chiclet(fromValue: Float(currentValue), maxValue: maxValue)
let osdChicletFromValue = OSDUtils.chiclet(fromValue: Float(currentValue), maxValue: Float(maxValue))
let distance = OSDUtils.getDistance(fromNearestChiclet: osdChicletFromValue)
// get the next rounded chiclet
@ -240,11 +329,11 @@ class ExternalDisplay: Display {
nextFilledChiclet += 1
}
nextValue = Int(round(OSDUtils.value(fromChiclet: nextFilledChiclet, maxValue: maxValue)))
nextValue = Int(round(OSDUtils.value(fromChiclet: nextFilledChiclet, maxValue: Float(maxValue))))
os_log("next: .value %{public}@/%{public}@, .osd %{public}@/%{public}@", type: .debug, String(nextValue), String(maxValue), String(nextFilledChiclet), String(OSDUtils.chicletCount))
}
return max(0, min(self.getMaxValue(for: command), nextValue))
return max(0, min(maxValue, nextValue))
}
func getValue(for command: DDC.Command) -> Int {
@ -261,7 +350,7 @@ class ExternalDisplay: Display {
func getMaxValue(for command: DDC.Command) -> Int {
let max = self.prefs.integer(forKey: "max-\(command.rawValue)-\(self.identifier)")
return max == 0 ? 100 : max
return min(self.DDC_HARD_MAX_LIMIT, max == 0 ? self.DDC_HARD_MAX_LIMIT : max)
}
func getRestoreValue(for command: DDC.Command) -> Int {
@ -316,13 +405,8 @@ class ExternalDisplay: Display {
return isSmallIncrement ? 1 : Int(floor(Float(self.getMaxValue(for: command)) / OSDUtils.chicletCount))
}
override func showOsd(command: DDC.Command, value: Int, maxValue _: Int = 100, roundChiclet: Bool = false) {
super.showOsd(command: command, value: value, maxValue: self.getMaxValue(for: command), roundChiclet: roundChiclet)
}
private func supportsMuteCommand() -> Bool {
// Monitors which don't support the mute command - e.g. Dell U3419W - will have a maximum value of 100 for the DDC mute command
return self.getMaxValue(for: .audioMuteScreenBlank) == 2
override func showOsd(command: DDC.Command, value: Int, maxValue _: Int = 100, roundChiclet: Bool = false, lock: Bool = false) {
super.showOsd(command: command, value: value, maxValue: self.getMaxValue(for: command), roundChiclet: roundChiclet, lock: lock)
}
private func playVolumeChangedSound() {

View file

@ -5,7 +5,7 @@
// Created by Joni Van Roost on 24/01/2020.
// Copyright © 2020 MonitorControl. All rights reserved.
//
// Most of the code in this file was sourced from:
// Some of the code in this file was sourced from:
// https://github.com/fnesveda/ExternalDisplayBrightness
// all credit goes to @fnesveda
@ -15,9 +15,9 @@ class InternalDisplay: Display {
// the queue for dispatching display operations, so they're not performed directly and concurrently
private var displayQueue: DispatchQueue
override init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?) {
override init(_ identifier: CGDirectDisplayID, name: String, vendorNumber: UInt32?, modelNumber: UInt32?, isVirtual: Bool = false) {
self.displayQueue = DispatchQueue(label: String("displayQueue-\(identifier)"))
super.init(identifier, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber)
super.init(identifier, name: name, vendorNumber: vendorNumber, modelNumber: modelNumber, isVirtual: isVirtual)
}
func calcNewBrightness(isUp: Bool, isSmallIncrement: Bool) -> Float {
@ -30,56 +30,17 @@ class InternalDisplay: Display {
}
public func getBrightness() -> Float {
self.displayQueue.sync {
Float(type(of: self).CoreDisplayGetUserBrightness?(self.identifier) ?? 0.5)
}
var brightness: Float = 0
DisplayServicesGetBrightness(self.identifier, &brightness)
return brightness
}
override func stepBrightness(isUp: Bool, isSmallIncrement: Bool) {
let value = self.calcNewBrightness(isUp: isUp, isSmallIncrement: isSmallIncrement)
self.displayQueue.sync {
type(of: self).CoreDisplaySetUserBrightness?(self.identifier, Double(value))
type(of: self).DisplayServicesBrightnessChanged?(self.identifier, Double(value))
DisplayServicesSetBrightness(self.identifier, Float(value))
DisplayServicesBrightnessChanged(self.identifier, Double(value))
self.showOsd(command: .brightness, value: Int(value * 64), maxValue: 64)
}
}
// notifies the system that the brightness of a specified display has changed (to update System Preferences etc.)
// unfortunately Apple doesn't provide a public API for this, so we have to manually extract the function from the DisplayServices framework
private static var DisplayServicesBrightnessChanged: ((CGDirectDisplayID, Double) -> Void)? {
let displayServicesPath = CFURLCreateWithString(kCFAllocatorDefault, "/System/Library/PrivateFrameworks/DisplayServices.framework" as CFString, nil)
if let displayServicesBundle = CFBundleCreate(kCFAllocatorDefault, displayServicesPath) {
if let funcPointer = CFBundleGetFunctionPointerForName(displayServicesBundle, "DisplayServicesBrightnessChanged" as CFString) {
typealias DSBCFunctionType = @convention(c) (UInt32, Double) -> Void
return unsafeBitCast(funcPointer, to: DSBCFunctionType.self)
}
}
return nil
}
// reads the brightness of a display through the CoreDisplay framework
// unfortunately Apple doesn't provide a public API for this, so we have to manually extract the function from the CoreDisplay framework
private static var CoreDisplayGetUserBrightness: ((CGDirectDisplayID) -> Double)? {
let coreDisplayPath = CFURLCreateWithString(kCFAllocatorDefault, "/System/Library/Frameworks/CoreDisplay.framework" as CFString, nil)
if let coreDisplayBundle = CFBundleCreate(kCFAllocatorDefault, coreDisplayPath) {
if let funcPointer = CFBundleGetFunctionPointerForName(coreDisplayBundle, "CoreDisplay_Display_GetUserBrightness" as CFString) {
typealias CDGUBFunctionType = @convention(c) (UInt32) -> Double
return unsafeBitCast(funcPointer, to: CDGUBFunctionType.self)
}
}
return nil
}
// sets the brightness of a display through the CoreDisplay framework
// unfortunately Apple doesn't provide a public API for this, so we have to manually extract the function from the CoreDisplay framework
private static var CoreDisplaySetUserBrightness: ((CGDirectDisplayID, Double) -> Void)? {
let coreDisplayPath = CFURLCreateWithString(kCFAllocatorDefault, "/System/Library/Frameworks/CoreDisplay.framework" as CFString, nil)
if let coreDisplayBundle = CFBundleCreate(kCFAllocatorDefault, coreDisplayPath) {
if let funcPointer = CFBundleGetFunctionPointerForName(coreDisplayBundle, "CoreDisplay_Display_SetUserBrightness" as CFString) {
typealias CDSUBFunctionType = @convention(c) (UInt32, Double) -> Void
return unsafeBitCast(funcPointer, to: CDSUBFunctionType.self)
}
}
return nil
}
}

View file

@ -0,0 +1,277 @@
//
// Arm64DDCUitls.swift
// MonitorControl
//
// Created by @waydabber, 2021
// Copyright © 2021. MonitorControl. All rights reserved.
//
import Foundation
import IOKit
class Arm64DDCUtils: NSObject {
public struct DisplayService {
var displayID: CGDirectDisplayID = 0
var service: IOAVService?
var serviceLocation: Int = 0
var isDiscouraged: Bool = false
}
#if arch(arm64)
public static let isArm64: Bool = true
#else
public static let isArm64: Bool = false
#endif
// This matches Displays to the right IOAVService
public static func getServiceMatches(displayIDs: [CGDirectDisplayID]) -> [DisplayService] {
let ioregServicesForMatching = self.getIoregServicesForMatching()
var matchedDisplayServices: [DisplayService] = []
var scoredCandidateDisplayServices: [Int: [DisplayService]] = [:]
for displayID in displayIDs {
for ioregServiceForMatching in ioregServicesForMatching {
let score = self.ioregMatchScore(displayID: displayID, ioregEdidUUID: ioregServiceForMatching.edidUUID, ioregProductName: ioregServiceForMatching.productName, ioregSerialNumber: ioregServiceForMatching.serialNumber, serviceLocation: ioregServiceForMatching.serviceLocation)
let isDiscouraged = self.checkIfDiscouraged(ioregService: ioregServiceForMatching)
let displayService = DisplayService(displayID: displayID, service: ioregServiceForMatching.service, serviceLocation: ioregServiceForMatching.serviceLocation, isDiscouraged: isDiscouraged)
if scoredCandidateDisplayServices[score] == nil {
scoredCandidateDisplayServices[score] = []
}
scoredCandidateDisplayServices[score]?.append(displayService)
}
}
var takenServiceLocations: [Int] = []
var takenDisplayIDs: [CGDirectDisplayID] = []
for score in stride(from: self.MAX_MATCH_SCORE, to: 0, by: -1) {
if let scoredCandidateDisplayService = scoredCandidateDisplayServices[score] {
for candidateDisplayService in scoredCandidateDisplayService {
if !(takenDisplayIDs.contains(candidateDisplayService.displayID) || takenServiceLocations.contains(candidateDisplayService.serviceLocation)) {
takenDisplayIDs.append(candidateDisplayService.displayID)
takenServiceLocations.append(candidateDisplayService.serviceLocation)
matchedDisplayServices.append(candidateDisplayService)
}
}
}
}
return matchedDisplayServices
}
// Perform DDC read
public static func read(service: IOAVService?, command: UInt8, tries: UInt8 = 3, minReplyDelay: UInt32 = 10000) -> (current: UInt16, max: UInt16)? {
var values: (UInt16, UInt16)?
var send: [UInt8] = [command]
var reply = [UInt8](repeating: 0, count: 11)
if Arm64DDCUtils.performDDCCommunication(service: service, send: &send, reply: &reply, readSleepTime: minReplyDelay, numOfRetryAttemps: tries) {
let max = UInt16(reply[6]) * 256 + UInt16(reply[7])
let current = UInt16(reply[8]) * 256 + UInt16(reply[9])
values = (current, max)
} else {
values = nil
}
return values
}
// Perform DDC write
public static func write(service: IOAVService?, command: UInt8, value: UInt16) -> Bool {
var send: [UInt8] = [command, UInt8(value >> 8), UInt8(value & 255)]
var reply: [UInt8] = []
return Arm64DDCUtils.performDDCCommunication(service: service, send: &send, reply: &reply)
}
// Performs DDC read or write
public static func performDDCCommunication(service: IOAVService?, send: inout [UInt8], reply: inout [UInt8], writeSleepTime: UInt32 = 10000, numofWriteCycles: UInt8 = 2, readSleepTime: UInt32 = 10000, numOfRetryAttemps: UInt8 = 3, retrySleepTime: UInt32 = 20000) -> Bool {
var success: Bool = false
guard service != nil else {
return success
}
var checkedsend: [UInt8] = [UInt8(0x80 | (send.count + 1)), UInt8(send.count)] + send + [0]
checkedsend[checkedsend.count - 1] = Utils.checksum(chk: send.count == 1 ? 0x6E : 0x6E ^ 0x51, data: &checkedsend, start: 0, end: checkedsend.count - 2)
for _ in 1 ... numOfRetryAttemps {
for _ in 1 ... numofWriteCycles {
usleep(writeSleepTime)
if IOAVServiceWriteI2C(service, 0x37, 0x51, &checkedsend, UInt32(checkedsend.count)) == 0 {
success = true
}
}
if reply.count > 0 {
usleep(readSleepTime)
if IOAVServiceReadI2C(service, 0x37, 0x51, &reply, UInt32(reply.count)) == 0 {
if Utils.checksum(chk: 0x50, data: &reply, start: 0, end: reply.count - 2) == reply[reply.count - 1] {
success = true
} else {
success = false
}
}
}
if success {
return success
}
usleep(retrySleepTime)
}
return success
}
// -------
private struct IOregService {
var edidUUID: String = ""
var manufacturerID: String = ""
var productName: String = ""
var serialNumber: Int64 = 0
var location: String = ""
var transportUpstream: String = ""
var transportDownstream: String = ""
var service: IOAVService?
var serviceLocation: Int = 0
}
private static let MAX_MATCH_SCORE: Int = 13
// Scores the likelihood of a display match based on EDID UUID, ProductName and SerialNumber from in ioreg, compared to DisplayCreateInfoDictionary.
private static func ioregMatchScore(displayID: CGDirectDisplayID, ioregEdidUUID: String, ioregProductName: String = "", ioregSerialNumber: Int64 = 0, serviceLocation: Int = 0) -> Int {
var matchScore: Int = 0
if let dictionary = (CoreDisplay_DisplayCreateInfoDictionary(displayID))?.takeRetainedValue() as NSDictionary? {
if let kDisplayYearOfManufacture = dictionary[kDisplayYearOfManufacture] as? Int64, let kDisplayWeekOfManufacture = dictionary[kDisplayWeekOfManufacture] as? Int64, let kDisplayVendorID = dictionary[kDisplayVendorID] as? Int64, let kDisplayProductID = dictionary[kDisplayProductID] as? Int64, let kDisplayVerticalImageSize = dictionary[kDisplayVerticalImageSize] as? Int64, let kDisplayHorizontalImageSize = dictionary[kDisplayHorizontalImageSize] as? Int64 {
struct KeyLoc {
var key: String
var loc: Int
}
let edidUUIDSearchKeys: [KeyLoc] = [
// Vendor ID
KeyLoc(key: String(format: "%04x", UInt16(max(0, min(kDisplayVendorID, 256 * 256 - 1)))).uppercased(), loc: 0),
// Product ID
KeyLoc(key: String(format: "%02x", UInt8((UInt16(max(0, min(kDisplayProductID, 256 * 256 - 1))) >> (0 * 8)) & 0xFF)).uppercased()
+ String(format: "%02x", UInt8((UInt16(max(0, min(kDisplayProductID, 256 * 256 - 1))) >> (1 * 8)) & 0xFF)).uppercased(), loc: 4),
// Manufacture date
KeyLoc(key: String(format: "%02x", UInt8(max(0, min(kDisplayWeekOfManufacture, 256 - 1)))).uppercased()
+ String(format: "%02x", UInt8(max(0, min(kDisplayYearOfManufacture - 1990, 256 - 1)))).uppercased(), loc: 19),
// Image size
KeyLoc(key: String(format: "%02x", UInt8(max(0, min(kDisplayHorizontalImageSize / 10, 256 - 1)))).uppercased()
+ String(format: "%02x", UInt8(max(0, min(kDisplayVerticalImageSize / 10, 256 - 1)))).uppercased(), loc: 30),
]
for searchKey in edidUUIDSearchKeys where searchKey.key != "0000" && searchKey.key == ioregEdidUUID.prefix(searchKey.loc + 4).suffix(4) {
matchScore += 2
}
}
if ioregProductName != "", let nameList = dictionary["DisplayProductName"] as? [String: String], let name = nameList["en_US"] ?? nameList.first?.value, name.lowercased() == ioregProductName.lowercased() {
matchScore += 2
}
if ioregSerialNumber != 0, let serial = dictionary[kDisplaySerialNumber] as? Int64, serial == ioregSerialNumber {
matchScore += 2
}
if serviceLocation == displayID {
matchScore += 1
}
}
return matchScore
}
// Iterate to the next AppleCLCD2 or DCPAVServiceProxy item in the ioreg tree and return the name and corresponding service
private static func ioregIterateToNextObjectOfInterest(interests _: [String], iterator: inout io_iterator_t) -> (name: String, service: io_service_t)? {
var objectName: String = ""
var service: io_service_t = IO_OBJECT_NULL
let name = UnsafeMutablePointer<CChar>.allocate(capacity: MemoryLayout<io_name_t>.size)
defer {
name.deallocate()
}
while true {
service = IOIteratorNext(iterator)
guard service != MACH_PORT_NULL else {
service = IO_OBJECT_NULL
break
}
guard IORegistryEntryGetName(service, name) == KERN_SUCCESS else {
service = IO_OBJECT_NULL
break
}
if String(cString: name) == "AppleCLCD2" || String(cString: name) == "DCPAVServiceProxy" {
objectName = String(cString: name)
return (objectName, service)
}
}
return nil
}
// Returns EDID UUDI, Product Name and Serial Number in an IOregService if it is found using the provided io_service_t pointing to a AppleCDC2 item in the ioreg tree
private static func getIORegServiceAppleCDC2Properties(service: io_service_t) -> IOregService {
var ioregService = IOregService()
if let unmanagedEdidUUID = IORegistryEntryCreateCFProperty(service, CFStringCreateWithCString(kCFAllocatorDefault, "EDID UUID", kCFStringEncodingASCII), kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively)), let edidUUID = unmanagedEdidUUID.takeRetainedValue() as? String {
ioregService.edidUUID = edidUUID
}
if let unmanagedDisplayAttrs = IORegistryEntryCreateCFProperty(service, CFStringCreateWithCString(kCFAllocatorDefault, "DisplayAttributes", kCFStringEncodingASCII), kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively)), let displayAttrs = unmanagedDisplayAttrs.takeRetainedValue() as? NSDictionary, let productAttrs = displayAttrs.value(forKey: "ProductAttributes") as? NSDictionary {
if let manufacturerID = productAttrs.value(forKey: "ManufacturerID") as? String {
ioregService.manufacturerID = manufacturerID
}
if let productName = productAttrs.value(forKey: "ProductName") as? String {
ioregService.productName = productName
}
if let serialNumber = productAttrs.value(forKey: "SerialNumber") as? Int64 {
ioregService.serialNumber = serialNumber
}
}
if let unmanagedTransport = IORegistryEntryCreateCFProperty(service, CFStringCreateWithCString(kCFAllocatorDefault, "Transport", kCFStringEncodingASCII), kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively)), let transport = unmanagedTransport.takeRetainedValue() as? NSDictionary {
if let upstream = transport.value(forKey: "Upstream") as? String {
ioregService.transportUpstream = upstream
}
if let downstream = transport.value(forKey: "Downstream") as? String {
ioregService.transportDownstream = downstream
}
}
return ioregService
}
// Sets up the service in an IOregService if it is found using the provided io_service_t pointing to a DCPAVServiceProxy item in the ioreg tree
private static func setIORegServiceDCPAVServiceProxy(service: io_service_t, ioregService: inout IOregService) {
if let unmanagedLocation = IORegistryEntryCreateCFProperty(service, CFStringCreateWithCString(kCFAllocatorDefault, "Location", kCFStringEncodingASCII), kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively)), let location = unmanagedLocation.takeRetainedValue() as? String {
ioregService.location = location
if location == "External" {
ioregService.service = IOAVServiceCreateWithService(kCFAllocatorDefault, service)?.takeRetainedValue() as IOAVService
}
}
}
// Returns IOAVSerivces with associated display properties for matching logic
private static func getIoregServicesForMatching() -> [IOregService] {
var serviceLocation: Int = 0
var ioregServicesForMatching: [IOregService] = []
let ioregRoot: io_registry_entry_t = IORegistryGetRootEntry(kIOMasterPortDefault)
var iterator = io_iterator_t()
var ioregService = IOregService()
guard IORegistryEntryCreateIterator(ioregRoot, "IOService", IOOptionBits(kIORegistryIterateRecursively), &iterator) == KERN_SUCCESS else {
return ioregServicesForMatching
}
while true {
if let objectOfInterest = ioregIterateToNextObjectOfInterest(interests: ["AppleCLCD2", "DCPAVServiceProxy"], iterator: &iterator) {
if objectOfInterest.name == "AppleCLCD2", objectOfInterest.service != IO_OBJECT_NULL {
ioregService = self.getIORegServiceAppleCDC2Properties(service: objectOfInterest.service)
serviceLocation += 1
ioregService.serviceLocation = serviceLocation
}
if objectOfInterest.name == "DCPAVServiceProxy", objectOfInterest.service != IO_OBJECT_NULL {
self.setIORegServiceDCPAVServiceProxy(service: objectOfInterest.service, ioregService: &ioregService)
ioregServicesForMatching.append(ioregService)
}
} else {
break
}
}
return ioregServicesForMatching
}
// Check if it is problematic to enable DDC on the display
private static func checkIfDiscouraged(ioregService: IOregService) -> Bool {
var modelIdentifier: String = ""
let platformExpertDevice = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"))
if let modelData = IORegistryEntryCreateCFProperty(platformExpertDevice, "model" as CFString, kCFAllocatorDefault, 0).takeRetainedValue() as? Data, let modelIdentifierCString = String(data: modelData, encoding: .utf8)?.cString(using: .utf8) {
modelIdentifier = String(cString: modelIdentifierCString)
}
// This is a well known dummy plug (not a real display) but it breaks DDC communication on M1
if ioregService.manufacturerID == "AOC", ioregService.productName == "28E850" {
return true
}
// First service location of Mac Mini HDMI is broken for DDC communication
if ioregService.transportDownstream == "HDMI", ioregService.serviceLocation == 1, modelIdentifier == "Macmini9,1" {
return true
}
return false
}
}

View file

@ -1,4 +1,48 @@
#pragma once
#import <Foundation/Foundation.h>
#import <OSD/OSDManager.h>
#import <IOKit/i2c/IOI2CInterface.h>
#import <CoreGraphics/CoreGraphics.h>
typedef CFTypeRef IOAVService;
extern IOAVService IOAVServiceCreate(CFAllocatorRef allocator);
extern IOAVService IOAVServiceCreateWithService(CFAllocatorRef allocator, io_service_t service);
extern IOReturn IOAVServiceReadI2C(IOAVService service, uint32_t chipAddress, uint32_t offset, void* outputBuffer, uint32_t outputBufferSize);
extern IOReturn IOAVServiceWriteI2C(IOAVService service, uint32_t chipAddress, uint32_t dataAddress, void* inputBuffer, uint32_t inputBufferSize);
extern CFDictionaryRef CoreDisplay_DisplayCreateInfoDictionary(CGDirectDisplayID);
extern void DisplayServicesBrightnessChanged(CGDirectDisplayID display, double brightness);
extern int DisplayServicesGetBrightness(CGDirectDisplayID display, float *brightness);
extern int DisplayServicesSetBrightness(CGDirectDisplayID display, float brightness);
@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
@class NSXPCConnection;
@interface OSDManager : NSObject <OSDUIHelperProtocol>
{
id <OSDUIHelperProtocol> _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 <OSDUIHelperProtocol> remoteObjectProxy; // @dynamic remoteObjectProxy;
@end

View file

@ -22,4 +22,17 @@ class OSDUtils: NSObject {
static func getDistance(fromNearestChiclet chiclet: Float) -> Float {
return abs(chiclet.rounded(.towardZero) - chiclet)
}
static func showOSDLockOnAllDisplays(osdImage: Int64) {
var displayCount: UInt32 = 0
var onlineDisplays = [CGDirectDisplayID](repeating: 0, count: Int(16))
if CGGetOnlineDisplayList(16, &onlineDisplays, &displayCount) == CGError.success {
let displayIDs = onlineDisplays.prefix(Int(displayCount))
for id in displayIDs {
if let manager = OSDManager.sharedManager() as? OSDManager {
manager.showImage(osdImage, onDisplayID: id, priority: 0x1F4, msecUntilFade: 1000, filledChiclets: 0, totalChiclets: 100, locked: true)
}
}
}
}
}

View file

@ -14,25 +14,48 @@ class Utils: NSObject {
/// - command: Command (Brightness/Volume/...)
/// - title: Title of the slider
/// - Returns: An `NSSlider` slider
static func addSliderMenuItem(toMenu menu: NSMenu, forDisplay display: ExternalDisplay, command: DDC.Command, title: String) -> SliderHandler {
static func addSliderMenuItem(toMenu menu: NSMenu, forDisplay display: ExternalDisplay, command: DDC.Command, title: String, numOfTickMarks: Int = 0) -> SliderHandler {
let item = NSMenuItem()
let handler = SliderHandler(display: display, command: command)
let slider = NSSlider(value: 0, minValue: 0, maxValue: 100, target: handler, action: #selector(SliderHandler.valueChanged))
slider.isEnabled = false
slider.frame.size.width = 180
slider.frame.origin = NSPoint(x: 20, y: 5)
handler.slider = slider
let view = NSView(frame: NSRect(x: 0, y: 0, width: slider.frame.width + 30, height: slider.frame.height + 10))
view.addSubview(slider)
item.view = view
menu.insertItem(item, at: 0)
menu.insertItem(withTitle: title, action: nil, keyEquivalent: "", at: 0)
if #available(macOS 11.0, *) {
slider.frame.size.width = 160
slider.frame.origin = NSPoint(x: 35, y: 5)
let view = NSView(frame: NSRect(x: 0, y: 0, width: slider.frame.width + 47, height: slider.frame.height + 14))
view.frame.origin = NSPoint(x: 12, y: 0)
var iconName: String = "circle.dashed"
switch command {
case .audioSpeakerVolume: iconName = "speaker.wave.2"
case .brightness: iconName = "sun.max"
case .contrast: iconName = "circle.lefthalf.fill"
default: break
}
let icon = NSImageView(image: NSImage(systemSymbolName: iconName, accessibilityDescription: title)!)
icon.frame = view.frame
icon.wantsLayer = true
icon.alphaValue = 0.7
icon.imageAlignment = NSImageAlignment.alignLeft
view.addSubview(icon)
view.addSubview(slider)
item.view = view
menu.insertItem(item, at: 0)
} else {
slider.frame.size.width = 180
slider.frame.origin = NSPoint(x: 15, y: 5)
let view = NSView(frame: NSRect(x: 0, y: 0, width: slider.frame.width + 30, height: slider.frame.height + 10))
let sliderHeaderItem = NSMenuItem()
let attrs: [NSAttributedString.Key: Any] = [.foregroundColor: NSColor.systemGray, .font: NSFont.systemFont(ofSize: 12)]
sliderHeaderItem.attributedTitle = NSAttributedString(string: title, attributes: attrs)
view.addSubview(slider)
item.view = view
menu.insertItem(item, at: 0)
menu.insertItem(sliderHeaderItem, at: 0)
}
var values: (UInt16, UInt16)?
let delay = display.needsLongerDelay ? UInt64(40 * kMillisecondScale) : nil
@ -40,23 +63,31 @@ class Utils: NSObject {
let tries = UInt(display.getPollingCount())
os_log("Polling %{public}@ times", type: .info, String(tries))
if tries != 0 {
values = display.readDDCValues(for: command, tries: tries, minReplyDelay: delay)
}
var (currentValue, maxValue) = (UInt16(0), UInt16(0))
let (currentDDCValue, maxValue) = values ?? (UInt16(display.getValue(for: command)), UInt16(display.getMaxValue(for: command)))
display.saveValue(Int(currentDDCValue), for: command)
display.saveMaxValue(Int(maxValue), for: command)
os_log("%{public}@ (%{public}@):", type: .info, display.name, String(reflecting: command))
os_log(" - current ddc value: %{public}@ - from display? %{public}@", type: .info, String(currentDDCValue), String(values != nil))
os_log(" - maximum ddc value: %{public}@ - from display? %{public}@", type: .info, String(maxValue), String(values != nil))
if command != .audioSpeakerVolume {
slider.integerValue = Int(currentDDCValue)
slider.maxValue = Double(maxValue)
if display.isSw(), command == DDC.Command.brightness {
(currentValue, maxValue) = (UInt16(display.getSwBrightnessPrefValue()), UInt16(display.getSwMaxBrightness()))
} else {
if tries != 0 {
values = display.readDDCValues(for: command, tries: tries, minReplyDelay: delay)
}
(currentValue, maxValue) = values ?? (UInt16(display.getValue(for: command)), 0) // We set 0 for max. value to indicate that there is no real DDC reported max. value - ExternalDisplay.getMaxValue() will return 100 in case of 0 max. values.
}
display.saveMaxValue(Int(maxValue), for: command)
display.saveValue(min(Int(currentValue), display.getMaxValue(for: command)), for: command) // We won't allow currrent value to be higher than the max. value
os_log("%{public}@ (%{public}@):", type: .info, display.name, String(reflecting: command))
os_log(" - current value: %{public}@ - from display? %{public}@", type: .info, String(currentValue), String(values != nil))
os_log(" - maximum value: %{public}@ - from display? %{public}@", type: .info, String(display.getMaxValue(for: command)), String(values != nil))
if command == .brightness {
if !display.isSw(), prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) {
slider.maxValue = Double(display.getMaxValue(for: command) * 2)
slider.integerValue = Int(slider.maxValue) / 2 + Int(currentValue)
} else {
slider.integerValue = Int(currentValue)
slider.maxValue = Double(display.getMaxValue(for: command))
}
} else if command == .audioSpeakerVolume {
// If we're looking at the audio speaker volume, also retrieve the values for the mute command
var muteValues: (current: UInt16, max: UInt16)?
@ -80,14 +111,18 @@ class Utils: NSObject {
// If the system is not currently muted, or doesn't support the mute command, display the current volume as the slider value
if muteValues == nil || muteValues!.current == 2 {
slider.integerValue = Int(currentDDCValue)
slider.integerValue = Int(currentValue)
} else {
slider.integerValue = 0
}
slider.maxValue = Double(maxValue)
slider.maxValue = Double(display.getMaxValue(for: command))
} else {
slider.integerValue = Int(currentValue)
slider.maxValue = Double(display.getMaxValue(for: command))
}
slider.numberOfTickMarks = numOfTickMarks
slider.isEnabled = true
return handler
}
@ -133,6 +168,22 @@ class Utils: NSObject {
}
}
static func checksum(chk: UInt8, data: inout [UInt8], start: Int, end: Int) -> UInt8 {
var chkd: UInt8 = chk
for i in start ... end {
chkd ^= data[i]
}
return chkd
}
static func alert(text: String) {
let alert = NSAlert()
alert.messageText = text
alert.alertStyle = NSAlert.Style.informational
alert.addButton(withTitle: "OK")
alert.runModal()
}
// MARK: - Enums
/// UserDefault Keys for the app prefs
@ -143,14 +194,23 @@ class Utils: NSObject {
/// Does the app start when plugged to an external monitor
case startWhenExternal
/// Hide menu icon
case hideMenuIcon
/// Keys listened for (Brightness/Volume)
case listenFor
/// Show contrast sliders
case showContrast
/// Lower contrast after brightness
case lowerContrast
/// Show volume sliders
case showVolume
/// Lower via software after brightness
case lowerSwAfterBrightness
/// Fallback to software control for external displays with no DDC
case fallbackSw
/// Change Brightness/Volume for all screens
case allScreens
@ -163,6 +223,9 @@ class Utils: NSObject {
/// Used for notification when displays are updated in DisplayManager
case displayListUpdate
/// Show advanced options under Displays tab in Preferences
case showAdvancedDisplays
}
/// Keys for the value of listenFor option

View file

@ -1,5 +1,8 @@
/* Shown in the main prefs window */
"Advanced" = "Erweitert";
/* Shown in the main prefs window */
"About" = "About";
/* Apple Silicon designation (shown after the version number in Preferences) */
"Apple Silicon" = "Apple Silicon";
/* Shown in the alert dialog */
"Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure." = "Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure.";
@ -13,53 +16,77 @@
/* Build */
"Build" = "Build";
/* Shown in the Display Preferences */
"Built-in Display" = "Built-in Display";
/* Shown in menu */
"Contrast" = "Kontrast";
/* Shown in menu */
"Default" = "Standard";
/* Version */
"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, ";
/* Shown in the main prefs window */
"Display" = "Monitor";
"Displays" = "Displays";
/* Shown in the alert dialog */
"Enable Longer Delay?" = "Enable Longer Delay?";
/* Shown in the Display Preferences */
"External Display" = "External Display";
/* Shown in the main prefs window */
"General" = "Allgemein";
/* Shown in the main prefs window */
"Keys" = "Tasten";
/* Shown in the Display Preferences */
"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)";
/* Shown in the Display Preferences */
"Hardware (DDC)" = "Hardware (DDC)";
/* Intel designation (shown after the version number in Preferences) */
"Intel" = "Intel";
/* Shown in the alert dialog */
"No" = "No";
/* Shown in the Display Preferences */
"No Control Available" = "No Control Available";
/* Shown in menu */
"No supported display found" = "Kein unterstützter Monitor angeschlossen";
/* Shown in the alert dialog */
"Ok" = "OK";
/* Shown in Preferences window */
"Preferences" = "Einstellungen";
/* Shown in the Display Preferences */
"Other Display" = "Other Display";
/* Shown in the alert dialog */
"Reset Preferences?" = "Reset Preferences?";
/* Shown in menu */
"Set as default" = "Als Standard festlegen";
/* Shown in the alert dialog */
"Shortcuts not available" = "Kurzbefehle nicht verfügbar";
/* Shown in the Display Preferences */
"Software (Forced)" = "Software (Forced)";
/* Shown in the Display Preferences */
"Software Only" = "Software Only";
/* unknown display name
unknown model
unknown vendor */
"Unknown" = "Unbekannt";
/* Shown in the Display Preferences */
"Unspecified" = "Unspecified";
/* Version */
"Version" = "Version";
/* Shown in the Display Preferences */
"Virtual Display" = "Virtual Display";
/* Shown in menu */
"Volume" = "Lautstärke";

View file

@ -1,5 +1,8 @@
/* Shown in the main prefs window */
"Advanced" = "Advanced";
"About" = "About";
/* Apple Silicon designation (shown after the version number in Preferences) */
"Apple Silicon" = "Apple Silicon";
/* Shown in the alert dialog */
"Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure." = "Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure.";
@ -7,59 +10,81 @@
/* Shown in the alert dialog */
"Are you sure you want to reset all preferences?" = "Are you sure you want to reset all preferences?";
/* Sown in menu */
/* Shown in menu */
"Brightness" = "Brightness";
/* Build */
"Build" = "Build";
/* Shown in the Display Preferences */
"Built-in Display" = "Built-in Display";
/* Shown in menu */
"Contrast" = "Contrast";
/* Shown in menu */
"Default" = "Default";
/* Version */
"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, ";
/* No comment provided by engineer. */
"Display" = "Display";
/* Shown in the main prefs window */
"Displays" = "Displays";
/* Shown in the alert dialog */
"Enable Longer Delay?" = "Enable Longer Delay?";
/* Shown in the Display Preferences */
"External Display" = "External Display";
/* Shown in the main prefs window */
"General" = "General";
/* Shown in the main prefs window */
"Keys" = "Keys";
/* Shown in the Display Preferences */
"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)";
/* Shown in the Display Preferences */
"Hardware (DDC)" = "Hardware (DDC)";
/* Intel designation (shown after the version number in Preferences) */
"Intel" = "Intel";
/* Shown in the alert dialog */
"No" = "No";
/* Shown in the Display Preferences */
"No Control Available" = "No Control Available";
/* Shown in menu */
"No supported display found" = "No supported display found";
/* Shown in the alert dialog */
"Ok" = "Ok";
/* Shown in Preferences window */
"Preferences" = "Preferences";
/* Shown in the Display Preferences */
"Other Display" = "Other Display";
/* Shown in the alert dialog */
"Reset Preferences?" = "Reset Preferences?";
/* Shown in menu */
"Set as default" = "Set as default";
/* Shown in the alert dialog */
"Shortcuts not available" = "Shortcuts not available";
/* Unknown display name
Unknown model
Unknown vendor */
/* Shown in the Display Preferences */
"Software (Forced)" = "Software (Forced)";
/* Shown in the Display Preferences */
"Software Only" = "Software Only";
/* Unknown display name */
"Unknown" = "Unknown";
/* Shown in the Display Preferences */
"Unspecified" = "Unspecified";
/* Version */
"Version" = "Version";
/* Shown in the Display Preferences */
"Virtual Display" = "Virtual Display";
/* Shown in menu */
"Volume" = "Volume";

View file

@ -1,5 +1,8 @@
/* Shown in the main prefs window */
"Advanced" = "Advanced";
"About" = "About";
/* Apple Silicon designation (shown after the version number in Preferences) */
"Apple Silicon" = "Apple Silicon";
/* Shown in the alert dialog */
"Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure." = "Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure.";
@ -13,53 +16,77 @@
/* Build */
"Build" = "Build";
/* Shown in the Display Preferences */
"Built-in Display" = "Built-in Display";
/* Shown in menu */
"Contrast" = "Contraste";
/* Shown in menu */
"Default" = "Écran par défaut";
/* Version */
"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, ";
/* No comment provided by engineer. */
"Display" = "Écrans";
/* Shown in the main prefs window */
"Displays" = "Displays";
/* Shown in the alert dialog */
"Enable Longer Delay?" = "Enable Longer Delay?";
/* Shown in the Display Preferences */
"External Display" = "External Display";
/* Shown in the main prefs window */
"General" = "Général";
/* Shown in the main prefs window */
"Keys" = "Touches";
/* Shown in the Display Preferences */
"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)";
/* Shown in the Display Preferences */
"Hardware (DDC)" = "Hardware (DDC)";
/* Intel designation (shown after the version number in Preferences) */
"Intel" = "Intel";
/* Shown in the alert dialog */
"No" = "No";
/* Shown in the Display Preferences */
"No Control Available" = "No Control Available";
/* Shown in menu */
"No supported display found" = "Aucun écran supporté trouvé";
/* Shown in the alert dialog */
"Ok" = "Ok";
/* Shown in Preferences window */
"Preferences" = "Préférences";
/* Shown in the Display Preferences */
"Other Display" = "Other Display";
/* Shown in the alert dialog */
"Reset Preferences?" = "Reset Preferences?";
/* Shown in menu */
"Set as default" = "Enregistrer comme écran par défaut";
/* Shown in the alert dialog */
"Shortcuts not available" = "Raccourcis non disponible";
/* Shown in the Display Preferences */
"Software (Forced)" = "Software (Forced)";
/* Shown in the Display Preferences */
"Software Only" = "Software Only";
/* Unknown display name
Unknown model
Unknown vendor */
"Unknown" = "Inconnu";
/* Shown in the Display Preferences */
"Unspecified" = "Unspecified";
/* Version */
"Version" = "Version";
/* Shown in the Display Preferences */
"Virtual Display" = "Virtual Display";
/* Shown in menu */
"Volume" = "Volume";

View file

@ -0,0 +1,97 @@
/* Shown in the main prefs window */
"About" = "Névjegy";
/* Apple Silicon designation (shown after the version number in Preferences) */
"Apple Silicon" = "Apple Silicon";
/* Shown in the alert dialog */
"Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure." = "Biztos benne, hogy engedélyezni kívánja a hosszabb várakozást? Ez bizonyos esetekben a rendszer lefagyását eredményezheti, akár újraindítás is szükségessé válhat. A bejelentkezéskori automatikus indítást letiltjuk a biztonság kedvéért.";
/* Shown in the alert dialog */
"Are you sure you want to reset all preferences?" = "Biztos benne, hogy vissza kívánja állítani az alapértelmezett beállításokat?";
/* Sown in menu */
"Brightness" = "Fényerő";
/* Build */
"Build" = "Build";
/* Shown in the Display Preferences */
"Built-in Display" = "Built-in Display";
/* Shown in menu */
"Contrast" = "Kontraszt";
/* Version */
"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, ";
/* Shown in the main prefs window */
"Displays" = "Kijelzők";
/* Shown in the alert dialog */
"Enable Longer Delay?" = "Hosszabb várakozás engedélyezése?";
/* Shown in the Display Preferences */
"External Display" = "External Display";
/* Shown in the main prefs window */
"General" = "Általános";
/* Shown in the Display Preferences */
"Hardware (CoreDisplay)" = "Hardver (CoreDisplay)";
/* Shown in the Display Preferences */
"Hardware (DDC)" = "Hardver (DDC)";
/* Intel designation (shown after the version number in Preferences) */
"Intel" = "Intel";
/* Shown in the alert dialog */
"No" = "Nem";
/* Shown in the Display Preferences */
"No Control Available" = "Nincs vezérlés";
/* Shown in menu */
"No supported display found" = "Nincs támogatott kijelző";
/* Shown in the alert dialog */
"Ok" = "Ok";
/* Shown in the Display Preferences */
"Other Display" = "Egyéb kijelző";
/* Shown in the alert dialog */
"Reset Preferences?" = "Alapértelmezett beállítások";
/* Shown in the alert dialog */
"Shortcuts not available" = "Gyorsbillentyűk nem elérhetők";
/* Shown in the Display Preferences */
"Software (Forced)" = "Szoftveres";
/* Shown in the Display Preferences */
"Software Only" = "Csak szoftveres";
/* Unknown display name
Unknown model
Unknown vendor */
"Unknown" = "Ismeretlen";
/* Shown in the Display Preferences */
"Unspecified" = "Meghatározatlan";
/* Version */
"Version" = "Verzió";
/* Shown in the Display Preferences */
"Virtual Display" = "Virtuális kijelző";
/* Shown in menu */
"Volume" = "Hangerő";
/* Shown in the alert dialog */
"Yes" = "Igen";
/* Shown in the alert dialog */
"You need to enable MonitorControl in System Preferences > Security and Privacy > Accessibility for the keyboard shortcuts to work" = "Engedélyeznie kell a MonitorControlt a Rendszerbeállítások > Biztonság és adatvédelem > Kisegítő lehetőségek alatt a gyorsbillentyűk használatához!";

View file

@ -1,5 +1,8 @@
/* Shown in the main prefs window */
"Advanced" = "Advanced";
"About" = "About";
/* Apple Silicon designation (shown after the version number in Preferences) */
"Apple Silicon" = "Apple Silicon";
/* Shown in the alert dialog */
"Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure." = "Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure.";
@ -13,53 +16,77 @@
/* Build */
"Build" = "Build";
/* Shown in the Display Preferences */
"Built-in Display" = "Built-in Display";
/* Shown in menu */
"Contrast" = "Contrasto";
/* Shown in menu */
"Default" = "Predefinito";
/* Version */
"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, ";
/* No comment provided by engineer. */
"Display" = "Monitor";
/* Shown in the main prefs window */
"Displays" = "Displays";
/* Shown in the alert dialog */
"Enable Longer Delay?" = "Enable Longer Delay?";
/* Shown in the Display Preferences */
"External Display" = "External Display";
/* Shown in the main prefs window */
"General" = "Generale";
/* Shown in the main prefs window */
"Keys" = "Tasti";
/* Shown in the Display Preferences */
"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)";
/* Shown in the Display Preferences */
"Hardware (DDC)" = "Hardware (DDC)";
/* Intel designation (shown after the version number in Preferences) */
"Intel" = "Intel";
/* Shown in the alert dialog */
"No" = "No";
/* Shown in the Display Preferences */
"No Control Available" = "No Control Available";
/* Shown in menu */
"No supported display found" = "Nessuno schermo supportato è stato trovato";
/* Shown in the alert dialog */
"Ok" = "Ok";
/* Shown in Preferences window */
"Preferences" = "Preferenze";
/* Shown in the Display Preferences */
"Other Display" = "Other Display";
/* Shown in the alert dialog */
"Reset Preferences?" = "Reset Preferences?";
/* Shown in menu */
"Set as default" = "Imposta come default";
/* Shown in the alert dialog */
"Shortcuts not available" = "Comandi rapidi non disponibili";
/* Shown in the Display Preferences */
"Software (Forced)" = "Software (Forced)";
/* Shown in the Display Preferences */
"Software Only" = "Software Only";
/* Unknown display name
Unknown model
Unknown vendor */
"Unknown" = "Sconosciuto";
/* Shown in the Display Preferences */
"Unspecified" = "Unspecified";
/* Version */
"Version" = "Versione";
/* Shown in the Display Preferences */
"Virtual Display" = "Virtual Display";
/* Shown in menu */
"Volume" = "Volume";

View file

@ -1,5 +1,8 @@
/* Shown in the main prefs window */
"Advanced" = "詳細設定";
/* Shown in the main prefs window */
"About" = "About";
/* Apple Silicon designation (shown after the version number in Preferences) */
"Apple Silicon" = "Apple Silicon";
/* Shown in the alert dialog */
"Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure." = "Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure.";
@ -13,53 +16,77 @@
/* Build */
"Build" = "ビルド";
/* Shown in the Display Preferences */
"Built-in Display" = "Built-in Display";
/* Shown in menu */
"Contrast" = "コントラスト";
/* Shown in menu */
"Default" = "デフォルト";
/* Version */
"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, ";
/* No comment provided by engineer. */
"Display" = "ディスプレイ";
/* Shown in the main prefs window */
"Displays" = "Displays";
/* Shown in the alert dialog */
"Enable Longer Delay?" = "Enable Longer Delay?";
/* Shown in the Display Preferences */
"External Display" = "External Display";
/* Shown in the main prefs window */
"General" = "一般";
/* Shown in the main prefs window */
"Keys" = "キー";
/* Shown in the Display Preferences */
"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)";
/* Shown in the Display Preferences */
"Hardware (DDC)" = "Hardware (DDC)";
/* Intel designation (shown after the version number in Preferences) */
"Intel" = "Intel";
/* Shown in the alert dialog */
"No" = "No";
/* Shown in the Display Preferences */
"No Control Available" = "No Control Available";
/* Shown in menu */
"No supported display found" = "サポートされていないディスプレイが検知されました";
/* Shown in the alert dialog */
"Ok" = "OK";
/* Shown in Preferences window */
"Preferences" = "環境設定";
/* Shown in the Display Preferences */
"Other Display" = "Other Display";
/* Shown in the alert dialog */
"Reset Preferences?" = "Reset Preferences?";
/* Shown in menu */
"Set as default" = "デフォルトとして設定";
/* Shown in the alert dialog */
"Shortcuts not available" = "ショートカットキーを使用できません";
/* Shown in the Display Preferences */
"Software (Forced)" = "Software (Forced)";
/* Shown in the Display Preferences */
"Software Only" = "Software Only";
/* Unknown display name
Unknown model
Unknown vendor */
"Unknown" = "不明";
/* Shown in the Display Preferences */
"Unspecified" = "Unspecified";
/* Version */
"Version" = "バージョン";
/* Shown in the Display Preferences */
"Virtual Display" = "Virtual Display";
/* Shown in menu */
"Volume" = "音量";

View file

@ -1,5 +1,8 @@
/* Shown in the main prefs window */
"Advanced" = "Zaawansowane";
"About" = "About";
/* Apple Silicon designation (shown after the version number in Preferences) */
"Apple Silicon" = "Apple Silicon";
/* Shown in the alert dialog */
"Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure." = "Czy na pewno chcesz ustawić większe opóźnienie? Może to skutkować zawieszeniem systemu i koniecznością restartu. Uruchamianie programu podczas logowania zostanie wyłączone.";
@ -13,53 +16,77 @@
/* Build */
"Build" = "Kompilacja";
/* Shown in the Display Preferences */
"Built-in Display" = "Built-in Display";
/* Shown in menu */
"Contrast" = "Kontrast";
/* Shown in menu */
"Default" = "Domyślnie";
/* Version */
"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, ";
/* No comment provided by engineer. */
"Display" = "Wyświetlacz";
/* Shown in the main prefs window */
"Displays" = "Displays";
/* Shown in the alert dialog */
"Enable Longer Delay?" = "Enable Longer Delay?";
/* Shown in the Display Preferences */
"External Display" = "External Display";
/* Shown in the main prefs window */
"General" = "Ogólne";
/* Shown in the main prefs window */
"Keys" = "Klawisze";
/* Shown in the Display Preferences */
"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)";
/* Shown in the Display Preferences */
"Hardware (DDC)" = "Hardware (DDC)";
/* Intel designation (shown after the version number in Preferences) */
"Intel" = "Intel";
/* Shown in the alert dialog */
"No" = "Nie";
/* Shown in the Display Preferences */
"No Control Available" = "No Control Available";
/* Shown in menu */
"No supported display found" = "Nie znaleziono obsługiwanego wyświetlacza";
/* Shown in the alert dialog */
"Ok" = "Ok";
/* Shown in Preferences window */
"Preferences" = "Preferencje";
/* Shown in the Display Preferences */
"Other Display" = "Other Display";
/* Shown in the alert dialog */
"Reset Preferences?" = "Reset Preferences?";
/* Shown in menu */
"Set as default" = "Ustaw jako domyślne";
/* Shown in the alert dialog */
"Shortcuts not available" = "Skróty klawiszowe niedostępne";
/* Shown in the Display Preferences */
"Software (Forced)" = "Software (Forced)";
/* Shown in the Display Preferences */
"Software Only" = "Software Only";
/* Unknown display name
Unknown model
Unknown vendor */
"Unknown" = "Nieznany";
/* Shown in the Display Preferences */
"Unspecified" = "Unspecified";
/* Version */
"Version" = "Wersja";
/* Shown in the Display Preferences */
"Virtual Display" = "Virtual Display";
/* Shown in menu */
"Volume" = "Głośność";

View file

@ -1,5 +1,8 @@
/* Shown in the main prefs window */
"Advanced" = "Дополнительные";
/* Shown in the main prefs window */
"About" = "About";
/* Apple Silicon designation (shown after the version number in Preferences) */
"Apple Silicon" = "Apple Silicon";
/* Shown in the alert dialog */
"Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure." = "Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure.";
@ -13,53 +16,77 @@
/* Build */
"Build" = "Сборка";
/* Shown in the Display Preferences */
"Built-in Display" = "Built-in Display";
/* Shown in menu */
"Contrast" = "Контрастность";
/* Shown in menu */
"Default" = "По умолчанию";
/* Version */
"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, ";
/* No comment provided by engineer. */
"Display" = "Мониторы";
/* Shown in the main prefs window */
"Displays" = "Displays";
/* Shown in the alert dialog */
"Enable Longer Delay?" = "Enable Longer Delay?";
/* Shown in the Display Preferences */
"External Display" = "External Display";
/* Shown in the main prefs window */
"General" = "Основные";
/* Shown in the main prefs window */
"Keys" = "Сочетания клавиш";
/* Shown in the Display Preferences */
"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)";
/* Shown in the Display Preferences */
"Hardware (DDC)" = "Hardware (DDC)";
/* Intel designation (shown after the version number in Preferences) */
"Intel" = "Intel";
/* Shown in the alert dialog */
"No" = "No";
/* Shown in the Display Preferences */
"No Control Available" = "No Control Available";
/* Shown in menu */
"No supported display found" = "Поддерживаемых мониторов не найдено";
/* Shown in the alert dialog */
"Ok" = "ОК";
/* Shown in Preferences window */
"Preferences" = "Настройки";
/* Shown in the Display Preferences */
"Other Display" = "Other Display";
/* Shown in the alert dialog */
"Reset Preferences?" = "Reset Preferences?";
/* Shown in menu */
"Set as default" = "Сделать основным";
/* Shown in the alert dialog */
"Shortcuts not available" = "Сочетания клавиш недоступны";
/* Shown in the Display Preferences */
"Software (Forced)" = "Software (Forced)";
/* Shown in the Display Preferences */
"Software Only" = "Software Only";
/* Unknown display name
Unknown model
Unknown vendor */
"Unknown" = "Неизвестный";
/* Shown in the Display Preferences */
"Unspecified" = "Unspecified";
/* Version */
"Version" = "Версия";
/* Shown in the Display Preferences */
"Virtual Display" = "Virtual Display";
/* Shown in menu */
"Volume" = "Громкость";

View file

@ -1,5 +1,8 @@
/* Shown in the main prefs window */
"Advanced" = "Розширені";
/* Shown in the main prefs window */
"About" = "About";
/* Apple Silicon designation (shown after the version number in Preferences) */
"Apple Silicon" = "Apple Silicon";
/* Shown in the alert dialog */
"Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure." = "Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure.";
@ -13,53 +16,77 @@
/* Build */
"Build" = "Білд";
/* Shown in the Display Preferences */
"Built-in Display" = "Built-in Display";
/* Shown in menu */
"Contrast" = "Контраст";
/* Shown in menu */
"Default" = "Стандартне";
/* Version */
"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, ";
/* No comment provided by engineer. */
"Display" = "Дісплей";
/* Shown in the main prefs window */
"Displays" = "Displays";
/* Shown in the alert dialog */
"Enable Longer Delay?" = "Enable Longer Delay?";
/* Shown in the Display Preferences */
"External Display" = "External Display";
/* Shown in the main prefs window */
"General" = "Загальні";
/* Shown in the main prefs window */
"Keys" = "Клавіші";
/* Shown in the Display Preferences */
"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)";
/* Shown in the Display Preferences */
"Hardware (DDC)" = "Hardware (DDC)";
/* Intel designation (shown after the version number in Preferences) */
"Intel" = "Intel";
/* Shown in the alert dialog */
"No" = "No";
/* Shown in the Display Preferences */
"No Control Available" = "No Control Available";
/* Shown in menu */
"No supported display found" = "Не знайдено жодного дісплею";
/* Shown in the alert dialog */
"Ok" = "ОК";
/* Shown in Preferences window */
"Preferences" = "Налаштування";
/* Shown in the Display Preferences */
"Other Display" = "Other Display";
/* Shown in the alert dialog */
"Reset Preferences?" = "Reset Preferences?";
/* Shown in menu */
"Set as default" = "Вибрати за-умовчанням";
/* Shown in the alert dialog */
"Shortcuts not available" = "Скорочення недоступні";
/* Shown in the Display Preferences */
"Software (Forced)" = "Software (Forced)";
/* Shown in the Display Preferences */
"Software Only" = "Software Only";
/* Unknown display name
Unknown model
Unknown vendor */
"Unknown" = "Невідомо";
/* Shown in the Display Preferences */
"Unspecified" = "Unspecified";
/* Version */
"Version" = "Версія";
/* Shown in the Display Preferences */
"Virtual Display" = "Virtual Display";
/* Shown in menu */
"Volume" = "Гучність";

View file

@ -1,5 +1,8 @@
/* Shown in the main prefs window */
"Advanced" = "进阶设置";
/* Shown in the main prefs window */
"About" = "About";
/* Apple Silicon designation (shown after the version number in Preferences) */
"Apple Silicon" = "Apple Silicon";
/* Shown in the alert dialog */
"Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure." = "Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure.";
@ -13,53 +16,77 @@
/* Build */
"Build" = "Build";
/* Shown in the Display Preferences */
"Built-in Display" = "Built-in Display";
/* Shown in menu */
"Contrast" = "对比度";
/* Shown in menu */
"Default" = "默认";
/* Version */
"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, ";
/* No comment provided by engineer. */
"Display" = "显示器";
/* Shown in the main prefs window */
"Displays" = "Displays";
/* Shown in the alert dialog */
"Enable Longer Delay?" = "Enable Longer Delay?";
/* Shown in the Display Preferences */
"External Display" = "External Display";
/* Shown in the main prefs window */
"General" = "通用";
/* Shown in the main prefs window */
"Keys" = "快捷键";
/* Shown in the Display Preferences */
"Hardware (CoreDisplay)" = "Hardware (CoreDisplay)";
/* Shown in the Display Preferences */
"Hardware (DDC)" = "Hardware (DDC)";
/* Intel designation (shown after the version number in Preferences) */
"Intel" = "Intel";
/* Shown in the alert dialog */
"No" = "No";
/* Shown in the Display Preferences */
"No Control Available" = "No Control Available";
/* Shown in menu */
"No supported display found" = "未发现支持的显示器";
/* Shown in the alert dialog */
"Ok" = "Ok";
/* Shown in Preferences window */
"Preferences" = "偏好设置";
/* Shown in the Display Preferences */
"Other Display" = "Other Display";
/* Shown in the alert dialog */
"Reset Preferences?" = "Reset Preferences?";
/* Shown in menu */
"Set as default" = "设为默认";
/* Shown in the alert dialog */
"Shortcuts not available" = "快捷键不可用";
/* Shown in the Display Preferences */
"Software (Forced)" = "Software (Forced)";
/* Shown in the Display Preferences */
"Software Only" = "Software Only";
/* Unknown display name
Unknown model
Unknown vendor */
"Unknown" = "Unknown";
/* Shown in the Display Preferences */
"Unspecified" = "Unspecified";
/* Version */
"Version" = "Version";
/* Shown in the Display Preferences */
"Virtual Display" = "Virtual Display";
/* Shown in menu */
"Volume" = "音量";

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="18122" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19150" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="18122"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19150"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">

View file

@ -1,21 +0,0 @@
import Cocoa
import os.log
class ButtonCellView: NSTableCellView {
@IBOutlet var button: NSButton!
var display: Display?
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
}
@IBAction func buttonToggled(_ sender: NSButton) {
if let display = display {
let isEnabled = sender.state == .on
display.isEnabled = isEnabled
#if DEBUG
os_log("Toggle enabled display state: %{public}@", type: .info, isEnabled ? "on" : "off")
#endif
}
}
}

View file

@ -1,32 +0,0 @@
import Cocoa
import os.log
class FriendlyNameCellView: NSTableCellView {
var display: Display?
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
}
@IBAction func valueChanged(_ sender: NSTextFieldCell) {
if let display = display {
let newValue = sender.stringValue
let originalValue = display.getFriendlyName()
if newValue.isEmpty {
self.textField?.stringValue = originalValue
return
}
if newValue != originalValue,
!newValue.isEmpty
{
display.setFriendlyName(newValue)
NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.friendlyName.rawValue), object: nil)
#if DEBUG
os_log("Value changed for friendly name: %{public}@", type: .info, "from `\(originalValue)` to `\(newValue)`")
#endif
}
}
}
}

View file

@ -1,25 +0,0 @@
import Cocoa
import os.log
class HideOsdCellView: NSTableCellView {
@IBOutlet var button: NSButton!
var display: ExternalDisplay?
let prefs = UserDefaults.standard
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
}
@IBAction func buttonToggled(_ sender: NSButton) {
if let display = display {
switch sender.state {
case .on:
display.hideOsd = true
case .off:
display.hideOsd = false
default:
break
}
}
}
}

View file

@ -1,41 +0,0 @@
import Cocoa
import os.log
class LongerDelayCellView: NSTableCellView {
@IBOutlet var button: NSButton!
var display: ExternalDisplay?
let prefs = UserDefaults.standard
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
}
@IBAction func buttonToggled(_ sender: NSButton) {
if let display = self.display {
switch sender.state {
case .on:
let alert = NSAlert()
alert.messageText = NSLocalizedString("Enable Longer Delay?", comment: "Shown in the alert dialog")
alert.informativeText = NSLocalizedString("Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure.", comment: "Shown in the alert dialog")
alert.addButton(withTitle: NSLocalizedString("Yes", comment: "Shown in the alert dialog"))
alert.addButton(withTitle: NSLocalizedString("No", comment: "Shown in the alert dialog"))
alert.alertStyle = NSAlert.Style.critical
if let window = self.window {
alert.beginSheetModal(for: window, completionHandler: { modalResponse in
if modalResponse == NSApplication.ModalResponse.alertFirstButtonReturn {
Utils.setStartAtLogin(enabled: false)
display.needsLongerDelay = true
} else {
sender.state = .off
}
})
}
case .off:
display.needsLongerDelay = false
default:
break
}
}
}
}

View file

@ -1,25 +0,0 @@
import Cocoa
import os.log
class PollingCountCellView: NSTableCellView {
var display: ExternalDisplay?
@IBAction func valueChanged(_ sender: NSTextField) {
if let display = display {
let newValue = sender.stringValue
let originalValue = "\(display.getPollingCount())"
if newValue.isEmpty {
self.textField?.stringValue = originalValue
}
if newValue != originalValue,
!newValue.isEmpty,
let newValue = Int(newValue)
{
display.setPollingCount(newValue)
os_log("Value changed for polling count: %{public}@", type: .info, "from `\(originalValue)` to `\(newValue)`")
}
}
}
}

View file

@ -1,31 +0,0 @@
import Cocoa
import os.log
/*
menu tags:
0: none
1: minimal
2: normal
3: heavy
4: custom
We use these tags as a way to mark selection
*/
class PollingModeCellView: NSTableCellView {
var display: ExternalDisplay?
@IBOutlet var pollingModeMenu: NSPopUpButtonCell!
var didChangePollingMode: ((_ pollingModeInt: Int) -> Void)?
@IBAction func valueChanged(_ sender: NSPopUpButton) {
if let display = display {
let newValue = sender.selectedTag()
let originalValue = display.getPollingMode()
if newValue != originalValue {
display.setPollingMode(newValue)
self.didChangePollingMode?(newValue)
os_log("Value changed for polling count: %{public}@", type: .info, "from `\(originalValue)` to `\(newValue)`")
}
}
}
}

View file

@ -12,6 +12,9 @@ class SliderHandler {
}
@objc func valueChanged(slider: NSSlider) {
guard app.sleepID == 0, app.reconfigureID == 0 else {
return
}
let snapInterval = 25
let snapThreshold = 3
@ -28,17 +31,27 @@ class SliderHandler {
self.display.toggleMute(fromVolumeSlider: true)
}
// If the command is to adjust brightness, also instruct the display to set the contrast value, if necessary
if self.cmd == .brightness {
self.display.setContrastValueForBrightness(value)
if !self.display.isSw() {
if self.cmd == DDC.Command.brightness, prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) {
var brightnessDDCValue: Int = 0
var brightnessSwValue: Int = 100
if value >= Int(slider.maxValue / 2) {
brightnessDDCValue = slider.integerValue - Int(slider.maxValue / 2)
brightnessSwValue = Int(self.display.getSwMaxBrightness())
} else {
brightnessDDCValue = 0
brightnessSwValue = Int((Float(value) / Float(slider.maxValue / 2)) * Float(self.display.getSwMaxBrightness()))
}
_ = self.display.writeDDCValues(command: self.cmd, value: UInt16(brightnessDDCValue))
_ = self.display.setSwBrightness(value: UInt8(brightnessSwValue))
self.display.saveValue(brightnessDDCValue, for: self.cmd)
} else {
_ = self.display.writeDDCValues(command: self.cmd, value: UInt16(value))
self.display.saveValue(value, for: self.cmd)
}
} else if self.cmd == DDC.Command.brightness {
_ = self.display.setSwBrightness(value: UInt8(value))
self.display.saveValue(value, for: self.cmd)
}
// If the command is to adjust contrast, erase the previous value for the contrast to restore after brightness is increased
if self.cmd == .contrast {
self.display.setRestoreValue(nil, for: .contrast)
}
_ = self.display.ddc?.write(command: self.cmd, value: UInt16(value))
self.display.saveValue(value, for: self.cmd)
}
}

View file

@ -1,83 +1,110 @@
/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */
"0Z7-PQ-Bl8.title" = "Helligkeit/Lautstärke für alle Monitore ändern";
/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */
"1PJ-14-Bvn.title" = "MonitorControl";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */
"4Pj-3t-PJr.title" = "Einstellungen zurücksetzen";
/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */
"95V-M4-2l5.title" = "Special thanks to our contributors!";
/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */
"8U8-ec-Zbv.headerCell.title" = "Aktiv";
/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */
"aXL-i8-S6R.title" = "Hide Menu Icon";
/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */
"CHc-s5-4MN.headerCell.title" = "Name";
/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */
"bkM-Px-U3b.title" = "Disable macOS volume OSD";
/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */
"BYS-7Y-bRz.title" = "Reset settings";
/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */
"bZq-0d-lJa.title" = "Enable Mute DDC command";
/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */
"c7N-cO-759.title" = "Keyboard:";
/* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */
"Cle-DD-vR7.title" = "Eigene";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */
"dgp-q7-cBK.headerCell.title" = "ID";
/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */
"Cln-uW-2dd.title" = "Website";
/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */
"dNl-I0-hcg.headerCell.title" = "Anzeigename";
/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */
"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!";
/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */
"dhP-eB-1L6.title" = "Show volume slider in menu";
/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */
"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens";
/* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */
"Eq3-z9-yIo.title" = "Minimal";
/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */
/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */
"f9g-8s-gdd.title" = "Reset Name";
/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */
"fhy-Er-0aI.title" = "Kontrast nach Helligkeit verringern";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */
"FoA-yh-Yx3.title" = "Aus";
/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */
"frw-j2-tE1.title" = "Warnung ⚠️\nDas Ändern dieser Einstellungen kann zum Einfrieren des Systems oder unerwartetem Verhalten führen.";
/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */
"grO-Kr-l4d.headerCell.title" = "Verzögerung";
/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */
"gxn-NH-Qhb.headerCell.title" = "Abfragemodus";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */
"H4a-c9-LcB.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */
"hdd-Zz-buN.title" = "Brightness control:";
/* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */
"hjz-0c-rvK.title" = "Helligkeit";
/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */
/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */
"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only.";
/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */
"j72-NF-zsW.title" = "MonitorControl beim login starten";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */
"JKW-oY-bSb.headerCell.title" = "ID";
/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */
"J77-r0-djA.title" = "Custom read polling count:";
/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */
"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume.";
/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */
"kMa-3q-udl.title" = "Enable software dimming if required";
/* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */
"kqn-gU-mZX.ibShadowedToolTip" = "Mehr Informationen";
/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */
"LRJ-fb-Z9E.headerCell.title" = "Hersteller";
/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */
"lSJ-6w-KJ2.title" = "Display type:";
/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */
"MPF-Mr-zVU.headerCell.title" = "ohne OSD";
/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */
"MJx-MK-e7D.title" = "Menu contents:";
/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */
"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead.";
/* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */
"NLP-dU-Dam.title" = "Lautstärke";
/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */
"Nvp-hI-w4x.headerCell.title" = "Modell";
/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */
"okD-DG-pYa.title" = "Application:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */
"PZ9-0Z-K6J.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */
"PaK-1f-DsW.title" = "Control method:";
/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */
"pF5-Sw-7BR.title" = "Longer delay during DDC read operations";
/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */
"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!";
/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */
"r7i-oG-Ab6.title" = "Advanced:";
/* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */
"Riq-uM-bTs.title" = "Normal";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */
"UBV-gO-AZz.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber";
/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */
"uoI-1J-RdD.headerCell.title" = "Anzeigename";
/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */
"Vh8-06-U3K.title" = "Hören auf";
/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */
"UqR-WE-jHl.title" = "Enable keyboard control for display";
/* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */
"vik-vN-bJe.title" = "Stark";
@ -85,32 +112,32 @@
/* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */
"Vr4-xb-B4o.title" = "Helligkeit & Lautstärke";
/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */
"vwm-hY-on5.title" = "DDC read polling mode:";
/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */
"Wnd-hx-Meb.title" = "Show advanced settings under Displays";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */
"X96-ny-lAP.title" = "None";
/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */
"xFw-if-3FU.headerCell.title" = "DDC";
/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */
/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */
"xSI-8W-Xd0.title" = "Slider für Kontrast anzeigen";
/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */
"ytT-up-Dhs.headerCell.title" = "Anzahl Abfragen";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */
"xY6-aw-o9u.title" = "Reset Preferences";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */
"2gr-xG-Byx.title" = "";
/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */
"Xz0-X0-rB4.title" = "Additional settings:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */
"afl-95-ZJl.title" = "";
/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */
"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only.";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */
"as0-t3-Aub.title" = "";
/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */
"YqZ-LS-YvR.title" = "Identifier:";
/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */
"mBs-6m-13Q.title" = "";
/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */
"ZdU-gV-V05.title" = "Use hardware DDC control";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */
"vkG-RF-Yne.title" = "";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */
"VPD-MR-IXg.title" = "";
/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */
"ZKk-ve-rS4.title" = "Donate";

View file

@ -1,83 +1,110 @@
/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */
"0Z7-PQ-Bl8.title" = "Change Brightness/Volume for all screens";
/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */
"1PJ-14-Bvn.title" = "MonitorControl";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */
"4Pj-3t-PJr.title" = "Reset Preferences";
/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */
"95V-M4-2l5.title" = "Special thanks to our contributors!";
/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */
"8U8-ec-Zbv.headerCell.title" = "Enabled";
/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */
"aXL-i8-S6R.title" = "Hide Menu Icon";
/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */
"CHc-s5-4MN.headerCell.title" = "Name";
/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */
"bkM-Px-U3b.title" = "Disable macOS volume OSD";
/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */
"BYS-7Y-bRz.title" = "Reset settings";
/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */
"bZq-0d-lJa.title" = "Enable Mute DDC command";
/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */
"c7N-cO-759.title" = "Keyboard:";
/* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */
"Cle-DD-vR7.title" = "Custom";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */
"dgp-q7-cBK.headerCell.title" = "ID";
/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */
"Cln-uW-2dd.title" = "Website";
/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */
"dNl-I0-hcg.headerCell.title" = "Display Name";
/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */
"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!";
/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */
"dhP-eB-1L6.title" = "Show volume slider in menu";
/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */
"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens";
/* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */
"Eq3-z9-yIo.title" = "Minimal";
/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */
"fhy-Er-0aI.title" = "Lower contrast after brightness";
/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */
"f9g-8s-gdd.title" = "Reset Name";
/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */
"fhy-Er-0aI.title" = "Further lower brightness via software dimming";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */
"FoA-yh-Yx3.title" = "None";
/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */
"frw-j2-tE1.title" = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. ";
/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */
"grO-Kr-l4d.headerCell.title" = "Longer Delay";
/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */
"gxn-NH-Qhb.headerCell.title" = "Polling Mode";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */
"H4a-c9-LcB.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */
"hdd-Zz-buN.title" = "Brightness control:";
/* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */
"hjz-0c-rvK.title" = "Brightness only";
/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */
"j72-NF-zsW.title" = "Start MonitorControl at login";
/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */
"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only.";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */
"JKW-oY-bSb.headerCell.title" = "ID";
/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */
"j72-NF-zsW.title" = "Start at Login";
/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */
"J77-r0-djA.title" = "Custom read polling count:";
/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */
"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume.";
/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */
"kMa-3q-udl.title" = "Enable software dimming if required";
/* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */
"kqn-gU-mZX.ibShadowedToolTip" = "More Info";
/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */
"LRJ-fb-Z9E.headerCell.title" = "Vendor";
/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */
"lSJ-6w-KJ2.title" = "Display type:";
/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */
"MPF-Mr-zVU.headerCell.title" = "Hide OSD";
/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */
"MJx-MK-e7D.title" = "Menu contents:";
/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */
"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead.";
/* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */
"NLP-dU-Dam.title" = "Volume only";
/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */
"Nvp-hI-w4x.headerCell.title" = "Model";
/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */
"okD-DG-pYa.title" = "Application:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */
"PZ9-0Z-K6J.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */
"PaK-1f-DsW.title" = "Control method:";
/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */
"pF5-Sw-7BR.title" = "Longer delay during DDC read operations";
/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */
"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!";
/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */
"r7i-oG-Ab6.title" = "Advanced:";
/* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */
"Riq-uM-bTs.title" = "Normal";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */
"UBV-gO-AZz.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek\n@JoniVR\n@waydabber";
/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */
"uoI-1J-RdD.headerCell.title" = "Display Name";
/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */
"Vh8-06-U3K.title" = "Listen for";
/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */
"UqR-WE-jHl.title" = "Enable keyboard control for display";
/* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */
"vik-vN-bJe.title" = "Heavy";
@ -85,32 +112,32 @@
/* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */
"Vr4-xb-B4o.title" = "Both Brightness & Volume";
/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */
"vwm-hY-on5.title" = "DDC read polling mode:";
/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */
"Wnd-hx-Meb.title" = "Show advanced settings under Displays";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */
"X96-ny-lAP.title" = "None";
/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */
"xFw-if-3FU.headerCell.title" = "DDC";
/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */
"xSI-8W-Xd0.title" = "Show contrast slider in menu";
/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */
"xSI-8W-Xd0.title" = "Show a slider for contrast";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */
"xY6-aw-o9u.title" = "Reset Preferences";
/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */
"ytT-up-Dhs.headerCell.title" = "Polling Count";
/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */
"Xz0-X0-rB4.title" = "Additional settings:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */
"2gr-xG-Byx.title" = "";
/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */
"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only.";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */
"afl-95-ZJl.title" = "";
/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */
"YqZ-LS-YvR.title" = "Identifier:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */
"as0-t3-Aub.title" = "";
/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */
"ZdU-gV-V05.title" = "Use hardware DDC control";
/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */
"mBs-6m-13Q.title" = "";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */
"vkG-RF-Yne.title" = "";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */
"VPD-MR-IXg.title" = "";
/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */
"ZKk-ve-rS4.title" = "Donate";

View file

@ -1,83 +1,110 @@
/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */
"0Z7-PQ-Bl8.title" = "Modifier Luminosité/Volume pour tous les écrans";
/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */
"1PJ-14-Bvn.title" = "MonitorControl";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */
"4Pj-3t-PJr.title" = "Reset Preferences";
/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */
"95V-M4-2l5.title" = "Special thanks to our contributors!";
/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */
"8U8-ec-Zbv.headerCell.title" = "Activé";
/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */
"aXL-i8-S6R.title" = "Hide Menu Icon";
/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */
"CHc-s5-4MN.headerCell.title" = "Nom de l'écran";
/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */
"bkM-Px-U3b.title" = "Disable macOS volume OSD";
/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */
"BYS-7Y-bRz.title" = "Reset settings";
/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */
"bZq-0d-lJa.title" = "Enable Mute DDC command";
/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */
"c7N-cO-759.title" = "Keyboard:";
/* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */
"Cle-DD-vR7.title" = "Custom";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */
"dgp-q7-cBK.headerCell.title" = "Identifiant";
/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */
"Cln-uW-2dd.title" = "Website";
/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */
"dNl-I0-hcg.headerCell.title" = "Display Name";
/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */
"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!";
/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */
"dhP-eB-1L6.title" = "Show volume slider in menu";
/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */
"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens";
/* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */
"Eq3-z9-yIo.title" = "Minimal";
/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */
/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */
"f9g-8s-gdd.title" = "Reset Name";
/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */
"fhy-Er-0aI.title" = "Diminuer le contraste après la luminosité";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */
"FoA-yh-Yx3.title" = "None";
/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */
"frw-j2-tE1.title" = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. ";
/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */
"grO-Kr-l4d.headerCell.title" = "Longer Delay";
/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */
"gxn-NH-Qhb.headerCell.title" = "Polling Mode";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */
"H4a-c9-LcB.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */
"hdd-Zz-buN.title" = "Brightness control:";
/* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */
"hjz-0c-rvK.title" = "Luminosité uniquement";
/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */
/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */
"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only.";
/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */
"j72-NF-zsW.title" = "Lancer MonitorControl au démarrage";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */
"JKW-oY-bSb.headerCell.title" = "ID";
/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */
"J77-r0-djA.title" = "Custom read polling count:";
/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */
"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume.";
/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */
"kMa-3q-udl.title" = "Enable software dimming if required";
/* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */
"kqn-gU-mZX.ibShadowedToolTip" = "More Info";
/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */
"LRJ-fb-Z9E.headerCell.title" = "Vendeur";
/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */
"lSJ-6w-KJ2.title" = "Display type:";
/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */
"MPF-Mr-zVU.headerCell.title" = "Hide OSD";
/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */
"MJx-MK-e7D.title" = "Menu contents:";
/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */
"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead.";
/* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */
"NLP-dU-Dam.title" = "Volume uniquement";
/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */
"Nvp-hI-w4x.headerCell.title" = "Model";
/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */
"okD-DG-pYa.title" = "Application:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */
"PZ9-0Z-K6J.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */
"PaK-1f-DsW.title" = "Control method:";
/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */
"pF5-Sw-7BR.title" = "Longer delay during DDC read operations";
/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */
"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!";
/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */
"r7i-oG-Ab6.title" = "Advanced:";
/* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */
"Riq-uM-bTs.title" = "Normal";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */
"UBV-gO-AZz.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber";
/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */
"uoI-1J-RdD.headerCell.title" = "Nom d'affichage";
/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */
"Vh8-06-U3K.title" = "Écouter pour";
/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */
"UqR-WE-jHl.title" = "Enable keyboard control for display";
/* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */
"vik-vN-bJe.title" = "Heavy";
@ -85,32 +112,32 @@
/* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */
"Vr4-xb-B4o.title" = "Luminosité & Volume";
/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */
"vwm-hY-on5.title" = "DDC read polling mode:";
/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */
"Wnd-hx-Meb.title" = "Show advanced settings under Displays";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */
"X96-ny-lAP.title" = "None";
/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */
"xFw-if-3FU.headerCell.title" = "DDC";
/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */
/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */
"xSI-8W-Xd0.title" = "Afficher un slide pour le contraste";
/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */
"ytT-up-Dhs.headerCell.title" = "Polling Count";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */
"xY6-aw-o9u.title" = "Reset Preferences";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */
"2gr-xG-Byx.title" = "";
/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */
"Xz0-X0-rB4.title" = "Additional settings:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */
"afl-95-ZJl.title" = "";
/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */
"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only.";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */
"as0-t3-Aub.title" = "";
/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */
"YqZ-LS-YvR.title" = "Identifier:";
/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */
"mBs-6m-13Q.title" = "";
/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */
"ZdU-gV-V05.title" = "Use hardware DDC control";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */
"vkG-RF-Yne.title" = "";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */
"VPD-MR-IXg.title" = "";
/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */
"ZKk-ve-rS4.title" = "Donate";

View file

@ -0,0 +1,143 @@
/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */
"1PJ-14-Bvn.title" = "MonitorControl";
/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */
"95V-M4-2l5.title" = "Köszönjük mindenkinek, aki hozzájárult!";
/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */
"aXL-i8-S6R.title" = "Menü ikon elrejtése";
/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */
"bkM-Px-U3b.title" = "MacOS hangerő OSD tiltása";
/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */
"BYS-7Y-bRz.title" = "Visszaállítás";
/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */
"bZq-0d-lJa.title" = "DDC némítás parancs engedélyezése";
/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */
"c7N-cO-759.title" = "Billentyűzet:";
/* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */
"Cle-DD-vR7.title" = "Egyedi";
/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */
"Cln-uW-2dd.title" = "Weboldal";
/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */
"Cz1-Mh-llk.title" = "⚠️ Figyelem! Ezen beállítások változtatása veszélyeztetheti a rendszer stabilitását!";
/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */
"dhP-eB-1L6.title" = "Hangerő csúszka megjelenítése a menüben";
/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */
"E6M-ih-S8Y.title" = "Fényerő/hangerő módosítása az összes képernyőn";
/* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */
"Eq3-z9-yIo.title" = "Minimális";
/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */
"f9g-8s-gdd.title" = "Alaphelyzet";
/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */
"fhy-Er-0aI.title" = "Fényerő tovább csökkentése szoftveres sötétítéssel";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */
"FoA-yh-Yx3.title" = "Nincs";
/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */
"hdd-Zz-buN.title" = "Fényerő billentyűk:";
/* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */
"hjz-0c-rvK.title" = "Csak a fényerő billentyűk";
/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */
"iBZ-8c-JDY.title" = "Ezek a lehetőségek hardveresen (DDC) vezérelhető kijelzőkkel működnek.";
/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */
"j72-NF-zsW.title" = "Automatikus indítás bejelentkezéskor";
/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */
"J77-r0-djA.title" = "Olvasási próbálkozások:";
/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */
"K2r-aD-eec.title" = "A képernyő fényerejét és hangerejét az Apple Billentyűzet fényerő és hangerő gombjaival lehet szabályozni.";
/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */
"kMa-3q-udl.title" = "Átállás szoftveres sötétítésre, ha szükséges";
/* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */
"kqn-gU-mZX.ibShadowedToolTip" = "További információ";
/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */
"lSJ-6w-KJ2.title" = "Kijelző típusa:";
/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */
"MJx-MK-e7D.title" = "Menü tartalom:";
/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */
"n4V-jQ-1Ri.title" = "Szoftveres sötétítés használata, ha egy külső kijelzőt nem lehet vezérelni. Csak a fényerő szabályozás elérhető ilyen kijelzőknél.";
/* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */
"NLP-dU-Dam.title" = "Csak a hangerő billentyűk";
/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */
"okD-DG-pYa.title" = "Alkalmazás:";
/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */
"PaK-1f-DsW.title" = "Vezérlés:";
/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */
"pF5-Sw-7BR.title" = "Hosszabb várakozás DDC olvasáskor";
/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */
"PVE-y7-zIk.title" = "Ha rejtett, indítsa el újra az alkalmazást a beállítások megnyitásához!";
/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */
"r7i-oG-Ab6.title" = "Haladó:";
/* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */
"Riq-uM-bTs.title" = "Normál";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek\n@JoniVR\n@waydabber";
/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */
"UqR-WE-jHl.title" = "Vezérlés billentyűzetről";
/* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */
"vik-vN-bJe.title" = "Magas";
/* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */
"Vr4-xb-B4o.title" = "Fényerő és hangerő billentyűk";
/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */
"vwm-hY-on5.title" = "DDC olvasás mód:";
/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */
"Wnd-hx-Meb.title" = "Haladó beállítások a Kijelzők alatt";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */
"X96-ny-lAP.title" = "Nincs";
/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */
"xSI-8W-Xd0.title" = "Kontraszt csúszka megjelenítése a menüben";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */
"xY6-aw-o9u.title" = "Alaphelyzetbe állítás";
/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */
"Xz0-X0-rB4.title" = "Additional settings:";
/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */
"yeg-GN-SuO.title" = "A fényerő szoftveres csökkentése, ha a kijelző elérte a nulla fényerőt. A menü csúszkát is befolyásolja, 50% a váltóhatár. Csak hardveresen (DDC) vezérelhető kijelzőkkel működik.";
/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */
"YqZ-LS-YvR.title" = "Azonosító:";
/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */
"ZdU-gV-V05.title" = "Hardveres DDC vezérlés";
/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */
"ZKk-ve-rS4.title" = "Adakozás";

View file

@ -0,0 +1,5 @@
/* Class = "NSMenuItem"; title = "Quit"; ObjectID = "JTa-2I-AsI"; */
"JTa-2I-AsI.title" = "Kilépés";
/* Class = "NSMenuItem"; title = "Preferences..."; ObjectID = "SOS-eZ-uU5"; */
"SOS-eZ-uU5.title" = "Beállítások...";

View file

@ -1,83 +1,110 @@
/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */
"0Z7-PQ-Bl8.title" = "Modifica Luminosità/Volume per tutti i monitor";
/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */
"1PJ-14-Bvn.title" = "MonitorControl";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */
"4Pj-3t-PJr.title" = "Reset Preferences";
/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */
"95V-M4-2l5.title" = "Special thanks to our contributors!";
/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */
"8U8-ec-Zbv.headerCell.title" = "Abilitato";
/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */
"aXL-i8-S6R.title" = "Hide Menu Icon";
/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */
"CHc-s5-4MN.headerCell.title" = "Nome";
/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */
"bkM-Px-U3b.title" = "Disable macOS volume OSD";
/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */
"BYS-7Y-bRz.title" = "Reset settings";
/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */
"bZq-0d-lJa.title" = "Enable Mute DDC command";
/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */
"c7N-cO-759.title" = "Keyboard:";
/* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */
"Cle-DD-vR7.title" = "Custom";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */
"dgp-q7-cBK.headerCell.title" = "ID";
/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */
"Cln-uW-2dd.title" = "Website";
/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */
"dNl-I0-hcg.headerCell.title" = "Display Name";
/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */
"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!";
/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */
"dhP-eB-1L6.title" = "Show volume slider in menu";
/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */
"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens";
/* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */
"Eq3-z9-yIo.title" = "Minimal";
/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */
/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */
"f9g-8s-gdd.title" = "Reset Name";
/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */
"fhy-Er-0aI.title" = "Abbassa il contrasto dopo la luminosità";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */
"FoA-yh-Yx3.title" = "None";
/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */
"frw-j2-tE1.title" = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. ";
/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */
"grO-Kr-l4d.headerCell.title" = "Longer Delay";
/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */
"gxn-NH-Qhb.headerCell.title" = "Polling Mode";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */
"H4a-c9-LcB.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */
"hdd-Zz-buN.title" = "Brightness control:";
/* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */
"hjz-0c-rvK.title" = "Solo Luminosità";
/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */
/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */
"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only.";
/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */
"j72-NF-zsW.title" = "Avvia MonitorControl al login";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */
"JKW-oY-bSb.headerCell.title" = "ID";
/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */
"J77-r0-djA.title" = "Custom read polling count:";
/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */
"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume.";
/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */
"kMa-3q-udl.title" = "Enable software dimming if required";
/* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */
"kqn-gU-mZX.ibShadowedToolTip" = "More Info";
/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */
"LRJ-fb-Z9E.headerCell.title" = "Produttore";
/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */
"lSJ-6w-KJ2.title" = "Display type:";
/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */
"MPF-Mr-zVU.headerCell.title" = "Hide OSD";
/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */
"MJx-MK-e7D.title" = "Menu contents:";
/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */
"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead.";
/* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */
"NLP-dU-Dam.title" = "Solo Volume";
/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */
"Nvp-hI-w4x.headerCell.title" = "Modello";
/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */
"okD-DG-pYa.title" = "Application:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */
"PZ9-0Z-K6J.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */
"PaK-1f-DsW.title" = "Control method:";
/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */
"pF5-Sw-7BR.title" = "Longer delay during DDC read operations";
/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */
"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!";
/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */
"r7i-oG-Ab6.title" = "Advanced:";
/* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */
"Riq-uM-bTs.title" = "Normal";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */
"UBV-gO-AZz.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber";
/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */
"uoI-1J-RdD.headerCell.title" = "Nome assegnato";
/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */
"Vh8-06-U3K.title" = "Gestisci";
/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */
"UqR-WE-jHl.title" = "Enable keyboard control for display";
/* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */
"vik-vN-bJe.title" = "Heavy";
@ -85,32 +112,32 @@
/* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */
"Vr4-xb-B4o.title" = "Luminosità e Volume";
/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */
"vwm-hY-on5.title" = "DDC read polling mode:";
/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */
"Wnd-hx-Meb.title" = "Show advanced settings under Displays";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */
"X96-ny-lAP.title" = "None";
/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */
"xFw-if-3FU.headerCell.title" = "DDC";
/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */
/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */
"xSI-8W-Xd0.title" = "Mostra un selettore per il Contrasto";
/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */
"ytT-up-Dhs.headerCell.title" = "Polling Count";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */
"xY6-aw-o9u.title" = "Reset Preferences";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */
"2gr-xG-Byx.title" = "";
/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */
"Xz0-X0-rB4.title" = "Additional settings:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */
"afl-95-ZJl.title" = "";
/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */
"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only.";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */
"as0-t3-Aub.title" = "";
/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */
"YqZ-LS-YvR.title" = "Identifier:";
/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */
"mBs-6m-13Q.title" = "";
/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */
"ZdU-gV-V05.title" = "Use hardware DDC control";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */
"vkG-RF-Yne.title" = "";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */
"VPD-MR-IXg.title" = "";
/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */
"ZKk-ve-rS4.title" = "Donate";

View file

@ -1,116 +1,143 @@
/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */
"0Z7-PQ-Bl8.title" = "すべての画面の画面輝度と音量を変更する";
/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */
"1PJ-14-Bvn.title" = "MonitorControl";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */
"2gr-xG-Byx.title" = "Text Cell";
/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */
"95V-M4-2l5.title" = "Special thanks to our contributors!";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */
"4Pj-3t-PJr.title" = "初期設定に戻す";
/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */
"aXL-i8-S6R.title" = "Hide Menu Icon";
/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */
"8U8-ec-Zbv.headerCell.title" = "有効";
/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */
"bkM-Px-U3b.title" = "Disable macOS volume OSD";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */
"afl-95-ZJl.title" = "Text Cell";
/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */
"BYS-7Y-bRz.title" = "Reset settings";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */
"as0-t3-Aub.title" = "Text Cell";
/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */
"bZq-0d-lJa.title" = "Enable Mute DDC command";
/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */
"CHc-s5-4MN.headerCell.title" = "名称";
/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */
"c7N-cO-759.title" = "Keyboard:";
/* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */
"Cle-DD-vR7.title" = "カスタム";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */
"dgp-q7-cBK.headerCell.title" = "ID";
/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */
"Cln-uW-2dd.title" = "Website";
/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */
"dNl-I0-hcg.headerCell.title" = "ディスプレイの名称";
/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */
"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!";
/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */
"dhP-eB-1L6.title" = "Show volume slider in menu";
/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */
"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens";
/* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */
"Eq3-z9-yIo.title" = "低頻度";
/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */
/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */
"f9g-8s-gdd.title" = "Reset Name";
/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */
"fhy-Er-0aI.title" = "画面輝度変更後、コントラストを下げる";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */
"FoA-yh-Yx3.title" = "設定しない";
/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */
"frw-j2-tE1.title" = "⚠️ 注意 ⚠️\n下の設定を変更するとMacがフリーズしたり予期せぬ挙動になる場合があります。";
/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */
"grO-Kr-l4d.headerCell.title" = "遅延を長くする";
/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */
"gxn-NH-Qhb.headerCell.title" = "ポーリングモード";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */
"H4a-c9-LcB.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */
"hdd-Zz-buN.title" = "Brightness control:";
/* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */
"hjz-0c-rvK.title" = "画面輝度のみ";
/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */
/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */
"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only.";
/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */
"j72-NF-zsW.title" = "ログイン時にMonitorCoontrolを起動する";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */
"JKW-oY-bSb.headerCell.title" = "ID";
/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */
"J77-r0-djA.title" = "Custom read polling count:";
/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */
"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume.";
/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */
"kMa-3q-udl.title" = "Enable software dimming if required";
/* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */
"kqn-gU-mZX.ibShadowedToolTip" = "More Info";
/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */
"LRJ-fb-Z9E.headerCell.title" = "ベンダー";
/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */
"lSJ-6w-KJ2.title" = "Display type:";
/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */
"mBs-6m-13Q.title" = "バージョン 0.0.0 (ビルド 0)";
/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */
"MJx-MK-e7D.title" = "Menu contents:";
/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */
"MPF-Mr-zVU.headerCell.title" = "OSDを隠す";
/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */
"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead.";
/* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */
"NLP-dU-Dam.title" = "音量のみ";
/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */
"Nvp-hI-w4x.headerCell.title" = "モデル";
/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */
"okD-DG-pYa.title" = "Application:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */
"PZ9-0Z-K6J.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */
"PaK-1f-DsW.title" = "Control method:";
/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */
"pF5-Sw-7BR.title" = "Longer delay during DDC read operations";
/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */
"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!";
/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */
"r7i-oG-Ab6.title" = "Advanced:";
/* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */
"Riq-uM-bTs.title" = "普通";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */
"UBV-gO-AZz.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber";
/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */
"uoI-1J-RdD.headerCell.title" = "表示名 (クリックして変更)";
/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */
"Vh8-06-U3K.title" = "操作対象:";
/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */
"UqR-WE-jHl.title" = "Enable keyboard control for display";
/* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */
"vik-vN-bJe.title" = "高頻度";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */
"vkG-RF-Yne.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */
"VPD-MR-IXg.title" = "Text Cell";
/* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */
"Vr4-xb-B4o.title" = "画面輝度と音量";
/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */
"vwm-hY-on5.title" = "DDC read polling mode:";
/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */
"Wnd-hx-Meb.title" = "Show advanced settings under Displays";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */
"X96-ny-lAP.title" = "None";
/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */
"xFw-if-3FU.headerCell.title" = "DDC";
/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */
/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */
"xSI-8W-Xd0.title" = "コントラスト変更用のスライダーをメニューに表示する";
/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */
"ytT-up-Dhs.headerCell.title" = "ポーリングカウント";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */
"xY6-aw-o9u.title" = "Reset Preferences";
/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */
"Xz0-X0-rB4.title" = "Additional settings:";
/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */
"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only.";
/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */
"YqZ-LS-YvR.title" = "Identifier:";
/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */
"ZdU-gV-V05.title" = "Use hardware DDC control";
/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */
"ZKk-ve-rS4.title" = "Donate";

View file

@ -1,80 +1,110 @@
/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */
"0Z7-PQ-Bl8.title" = "Zmiana jasności/głośności dla wszystkich ekranów";
/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */
"1PJ-14-Bvn.title" = "MonitorControl";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */
"4Pj-3t-PJr.title" = "Resetowanie ustawień";
/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */
"95V-M4-2l5.title" = "Special thanks to our contributors!";
/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */
"8U8-ec-Zbv.headerCell.title" = "Aktywne";
/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */
"aXL-i8-S6R.title" = "Hide Menu Icon";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */
"as0-t3-Aub.title" = "Text Cell";
/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */
"bkM-Px-U3b.title" = "Disable macOS volume OSD";
/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */
"CHc-s5-4MN.headerCell.title" = "Nazwa";
/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */
"BYS-7Y-bRz.title" = "Reset settings";
/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */
"bZq-0d-lJa.title" = "Enable Mute DDC command";
/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */
"c7N-cO-759.title" = "Keyboard:";
/* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */
"Cle-DD-vR7.title" = "Niestandardowy";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */
"dgp-q7-cBK.headerCell.title" = "ID";
/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */
"Cln-uW-2dd.title" = "Website";
/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */
"dNl-I0-hcg.headerCell.title" = "Nazwa wyświetlacza";
/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */
"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!";
/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */
"dhP-eB-1L6.title" = "Show volume slider in menu";
/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */
"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens";
/* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */
"Eq3-z9-yIo.title" = "Minimalny";
/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */
/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */
"f9g-8s-gdd.title" = "Reset Name";
/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */
"fhy-Er-0aI.title" = "Obniż kontrast po jasności.";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */
"FoA-yh-Yx3.title" = "Nikt";
/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */
"frw-j2-tE1.title" = "Uwaga ⚠️\nZmiana niektórych z tych ustawień może spowodować zawieszenia systemu lub nieoczekiwane zachowanie.";
/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */
"grO-Kr-l4d.headerCell.title" = "Dłuższe opóźnienie";
/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */
"gxn-NH-Qhb.headerCell.title" = "Tryb odpytywania";
/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */
"hdd-Zz-buN.title" = "Brightness control:";
/* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */
"hjz-0c-rvK.title" = "Tylko jasność";
/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */
/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */
"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only.";
/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */
"j72-NF-zsW.title" = "Uruchamiaj MonitorContol podczas logowania";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */
"JKW-oY-bSb.headerCell.title" = "ID";
/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */
"J77-r0-djA.title" = "Custom read polling count:";
/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */
"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume.";
/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */
"kMa-3q-udl.title" = "Enable software dimming if required";
/* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */
"kqn-gU-mZX.ibShadowedToolTip" = "Więcej informacji";
/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */
"LRJ-fb-Z9E.headerCell.title" = "Producent";
/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */
"lSJ-6w-KJ2.title" = "Display type:";
/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */
"mBs-6m-13Q.title" = "Wersja 0.0.0 (Kompilacja 0)";
/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */
"MJx-MK-e7D.title" = "Menu contents:";
/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */
"MPF-Mr-zVU.headerCell.title" = "Schowaj OSD";
/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */
"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead.";
/* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */
"NLP-dU-Dam.title" = "Tylko głośność";
/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */
"Nvp-hI-w4x.headerCell.title" = "Model";
/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */
"okD-DG-pYa.title" = "Application:";
/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */
"PaK-1f-DsW.title" = "Control method:";
/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */
"pF5-Sw-7BR.title" = "Longer delay during DDC read operations";
/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */
"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!";
/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */
"r7i-oG-Ab6.title" = "Advanced:";
/* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */
"Riq-uM-bTs.title" = "Normalny";
/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */
"uoI-1J-RdD.headerCell.title" = "Przyjazna nazwa";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber";
/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */
"Vh8-06-U3K.title" = "Reaguj na";
/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */
"UqR-WE-jHl.title" = "Enable keyboard control for display";
/* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */
"vik-vN-bJe.title" = "Ciężki";
@ -82,35 +112,32 @@
/* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */
"Vr4-xb-B4o.title" = "Jasność i Głośność";
/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */
"vwm-hY-on5.title" = "DDC read polling mode:";
/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */
"Wnd-hx-Meb.title" = "Show advanced settings under Displays";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */
"X96-ny-lAP.title" = "Nic";
/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */
"xFw-if-3FU.headerCell.title" = "DDC";
/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */
/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */
"xSI-8W-Xd0.title" = "Pokaż suwak dla kontrastu";
/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */
"ytT-up-Dhs.headerCell.title" = "Licznik odpytań";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */
"xY6-aw-o9u.title" = "Reset Preferences";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */
"2gr-xG-Byx.title" = "";
/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */
"Xz0-X0-rB4.title" = "Additional settings:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */
"afl-95-ZJl.title" = "";
/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */
"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only.";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */
"H4a-c9-LcB.title" = "";
/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */
"YqZ-LS-YvR.title" = "Identifier:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */
"PZ9-0Z-K6J.title" = "";
/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */
"ZdU-gV-V05.title" = "Use hardware DDC control";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */
"UBV-gO-AZz.title" = "";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */
"vkG-RF-Yne.title" = "";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */
"VPD-MR-IXg.title" = "";
/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */
"ZKk-ve-rS4.title" = "Donate";

View file

@ -1,77 +1,110 @@
/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */
"0Z7-PQ-Bl8.title" = "Изменять Яркость/Громкость на всех мониторах";
/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */
"1PJ-14-Bvn.title" = "MonitorControl";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */
"4Pj-3t-PJr.title" = "Сброс настроек";
/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */
"95V-M4-2l5.title" = "Special thanks to our contributors!";
/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */
"8U8-ec-Zbv.headerCell.title" = "Включено";
/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */
"aXL-i8-S6R.title" = "Hide Menu Icon";
/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */
"CHc-s5-4MN.headerCell.title" = "Имя";
/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */
"bkM-Px-U3b.title" = "Disable macOS volume OSD";
/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */
"BYS-7Y-bRz.title" = "Reset settings";
/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */
"bZq-0d-lJa.title" = "Enable Mute DDC command";
/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */
"c7N-cO-759.title" = "Keyboard:";
/* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */
"Cle-DD-vR7.title" = "Другое";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */
"dgp-q7-cBK.headerCell.title" = "ID";
/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */
"Cln-uW-2dd.title" = "Website";
/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */
"dNl-I0-hcg.headerCell.title" = "Название монитора";
/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */
"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!";
/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */
"dhP-eB-1L6.title" = "Show volume slider in menu";
/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */
"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens";
/* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */
"Eq3-z9-yIo.title" = "Редко";
/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */
/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */
"f9g-8s-gdd.title" = "Reset Name";
/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */
"fhy-Er-0aI.title" = "Уменьшать контрастность после яркости";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */
"FoA-yh-Yx3.title" = "Нет";
/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */
"frw-j2-tE1.title" = "Внимание ⚠️\nИзменение некоторых из этих настроек может привести к зависанию системы или неожиданному поведению.";
/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */
"grO-Kr-l4d.headerCell.title" = "Длительный опрос";
/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */
"gxn-NH-Qhb.headerCell.title" = "Режим опроса";
/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */
"hdd-Zz-buN.title" = "Brightness control:";
/* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */
"hjz-0c-rvK.title" = "Только яркость";
/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */
/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */
"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only.";
/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */
"j72-NF-zsW.title" = "Запускать MonitorControl при входе в систему";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */
"JKW-oY-bSb.headerCell.title" = "ID";
/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */
"J77-r0-djA.title" = "Custom read polling count:";
/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */
"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume.";
/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */
"kMa-3q-udl.title" = "Enable software dimming if required";
/* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */
"kqn-gU-mZX.ibShadowedToolTip" = "Больше информации";
/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */
"LRJ-fb-Z9E.headerCell.title" = "Производитель";
/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */
"lSJ-6w-KJ2.title" = "Display type:";
/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */
"mBs-6m-13Q.title" = "Версия 0.0.0 (Сборка 0)";
/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */
"MJx-MK-e7D.title" = "Menu contents:";
/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */
"MPF-Mr-zVU.headerCell.title" = "Скрыть OSD";
/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */
"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead.";
/* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */
"NLP-dU-Dam.title" = "Только громкость";
/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */
"Nvp-hI-w4x.headerCell.title" = "Модель";
/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */
"okD-DG-pYa.title" = "Application:";
/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */
"PaK-1f-DsW.title" = "Control method:";
/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */
"pF5-Sw-7BR.title" = "Longer delay during DDC read operations";
/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */
"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!";
/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */
"r7i-oG-Ab6.title" = "Advanced:";
/* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */
"Riq-uM-bTs.title" = "Нормально";
/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */
"uoI-1J-RdD.headerCell.title" = "Название монтора";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber";
/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */
"Vh8-06-U3K.title" = "Изменять клавишами";
/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */
"UqR-WE-jHl.title" = "Enable keyboard control for display";
/* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */
"vik-vN-bJe.title" = "Часто";
@ -79,38 +112,32 @@
/* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */
"Vr4-xb-B4o.title" = "Яркость и громкость вместе";
/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */
"vwm-hY-on5.title" = "DDC read polling mode:";
/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */
"Wnd-hx-Meb.title" = "Show advanced settings under Displays";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */
"X96-ny-lAP.title" = "None";
/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */
"xFw-if-3FU.headerCell.title" = "DDC";
/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */
/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */
"xSI-8W-Xd0.title" = "Показать ползунок для контрастности";
/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */
"ytT-up-Dhs.headerCell.title" = "Количество опросов";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */
"xY6-aw-o9u.title" = "Reset Preferences";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */
"2gr-xG-Byx.title" = "";
/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */
"Xz0-X0-rB4.title" = "Additional settings:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */
"afl-95-ZJl.title" = "";
/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */
"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only.";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */
"as0-t3-Aub.title" = "";
/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */
"YqZ-LS-YvR.title" = "Identifier:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */
"H4a-c9-LcB.title" = "";
/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */
"ZdU-gV-V05.title" = "Use hardware DDC control";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */
"PZ9-0Z-K6J.title" = "";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */
"UBV-gO-AZz.title" = "";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */
"vkG-RF-Yne.title" = "";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */
"VPD-MR-IXg.title" = "";
/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */
"ZKk-ve-rS4.title" = "Donate";

View file

@ -1,77 +1,110 @@
/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */
"0Z7-PQ-Bl8.title" = "Змінювати Яскравість та Гучність для усіх дісплеїв";
/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */
"1PJ-14-Bvn.title" = "MonitorControl";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */
"4Pj-3t-PJr.title" = "Відновлення налаштувань";
/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */
"95V-M4-2l5.title" = "Special thanks to our contributors!";
/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */
"8U8-ec-Zbv.headerCell.title" = "Актив.";
/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */
"aXL-i8-S6R.title" = "Hide Menu Icon";
/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */
"CHc-s5-4MN.headerCell.title" = "Назва";
/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */
"bkM-Px-U3b.title" = "Disable macOS volume OSD";
/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */
"BYS-7Y-bRz.title" = "Reset settings";
/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */
"bZq-0d-lJa.title" = "Enable Mute DDC command";
/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */
"c7N-cO-759.title" = "Keyboard:";
/* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */
"Cle-DD-vR7.title" = "Власне";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */
"dgp-q7-cBK.headerCell.title" = "ID";
/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */
"Cln-uW-2dd.title" = "Website";
/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */
"dNl-I0-hcg.headerCell.title" = "Назва дісплею";
/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */
"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!";
/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */
"dhP-eB-1L6.title" = "Show volume slider in menu";
/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */
"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens";
/* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */
"Eq3-z9-yIo.title" = "Мінім.";
/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */
/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */
"f9g-8s-gdd.title" = "Reset Name";
/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */
"fhy-Er-0aI.title" = "Зменшувати Контраст після Яскравості";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */
"FoA-yh-Yx3.title" = "Немає";
/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */
"frw-j2-tE1.title" = "Увага! ⚠️\nЗміна деяких із цих налаштувань може привести до зависання системи або неочікуванних наслідків.";
/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */
"grO-Kr-l4d.headerCell.title" = "Затримка";
/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */
"gxn-NH-Qhb.headerCell.title" = "Режим полінгу";
/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */
"hdd-Zz-buN.title" = "Brightness control:";
/* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */
"hjz-0c-rvK.title" = "лише Яскравість";
/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */
/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */
"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only.";
/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */
"j72-NF-zsW.title" = "Запускати MonitorControl разом із системою";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */
"JKW-oY-bSb.headerCell.title" = "ID";
/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */
"J77-r0-djA.title" = "Custom read polling count:";
/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */
"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume.";
/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */
"kMa-3q-udl.title" = "Enable software dimming if required";
/* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */
"kqn-gU-mZX.ibShadowedToolTip" = "Детальніше";
/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */
"LRJ-fb-Z9E.headerCell.title" = "Виробник";
/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */
"lSJ-6w-KJ2.title" = "Display type:";
/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */
"mBs-6m-13Q.title" = "Версія 0.0.0 (Білд 0)";
/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */
"MJx-MK-e7D.title" = "Menu contents:";
/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */
"MPF-Mr-zVU.headerCell.title" = "Без OSD";
/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */
"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead.";
/* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */
"NLP-dU-Dam.title" = "лише Гучність";
/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */
"Nvp-hI-w4x.headerCell.title" = "Модель";
/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */
"okD-DG-pYa.title" = "Application:";
/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */
"PaK-1f-DsW.title" = "Control method:";
/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */
"pF5-Sw-7BR.title" = "Longer delay during DDC read operations";
/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */
"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!";
/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */
"r7i-oG-Ab6.title" = "Advanced:";
/* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */
"Riq-uM-bTs.title" = "Звич.";
/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */
"uoI-1J-RdD.headerCell.title" = "Назва дісплею";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber";
/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */
"Vh8-06-U3K.title" = "Реагувати на";
/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */
"UqR-WE-jHl.title" = "Enable keyboard control for display";
/* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */
"vik-vN-bJe.title" = "Част.";
@ -79,38 +112,32 @@
/* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */
"Vr4-xb-B4o.title" = "Яскравість та Гучність ";
/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */
"vwm-hY-on5.title" = "DDC read polling mode:";
/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */
"Wnd-hx-Meb.title" = "Show advanced settings under Displays";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */
"X96-ny-lAP.title" = "None";
/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */
"xFw-if-3FU.headerCell.title" = "DDC";
/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */
/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */
"xSI-8W-Xd0.title" = "Показувати слайдер для контрасту";
/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */
"ytT-up-Dhs.headerCell.title" = "Опитувань/с";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */
"xY6-aw-o9u.title" = "Reset Preferences";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */
"2gr-xG-Byx.title" = "";
/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */
"Xz0-X0-rB4.title" = "Additional settings:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */
"afl-95-ZJl.title" = "";
/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */
"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only.";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */
"as0-t3-Aub.title" = "";
/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */
"YqZ-LS-YvR.title" = "Identifier:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */
"H4a-c9-LcB.title" = "";
/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */
"ZdU-gV-V05.title" = "Use hardware DDC control";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */
"PZ9-0Z-K6J.title" = "";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */
"UBV-gO-AZz.title" = "";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */
"vkG-RF-Yne.title" = "";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */
"VPD-MR-IXg.title" = "";
/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */
"ZKk-ve-rS4.title" = "Donate";

View file

@ -1,83 +1,110 @@
/* Class = "NSButtonCell"; title = "Change Brightness/Volume for all screens"; ObjectID = "0Z7-PQ-Bl8"; */
"0Z7-PQ-Bl8.title" = "将亮度/音量调节应用于所有显示器";
/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */
"1PJ-14-Bvn.title" = "MonitorControl";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "4Pj-3t-PJr"; */
"4Pj-3t-PJr.title" = "重置偏好设置";
/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */
"95V-M4-2l5.title" = "Special thanks to our contributors!";
/* Class = "NSTableColumn"; headerCell.title = "Enabled"; ObjectID = "8U8-ec-Zbv"; */
"8U8-ec-Zbv.headerCell.title" = "启用";
/* Class = "NSButtonCell"; title = "Hide Menu Icon"; ObjectID = "aXL-i8-S6R"; */
"aXL-i8-S6R.title" = "Hide Menu Icon";
/* Class = "NSTableColumn"; headerCell.title = "Name"; ObjectID = "CHc-s5-4MN"; */
"CHc-s5-4MN.headerCell.title" = "名字";
/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */
"bkM-Px-U3b.title" = "Disable macOS volume OSD";
/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */
"BYS-7Y-bRz.title" = "Reset settings";
/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */
"bZq-0d-lJa.title" = "Enable Mute DDC command";
/* Class = "NSTextFieldCell"; title = "Keyboard:"; ObjectID = "c7N-cO-759"; */
"c7N-cO-759.title" = "Keyboard:";
/* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */
"Cle-DD-vR7.title" = "自定义";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "dgp-q7-cBK"; */
"dgp-q7-cBK.headerCell.title" = "ID";
/* Class = "NSButtonCell"; title = "Website"; ObjectID = "Cln-uW-2dd"; */
"Cln-uW-2dd.title" = "Website";
/* Class = "NSTableColumn"; headerCell.title = "Display Name"; ObjectID = "dNl-I0-hcg"; */
"dNl-I0-hcg.headerCell.title" = "显示器名字";
/* Class = "NSTextFieldCell"; title = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!"; ObjectID = "Cz1-Mh-llk"; */
"Cz1-Mh-llk.title" = "⚠️ Warning! Changing some of these settings may cause system freezes or unexpected behavior!";
/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "dhP-eB-1L6"; */
"dhP-eB-1L6.title" = "Show volume slider in menu";
/* Class = "NSButtonCell"; title = "Change Brightness and Volume for all screens"; ObjectID = "E6M-ih-S8Y"; */
"E6M-ih-S8Y.title" = "Change Brightness and Volume for all screens";
/* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */
"Eq3-z9-yIo.title" = "少量";
/* Class = "NSButtonCell"; title = "Lower Contrast after Brightness"; ObjectID = "fhy-Er-0aI"; */
/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */
"f9g-8s-gdd.title" = "Reset Name";
/* Class = "NSButtonCell"; title = "Further lower brightness via software dimming"; ObjectID = "fhy-Er-0aI"; */
"fhy-Er-0aI.title" = "对比度与亮度同时降低";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */
"FoA-yh-Yx3.title" = "不请求";
/* Class = "NSTextFieldCell"; title = "Warning ⚠️\nChanging some of these setting may cause system freezes or unexpected behaviour. "; ObjectID = "frw-j2-tE1"; */
"frw-j2-tE1.title" = "警告 ⚠️\n更改这些设置可能会导致系统冻结或者其它的意外情况。";
/* Class = "NSTableColumn"; headerCell.title = "Longer Delay"; ObjectID = "grO-Kr-l4d"; */
"grO-Kr-l4d.headerCell.title" = "增加延时";
/* Class = "NSTableColumn"; headerCell.title = "Polling Mode"; ObjectID = "gxn-NH-Qhb"; */
"gxn-NH-Qhb.headerCell.title" = "请求模式";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "H4a-c9-LcB"; */
"H4a-c9-LcB.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "hdd-Zz-buN"; */
"hdd-Zz-buN.title" = "Brightness control:";
/* Class = "NSMenuItem"; title = "Brightness only"; ObjectID = "hjz-0c-rvK"; */
"hjz-0c-rvK.title" = "仅亮度";
/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "j72-NF-zsW"; */
/* Class = "NSTextFieldCell"; title = "These options work for hardware (DDC) controlled displays only."; ObjectID = "iBZ-8c-JDY"; */
"iBZ-8c-JDY.title" = "These options work for hardware (DDC) controlled displays only.";
/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */
"j72-NF-zsW.title" = "登录时启动 MonitorControl";
/* Class = "NSTableColumn"; headerCell.title = "ID"; ObjectID = "JKW-oY-bSb"; */
"JKW-oY-bSb.headerCell.title" = "ID";
/* Class = "NSTextFieldCell"; title = "Custom read polling count:"; ObjectID = "J77-r0-djA"; */
"J77-r0-djA.title" = "Custom read polling count:";
/* Class = "NSTextFieldCell"; title = "Use the media keys of your keyboard to control Brightness & Volume."; ObjectID = "K2r-aD-eec"; */
"K2r-aD-eec.title" = "Use the media keys of your keyboard to control Brightness & Volume.";
/* Class = "NSButtonCell"; title = "Enable software dimming if required"; ObjectID = "kMa-3q-udl"; */
"kMa-3q-udl.title" = "Enable software dimming if required";
/* Class = "NSButton"; ibShadowedToolTip = "More Info"; ObjectID = "kqn-gU-mZX"; */
"kqn-gU-mZX.ibShadowedToolTip" = "了解更多";
/* Class = "NSTableColumn"; headerCell.title = "Vendor"; ObjectID = "LRJ-fb-Z9E"; */
"LRJ-fb-Z9E.headerCell.title" = "制造商";
/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */
"lSJ-6w-KJ2.title" = "Display type:";
/* Class = "NSTableColumn"; headerCell.title = "Hide OSD"; ObjectID = "MPF-Mr-zVU"; */
"MPF-Mr-zVU.headerCell.title" = "隐藏 OSD";
/* Class = "NSTextFieldCell"; title = "Menu contents:"; ObjectID = "MJx-MK-e7D"; */
"MJx-MK-e7D.title" = "Menu contents:";
/* Class = "NSTextFieldCell"; title = "If an external display can't be controlled, software dimming will be used instead."; ObjectID = "n4V-jQ-1Ri"; */
"n4V-jQ-1Ri.title" = "If an external display can't be controlled, software dimming will be used instead.";
/* Class = "NSMenuItem"; title = "Volume only"; ObjectID = "NLP-dU-Dam"; */
"NLP-dU-Dam.title" = "仅音量";
/* Class = "NSTableColumn"; headerCell.title = "Model"; ObjectID = "Nvp-hI-w4x"; */
"Nvp-hI-w4x.headerCell.title" = "型号";
/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */
"okD-DG-pYa.title" = "Application:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "PZ9-0Z-K6J"; */
"PZ9-0Z-K6J.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */
"PaK-1f-DsW.title" = "Control method:";
/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */
"pF5-Sw-7BR.title" = "Longer delay during DDC read operations";
/* Class = "NSTextFieldCell"; title = "If the menu item is hidden, just relaunch the app to reveal Preferences!"; ObjectID = "PVE-y7-zIk"; */
"PVE-y7-zIk.title" = "If the menu item is hidden, just relaunch the app to reveal Preferences!";
/* Class = "NSTextFieldCell"; title = "Advanced:"; ObjectID = "r7i-oG-Ab6"; */
"r7i-oG-Ab6.title" = "Advanced:";
/* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */
"Riq-uM-bTs.title" = "正常";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "UBV-gO-AZz"; */
"UBV-gO-AZz.title" = "Text Cell";
/* Class = "NSTextFieldCell"; title = "@the0neyouseek\n@JoniVR\n@waydabber"; ObjectID = "TKd-J8-Iyk"; */
"TKd-J8-Iyk.title" = "@the0neyouseek\n@reitermarkus\n@JoniVR\n@waydabber";
/* Class = "NSTableColumn"; headerCell.title = "Friendly Name"; ObjectID = "uoI-1J-RdD"; */
"uoI-1J-RdD.headerCell.title" = "自定义名";
/* Class = "NSTextFieldCell"; title = "Listen for"; ObjectID = "Vh8-06-U3K"; */
"Vh8-06-U3K.title" = "通过快捷键调整";
/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */
"UqR-WE-jHl.title" = "Enable keyboard control for display";
/* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */
"vik-vN-bJe.title" = "多次";
@ -85,32 +112,32 @@
/* Class = "NSMenuItem"; title = "Both Brightness & Volume"; ObjectID = "Vr4-xb-B4o"; */
"Vr4-xb-B4o.title" = "亮度和音量";
/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */
"vwm-hY-on5.title" = "DDC read polling mode:";
/* Class = "NSButtonCell"; title = "Show advanced settings under Displays"; ObjectID = "Wnd-hx-Meb"; */
"Wnd-hx-Meb.title" = "Show advanced settings under Displays";
/* Class = "NSMenuItem"; title = "None"; ObjectID = "X96-ny-lAP"; */
"X96-ny-lAP.title" = "None";
/* Class = "NSTableColumn"; headerCell.title = "DDC"; ObjectID = "xFw-if-3FU"; */
"xFw-if-3FU.headerCell.title" = "DDC";
/* Class = "NSButtonCell"; title = "Show a slider for contrast"; ObjectID = "xSI-8W-Xd0"; */
/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "xSI-8W-Xd0"; */
"xSI-8W-Xd0.title" = "显示对比度滑动条";
/* Class = "NSTableColumn"; headerCell.title = "Polling Count"; ObjectID = "ytT-up-Dhs"; */
"ytT-up-Dhs.headerCell.title" = "查询次数";
/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "xY6-aw-o9u"; */
"xY6-aw-o9u.title" = "Reset Preferences";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "2gr-xG-Byx"; */
"2gr-xG-Byx.title" = "";
/* Class = "NSTextFieldCell"; title = "Additional settings:"; ObjectID = "Xz0-X0-rB4"; */
"Xz0-X0-rB4.title" = "Additional settings:";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "afl-95-ZJl"; */
"afl-95-ZJl.title" = "";
/* Class = "NSTextFieldCell"; title = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only."; ObjectID = "yeg-GN-SuO"; */
"yeg-GN-SuO.title" = "This activates additional software dimming after the display reached zero hardware brightness. Menu slider is also affected with 50% being the transition point. Works for DDC controlled displays only.";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "as0-t3-Aub"; */
"as0-t3-Aub.title" = "";
/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */
"YqZ-LS-YvR.title" = "Identifier:";
/* Class = "NSTextFieldCell"; title = "Version 0.0.0 (Build 0)"; ObjectID = "mBs-6m-13Q"; */
"mBs-6m-13Q.title" = "";
/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */
"ZdU-gV-V05.title" = "Use hardware DDC control";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "vkG-RF-Yne"; */
"vkG-RF-Yne.title" = "";
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "VPD-MR-IXg"; */
"VPD-MR-IXg.title" = "";
/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */
"ZKk-ve-rS4.title" = "Donate";

View file

@ -0,0 +1,71 @@
import Cocoa
import Preferences
import ServiceManagement
class AboutPrefsViewController: NSViewController, PreferencePane {
let preferencePaneIdentifier = Preferences.PaneIdentifier.about
let preferencePaneTitle: String = NSLocalizedString("About", comment: "Shown in the main prefs window")
var toolbarItemIcon: NSImage {
if #available(macOS 11.0, *) {
return NSImage(systemSymbolName: "info.circle", accessibilityDescription: "About")!
} else {
// Fallback on earlier versions
return NSImage(named: NSImage.infoName)!
}
}
@IBOutlet var versionLabel: NSTextField!
@IBOutlet var copyrightLabel: NSTextField!
@IBOutlet var openContributorsButton: NSButton!
override func viewDidLoad() {
super.viewDidLoad()
self.setAppInfo()
self.setCopyrightInfo()
}
@available(macOS, deprecated: 10.10)
override func viewWillAppear() {
super.viewWillAppear()
}
@IBAction func openDonate(_: NSButton) {
if let url = URL(string: "https://opencollective.com/monitorcontrol/donate") {
NSWorkspace.shared.open(url)
}
}
@IBAction func openWebPage(_: NSButton) {
if let url = URL(string: "https://monitorcontrol.app") {
NSWorkspace.shared.open(url)
}
}
@IBAction func openContributorsPage(_: NSButton) {
if let url = URL(string: "https://github.com/MonitorControl/MonitorControl/graphs/contributors") {
NSWorkspace.shared.open(url)
}
}
func setAppInfo() {
let versionName = NSLocalizedString("Version", comment: "Version")
let buildName = NSLocalizedString("Build", comment: "Build")
let versionNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") ?? "error"
let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") ?? "error"
#if arch(arm64)
let arch: String = NSLocalizedString("Apple Silicon", comment: "Apple Silicon designation (shown after the version number in Preferences)")
#else
let arch: String = NSLocalizedString("Intel", comment: "Intel designation (shown after the version number in Preferences)")
#endif
self.versionLabel.stringValue = "\(versionName) \(versionNumber) \(buildName) \(buildNumber) - \(arch)"
}
func setCopyrightInfo() {
let copyright = NSLocalizedString("Copyright Ⓒ MonitorControl, ", comment: "Version")
let year = Calendar.current.component(.year, from: Date())
self.copyrightLabel.stringValue = "\(copyright) \(year)"
}
}

View file

@ -1,139 +0,0 @@
import Cocoa
import DDC
import os.log
import Preferences
class AdvancedPrefsViewController: NSViewController, PreferencePane, NSTableViewDataSource, NSTableViewDelegate {
var preferencePaneIdentifier = Preferences.PaneIdentifier.advanced
var preferencePaneTitle: String = NSLocalizedString("Advanced", comment: "Shown in the main prefs window")
var toolbarItemIcon: NSImage {
if #available(macOS 11.0, *) {
return NSImage(systemSymbolName: "gearshape", accessibilityDescription: "Advanced")!
} else {
// Fallback on earlier versions
return NSImage(named: NSImage.advancedName)!
}
}
let prefs = UserDefaults.standard
var displays: [ExternalDisplay] = []
enum DisplayColumn: Int {
case friendlyName
case identifier
case pollingMode
case pollingCount
case longerDelay
case hideOsd
}
@IBOutlet var displayList: NSTableView!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.loadDisplayList), name: .displayListUpdate, object: nil)
self.loadDisplayList()
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@IBAction func resetPrefsClicked(_: NSButton) {
let alert = NSAlert()
alert.messageText = NSLocalizedString("Reset Preferences?", comment: "Shown in the alert dialog")
alert.informativeText = NSLocalizedString("Are you sure you want to reset all preferences?", comment: "Shown in the alert dialog")
alert.addButton(withTitle: NSLocalizedString("Yes", comment: "Shown in the alert dialog"))
alert.addButton(withTitle: NSLocalizedString("No", comment: "Shown in the alert dialog"))
alert.alertStyle = NSAlert.Style.warning
if let window = self.view.window {
alert.beginSheetModal(for: window, completionHandler: { modalResponse in
if modalResponse == NSApplication.ModalResponse.alertFirstButtonReturn {
if let bundleID = Bundle.main.bundleIdentifier {
UserDefaults.standard.removePersistentDomain(forName: bundleID)
NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.preferenceReset.rawValue), object: nil)
os_log("Resetting all preferences.")
}
}
})
}
}
@IBAction func helpClicked(_: NSButton) {
if let url = URL(string: "https://github.com/the0neyouseek/MonitorControl/wiki/Advanced-Preferences") {
NSWorkspace.shared.open(url)
}
}
@objc func loadDisplayList() {
self.displays = DisplayManager.shared.getDdcCapableDisplays()
self.displayList.reloadData()
}
func numberOfRows(in _: NSTableView) -> Int {
return self.displays.count
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
guard let tableColumn = tableColumn,
let columnIndex = tableView.tableColumns.firstIndex(of: tableColumn),
let column = DisplayColumn(rawValue: columnIndex)
else {
return nil
}
let display = self.displays[row]
let pollingMode = display.getPollingMode()
switch column {
case .pollingMode:
if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? PollingModeCellView {
cell.display = display
cell.pollingModeMenu.selectItem(withTag: pollingMode)
cell.didChangePollingMode = { _ in
// if the polling mode changed, reload the row so we can enable/disable the PollingCount field
tableView.reloadData(forRowIndexes: [row], columnIndexes: [DisplayColumn.pollingCount.rawValue])
}
return cell
}
case .pollingCount:
if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? PollingCountCellView {
cell.textField?.stringValue = "\(display.getPollingCount())"
cell.display = display
cell.textField?.isEnabled = pollingMode == 4
return cell
}
case .longerDelay:
if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? LongerDelayCellView {
cell.button.state = display.needsLongerDelay ? .on : .off
cell.display = display
return cell
}
case .hideOsd:
if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? HideOsdCellView {
cell.button.state = display.hideOsd ? .on : .off
cell.display = display
return cell
}
default:
if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? NSTableCellView {
cell.textField?.stringValue = self.getText(for: column, with: display)
return cell
}
}
return nil
}
private func getText(for column: DisplayColumn, with display: ExternalDisplay) -> String {
switch column {
case .friendlyName:
return display.getFriendlyName()
case .identifier:
return "\(display.identifier)"
default:
return ""
}
}
}

View file

@ -1,132 +0,0 @@
import Cocoa
import DDC
import os.log
import Preferences
class DisplayPrefsViewController: NSViewController, PreferencePane, NSTableViewDataSource, NSTableViewDelegate {
var preferencePaneIdentifier = Preferences.PaneIdentifier.display
var preferencePaneTitle: String = NSLocalizedString("Display", comment: "Shown in the main prefs window")
var toolbarItemIcon: NSImage {
if #available(macOS 11.0, *) {
return NSImage(systemSymbolName: "display", accessibilityDescription: "Display")!
} else {
// Fallback on earlier versions
return NSImage(named: NSImage.computerName)!
}
}
let prefs = UserDefaults.standard
var displays: [Display] = []
enum DisplayColumn: Int {
case checkbox
case ddc
case name
case friendlyName
case identifier
case vendor
case model
}
@IBOutlet var allScreens: NSButton!
@IBOutlet var displayList: NSTableView!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(self.loadDisplayList), name: .displayListUpdate, object: nil)
self.loadDisplayList()
}
override func viewWillAppear() {
super.viewWillAppear()
self.allScreens.state = self.prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) ? .on : .off
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@IBAction func allScreensTouched(_ sender: NSButton) {
switch sender.state {
case .on:
self.prefs.set(true, forKey: Utils.PrefKeys.allScreens.rawValue)
case .off:
self.prefs.set(false, forKey: Utils.PrefKeys.allScreens.rawValue)
default: break
}
#if DEBUG
os_log("Toggle allScreens state: %{public}@", type: .info, sender.state == .on ? "on" : "off")
#endif
}
// MARK: - Table datasource
@objc func loadDisplayList() {
self.displays = DisplayManager.shared.getAllDisplays()
self.displayList.reloadData()
}
func numberOfRows(in _: NSTableView) -> Int {
return self.displays.count
}
// MARK: - Table delegate
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
guard let tableColumn = tableColumn,
let columnIndex = tableView.tableColumns.firstIndex(of: tableColumn),
let column = DisplayColumn(rawValue: columnIndex)
else {
return nil
}
let display = self.displays[row]
switch column {
case .checkbox:
if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? ButtonCellView {
cell.display = display
cell.button.state = display.isEnabled ? .on : .off
return cell
}
case .ddc:
if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? ButtonCellView {
cell.display = display
cell.button.state = DDC(for: display.identifier) != nil ? .on : .off
cell.button.isEnabled = false
return cell
}
case .friendlyName:
if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? FriendlyNameCellView {
cell.display = display
cell.textField?.stringValue = display.getFriendlyName()
cell.textField?.isEditable = true
return cell
}
default:
if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? NSTableCellView {
cell.textField?.stringValue = self.getText(for: column, with: display)
return cell
}
}
return nil
}
private func getText(for column: DisplayColumn, with display: Display) -> String {
switch column {
case .name:
return display.name
case .identifier:
return "\(display.identifier)"
case .vendor:
return display.identifier.vendorNumber.map { String(format: "0x%02X", $0) } ?? NSLocalizedString("Unknown", comment: "Unknown vendor")
case .model:
return display.identifier.modelNumber.map { String(format: "0x%02X", $0) } ?? NSLocalizedString("Unknown", comment: "Unknown model")
default:
return ""
}
}
}

View file

@ -0,0 +1,208 @@
import Cocoa
import os.log
class DisplaysPrefsCellView: NSTableCellView {
var display: Display?
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
}
@IBOutlet var displayImage: NSImageCell!
@IBOutlet var friendlyName: NSTextFieldCell!
@IBOutlet var displayId: NSTextFieldCell!
@IBOutlet var enabledButton: NSButton!
@IBOutlet var ddcButton: NSButton!
@IBOutlet var controlMethod: NSTextFieldCell!
@IBOutlet var displayType: NSTextFieldCell!
@IBOutlet var disableVolumeOSDButton: NSButton!
@IBOutlet var advancedSettings: NSBox!
@IBOutlet var pollingModeMenu: NSPopUpButton!
@IBOutlet var longerDelayButton: NSButton!
@IBOutlet var pollingCount: NSTextFieldCell!
@IBOutlet var enableMuteButton: NSButton!
@IBAction func openAdvancedHelp(_: NSButton) {
if let url = URL(string: "https://github.com/the0neyouseek/MonitorControl/wiki/Advanced-Preferences") {
NSWorkspace.shared.open(url)
}
}
@IBAction func pollingModeValueChanged(_ sender: NSPopUpButton) {
if let display = display as? ExternalDisplay {
let newValue = sender.selectedTag()
let originalValue = display.getPollingMode()
if newValue != originalValue {
display.setPollingMode(newValue)
if display.getPollingMode() == 4 {
self.pollingCount.isEnabled = true
} else {
self.pollingCount.isEnabled = false
}
self.pollingCount.stringValue = String(display.getPollingCount())
os_log("Value changed for polling count: %{public}@", type: .info, "from `\(originalValue)` to `\(newValue)`")
}
}
}
@IBAction func pollingCountValueChanged(_ sender: NSTextFieldCell) {
if let display = display as? ExternalDisplay {
let newValue = sender.stringValue
let originalValue = "\(display.getPollingCount())"
if newValue.isEmpty {
self.pollingCount.stringValue = originalValue
} else if let intValue = Int(newValue) {
self.pollingCount.stringValue = String(intValue)
} else {
self.pollingCount.stringValue = ""
}
if newValue != originalValue, !newValue.isEmpty, let newValue = Int(newValue) {
display.setPollingCount(newValue)
os_log("Value changed for polling count: %{public}@", type: .info, "from `\(originalValue)` to `\(newValue)`")
}
}
}
@IBAction func enableMuteButtonToggled(_ sender: NSButton) {
if let display = display as? ExternalDisplay {
switch sender.state {
case .on:
display.enableMuteUnmute = true
case .off:
// If the display is currently muted, toggle back to unmute
// to prevent the display becoming stuck in the muted state
if display.isMuted() {
display.toggleMute()
}
display.enableMuteUnmute = false
default:
break
}
}
}
@IBAction func longerDelayButtonToggled(_ sender: NSButton) {
if let display = self.display as? ExternalDisplay {
switch sender.state {
case .on:
let alert = NSAlert()
alert.messageText = NSLocalizedString("Enable Longer Delay?", comment: "Shown in the alert dialog")
alert.informativeText = NSLocalizedString("Are you sure you want to enable a longer delay? Doing so may freeze your system and require a restart. Start at login will be disabled as a safety measure.", comment: "Shown in the alert dialog")
alert.addButton(withTitle: NSLocalizedString("Yes", comment: "Shown in the alert dialog"))
alert.addButton(withTitle: NSLocalizedString("No", comment: "Shown in the alert dialog"))
alert.alertStyle = NSAlert.Style.critical
if let window = self.window {
alert.beginSheetModal(for: window, completionHandler: { modalResponse in
if modalResponse == NSApplication.ModalResponse.alertFirstButtonReturn {
Utils.setStartAtLogin(enabled: false)
display.needsLongerDelay = true
} else {
sender.state = .off
}
})
}
case .off:
display.needsLongerDelay = false
default:
break
}
}
}
@IBAction func enabledButtonToggled(_ sender: NSButton) {
if let disp = display {
let isEnabled = sender.state == .on
disp.isEnabled = isEnabled
#if DEBUG
os_log("Toggle enabled display state: %{public}@", type: .info, isEnabled ? "on" : "off")
#endif
}
}
@IBAction func ddcButtonToggled(_ sender: NSButton) {
if let disp = display {
switch sender.state {
case .off:
disp.forceSw = true
case .on:
disp.forceSw = false
default:
break
}
_ = disp.resetSwBrightness()
app.updateMenus()
let displayInfo = DisplaysPrefsViewController.getDisplayInfo(display: disp)
self.controlMethod.stringValue = displayInfo.controlMethod
}
}
@IBAction func friendlyNameValueChanged(_ sender: NSTextFieldCell) {
if let disp = display {
let newValue = sender.stringValue
let originalValue = disp.getFriendlyName()
if newValue.isEmpty {
self.friendlyName.stringValue = originalValue
return
}
if newValue != originalValue, !newValue.isEmpty {
disp.setFriendlyName(newValue)
NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.friendlyName.rawValue), object: nil)
#if DEBUG
os_log("Value changed for friendly name: %{public}@", type: .info, "from `\(originalValue)` to `\(newValue)`")
#endif
}
}
}
@IBAction func disableVolumeOSDButton(_ sender: NSButton) {
if let disp = display as? ExternalDisplay {
switch sender.state {
case .on:
disp.hideOsd = true
case .off:
disp.hideOsd = false
default:
break
}
}
}
@IBAction func resetSettings(_: NSButton) {
if let disp = display {
if self.ddcButton.isEnabled {
self.ddcButton.state = .on
self.ddcButtonToggled(self.ddcButton)
}
if self.enabledButton.isEnabled {
self.enabledButton.state = .on
self.enabledButtonToggled(self.enabledButton)
}
if self.disableVolumeOSDButton.isEnabled {
self.disableVolumeOSDButton.state = .off
self.disableVolumeOSDButton(self.disableVolumeOSDButton)
}
if self.pollingModeMenu.isEnabled {
self.pollingModeMenu.selectItem(withTag: 2)
self.pollingModeValueChanged(self.pollingModeMenu)
}
if self.longerDelayButton.isEnabled {
self.longerDelayButton.state = .off
self.longerDelayButtonToggled(self.longerDelayButton)
}
if self.enableMuteButton.isEnabled {
self.enableMuteButton.state = .off
self.enableMuteButtonToggled(self.enableMuteButton)
}
self.friendlyName.stringValue = disp.name
self.friendlyNameValueChanged(self.friendlyName)
}
}
}

View file

@ -0,0 +1,185 @@
import Cocoa
import os.log
import Preferences
class DisplaysPrefsViewController: NSViewController, PreferencePane, NSTableViewDataSource, NSTableViewDelegate {
let preferencePaneIdentifier = Preferences.PaneIdentifier.displays
let preferencePaneTitle: String = NSLocalizedString("Displays", comment: "Shown in the main prefs window")
var toolbarItemIcon: NSImage {
if #available(macOS 11.0, *) {
return NSImage(systemSymbolName: "display.2", accessibilityDescription: "Displays")!
} else {
// Fallback on earlier versions
return NSImage(named: NSImage.computerName)!
}
}
let prefs = UserDefaults.standard
var displays: [Display] = []
@IBOutlet var displayList: NSTableView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear() {
super.viewWillAppear()
self.loadDisplayList()
NotificationCenter.default.addObserver(self, selector: #selector(self.loadDisplayList), name: .displayListUpdate, object: nil)
}
@objc func loadDisplayList() {
os_log("Reloading Displays preferences display list", type: .info)
self.displays = DisplayManager.shared.getAllDisplays()
self.displayList.reloadData()
self.updateDisplayListRowHeight()
}
func numberOfRows(in _: NSTableView) -> Int {
return self.displays.count
}
public static func isImac() -> Bool {
let platformExpertDevice = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"))
if let modelData = IORegistryEntryCreateCFProperty(platformExpertDevice, "model" as CFString, kCFAllocatorDefault, 0).takeRetainedValue() as? Data, let modelIdentifierCString = String(data: modelData, encoding: .utf8)?.cString(using: .utf8) {
let modelIdentifier = String(cString: modelIdentifierCString)
return modelIdentifier.contains("iMac")
}
return false
}
public struct DisplayInfo {
var displayType = ""
var displayImage = ""
var controlMethod = ""
}
public static func getDisplayInfo(display: Display) -> DisplayInfo {
var displayType = ""
var displayImage = ""
var controlMethod = ""
if display.isVirtual {
displayType = NSLocalizedString("Virtual Display", comment: "Shown in the Display Preferences")
displayImage = "tv.and.mediabox"
controlMethod = NSLocalizedString("No Control Available", comment: "Shown in the Display Preferences")
} else if display is ExternalDisplay {
displayType = NSLocalizedString("External Display", comment: "Shown in the Display Preferences")
displayImage = "display"
if let externalDisplay: ExternalDisplay = display as? ExternalDisplay {
if externalDisplay.isSwOnly() {
controlMethod = NSLocalizedString("Software Only", comment: "Shown in the Display Preferences")
displayImage = "display.trianglebadge.exclamationmark"
} else {
if externalDisplay.isSw() {
controlMethod = NSLocalizedString("Software (Forced)", comment: "Shown in the Display Preferences")
} else {
controlMethod = NSLocalizedString("Hardware (DDC)", comment: "Shown in the Display Preferences")
}
}
} else {
controlMethod = NSLocalizedString("Unspecified", comment: "Shown in the Display Preferences")
}
} else if display is InternalDisplay {
displayType = NSLocalizedString("Built-in Display", comment: "Shown in the Display Preferences")
if self.isImac() {
displayImage = "desktopcomputer"
} else {
displayImage = "laptopcomputer"
}
controlMethod = NSLocalizedString("Hardware (CoreDisplay)", comment: "Shown in the Display Preferences")
} else {
displayType = NSLocalizedString("Other Display", comment: "Shown in the Display Preferences")
displayImage = "display.trianglebadge.exclamationmark"
controlMethod = NSLocalizedString("No Control Available", comment: "Shown in the Display Preferences")
}
return DisplayInfo(displayType: displayType, displayImage: displayImage, controlMethod: controlMethod)
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
guard let tableColumn = tableColumn else {
return nil
}
os_log("Populating Displays Table")
let display = self.displays[row]
if let cell = tableView.makeView(withIdentifier: tableColumn.identifier, owner: nil) as? DisplaysPrefsCellView {
cell.display = display
// ID
cell.displayId.stringValue = String(display.identifier)
// Firendly name
cell.friendlyName.stringValue = display.getFriendlyName()
cell.friendlyName.isEditable = true
// Enabled
cell.enabledButton.state = display.isEnabled && !display.isVirtual ? .on : .off
cell.enabledButton.isEnabled = !display.isVirtual
// DDC
cell.ddcButton.state = ((display as? ExternalDisplay)?.isSw() ?? true) || ((display as? ExternalDisplay)?.isVirtual ?? true) ? .off : .on
if ((display as? ExternalDisplay)?.isSwOnly() ?? true) || ((display as? ExternalDisplay)?.isVirtual ?? true) {
cell.ddcButton.isEnabled = false
} else {
cell.ddcButton.isEnabled = true
}
// Display type, image, control method
let displayInfo = DisplaysPrefsViewController.getDisplayInfo(display: display)
cell.displayType.stringValue = displayInfo.displayType
cell.controlMethod.stringValue = displayInfo.controlMethod
if #available(macOS 11.0, *) {
cell.displayImage.image = NSImage(systemSymbolName: displayInfo.displayImage, accessibilityDescription: display.name)!
} else {
cell.displayImage.image = NSImage(named: NSImage.computerName)!
}
// Disable Volume OSD
if let externalDisplay = display as? ExternalDisplay, !externalDisplay.isVirtual {
cell.disableVolumeOSDButton.state = externalDisplay.hideOsd ? .on : .off
cell.disableVolumeOSDButton.isEnabled = true
} else {
cell.disableVolumeOSDButton.state = .off
cell.disableVolumeOSDButton.isEnabled = false
}
// Advanced settings
if let externalDisplay = display as? ExternalDisplay, !externalDisplay.isSwOnly(), !externalDisplay.isVirtual {
// DDC read polling mode
cell.pollingModeMenu.isEnabled = true
cell.pollingModeMenu.selectItem(withTag: externalDisplay.getPollingMode())
// Custom read polling count
if externalDisplay.getPollingMode() == 4 {
cell.pollingCount.isEnabled = true
} else {
cell.pollingCount.isEnabled = false
}
cell.pollingCount.stringValue = String(externalDisplay.getPollingCount())
// DDC read delay
cell.longerDelayButton.isEnabled = true
cell.longerDelayButton.state = externalDisplay.needsLongerDelay ? .on : .off
cell.enableMuteButton.isEnabled = true
cell.enableMuteButton.state = externalDisplay.enableMuteUnmute ? .on : .off
} else {
cell.pollingModeMenu.selectItem(withTag: 0)
cell.pollingModeMenu.isEnabled = false
cell.pollingCount.stringValue = ""
cell.pollingCount.isEnabled = false
cell.longerDelayButton.state = .off
cell.longerDelayButton.isEnabled = false
cell.enableMuteButton.state = .off
cell.enableMuteButton.isEnabled = false
}
if self.prefs.bool(forKey: Utils.PrefKeys.showAdvancedDisplays.rawValue) {
cell.advancedSettings.isHidden = false
} else {
cell.advancedSettings.isHidden = true
}
return cell
}
return nil
}
func updateDisplayListRowHeight() {
if self.prefs.bool(forKey: Utils.PrefKeys.showAdvancedDisplays.rawValue) {
self.displayList.rowHeight = 300
} else {
self.displayList.rowHeight = 150
}
}
}

View file

@ -1,34 +0,0 @@
import Cocoa
import os.log
import Preferences
class KeysPrefsViewController: NSViewController, PreferencePane {
var preferencePaneIdentifier = Preferences.PaneIdentifier.keys
var preferencePaneTitle: String = NSLocalizedString("Keys", comment: "Shown in the main prefs window")
var toolbarItemIcon: NSImage {
if #available(macOS 11.0, *) {
return NSImage(systemSymbolName: "keyboard", accessibilityDescription: "Keys")!
} else {
// Fallback on earlier versions
return NSImage(named: "KeyboardPref")!
}
}
let prefs = UserDefaults.standard
@IBOutlet var listenFor: NSPopUpButton!
override func viewWillAppear() {
super.viewWillAppear()
self.listenFor.selectItem(at: self.prefs.integer(forKey: Utils.PrefKeys.listenFor.rawValue))
}
@IBAction func listenForChanged(_ sender: NSPopUpButton) {
self.prefs.set(sender.selectedTag(), forKey: Utils.PrefKeys.listenFor.rawValue)
#if DEBUG
os_log("Toggle keys listened for state state: %{public}@", type: .info, sender.selectedItem?.title ?? "")
#endif
NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.listenFor.rawValue), object: nil)
}
}

View file

@ -18,23 +18,54 @@ class MainPrefsViewController: NSViewController, PreferencePane {
let prefs = UserDefaults.standard
@IBOutlet var versionLabel: NSTextField!
@IBOutlet var startAtLogin: NSButton!
@IBOutlet var hideMenuIcon: NSButton!
@IBOutlet var showContrastSlider: NSButton!
@IBOutlet var lowerContrast: NSButton!
@IBOutlet var showVolumeSlider: NSButton!
@IBOutlet var lowerSwAfterBrightness: NSButton!
@IBOutlet var fallbackSw: NSButton!
@IBOutlet var listenFor: NSPopUpButton!
@IBOutlet var allScreens: NSButton!
@IBOutlet var showAdvancedDisplays: NSButton!
override func viewDidLoad() {
super.viewDidLoad()
self.setVersionNumber()
}
@available(macOS, deprecated: 10.10)
override func viewWillAppear() {
super.viewWillAppear()
self.populateSettings()
}
@available(macOS, deprecated: 10.10)
func populateSettings() {
// This is marked as deprectated but according to the function header it still does not have a replacement as of macOS 12 Monterey and is valid to use.
let startAtLogin = (SMCopyAllJobDictionaries(kSMDomainUserLaunchd).takeRetainedValue() as? [[String: AnyObject]])?.first { $0["Label"] as? String == "\(Bundle.main.bundleIdentifier!)Helper" }?["OnDemand"] as? Bool ?? false
self.startAtLogin.state = startAtLogin ? .on : .off
self.hideMenuIcon.state = self.prefs.bool(forKey: Utils.PrefKeys.hideMenuIcon.rawValue) ? .on : .off
self.showContrastSlider.state = self.prefs.bool(forKey: Utils.PrefKeys.showContrast.rawValue) ? .on : .off
self.lowerContrast.state = self.prefs.bool(forKey: Utils.PrefKeys.lowerContrast.rawValue) ? .on : .off
self.showVolumeSlider.state = self.prefs.bool(forKey: Utils.PrefKeys.showVolume.rawValue) ? .on : .off
self.lowerSwAfterBrightness.state = self.prefs.bool(forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue) ? .on : .off
self.fallbackSw.state = self.prefs.bool(forKey: Utils.PrefKeys.fallbackSw.rawValue) ? .on : .off
self.listenFor.selectItem(at: self.prefs.integer(forKey: Utils.PrefKeys.listenFor.rawValue))
self.allScreens.state = self.prefs.bool(forKey: Utils.PrefKeys.allScreens.rawValue) ? .on : .off
self.showAdvancedDisplays.state = self.prefs.bool(forKey: Utils.PrefKeys.showAdvancedDisplays.rawValue) ? .on : .off
}
@IBAction func allScreensTouched(_ sender: NSButton) {
switch sender.state {
case .on:
self.prefs.set(true, forKey: Utils.PrefKeys.allScreens.rawValue)
case .off:
self.prefs.set(false, forKey: Utils.PrefKeys.allScreens.rawValue)
default: break
}
#if DEBUG
os_log("Toggle allScreens state: %{public}@", type: .info, sender.state == .on ? "on" : "off")
#endif
}
@IBAction func startAtLoginClicked(_ sender: NSButton) {
@ -47,6 +78,18 @@ class MainPrefsViewController: NSViewController, PreferencePane {
}
}
@IBAction func hideMenuIconClicked(_ sender: NSButton) {
switch sender.state {
case .on:
self.prefs.set(true, forKey: Utils.PrefKeys.hideMenuIcon.rawValue)
app.statusItem.isVisible = false
case .off:
self.prefs.set(false, forKey: Utils.PrefKeys.hideMenuIcon.rawValue)
app.statusItem.isVisible = true
default: break
}
}
@IBAction func showContrastSliderClicked(_ sender: NSButton) {
switch sender.state {
case .on:
@ -55,33 +98,96 @@ class MainPrefsViewController: NSViewController, PreferencePane {
self.prefs.set(false, forKey: Utils.PrefKeys.showContrast.rawValue)
default: break
}
app.updateMenus()
#if DEBUG
os_log("Toggle show contrast slider state: %{public}@", type: .info, sender.state == .on ? "on" : "off")
#endif
NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.showContrast.rawValue), object: nil)
}
@IBAction func lowerContrastClicked(_ sender: NSButton) {
@IBAction func showVolumeSliderClicked(_ sender: NSButton) {
switch sender.state {
case .on:
self.prefs.set(true, forKey: Utils.PrefKeys.lowerContrast.rawValue)
self.prefs.set(true, forKey: Utils.PrefKeys.showVolume.rawValue)
case .off:
self.prefs.set(false, forKey: Utils.PrefKeys.lowerContrast.rawValue)
self.prefs.set(false, forKey: Utils.PrefKeys.showVolume.rawValue)
default: break
}
app.updateMenus()
#if DEBUG
os_log("Toggle lower contrast after brightness state: %{public}@", type: .info, sender.state == .on ? "on" : "off")
os_log("Toggle show volume slider state: %{public}@", type: .info, sender.state == .on ? "on" : "off")
#endif
}
fileprivate func setVersionNumber() {
let versionName = NSLocalizedString("Version", comment: "Version")
let buildName = NSLocalizedString("Build", comment: "Build")
let versionNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") ?? "error"
let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") ?? "error"
self.versionLabel.stringValue = "\(versionName) \(versionNumber) (\(buildName) \(buildNumber))"
@IBAction func lowerSwAfterBrightnessClicked(_ sender: NSButton) {
switch sender.state {
case .on:
self.prefs.set(true, forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue)
case .off:
self.prefs.set(false, forKey: Utils.PrefKeys.lowerSwAfterBrightness.rawValue)
DisplayManager.shared.resetSwBrightnessForAllDisplays()
default: break
}
app.updateMenus()
#if DEBUG
os_log("Toggle software control after brightness state: %{public}@", type: .info, sender.state == .on ? "on" : "off")
#endif
}
@IBAction func fallbackSwClicked(_ sender: NSButton) {
switch sender.state {
case .on:
self.prefs.set(true, forKey: Utils.PrefKeys.fallbackSw.rawValue)
case .off:
self.prefs.set(false, forKey: Utils.PrefKeys.fallbackSw.rawValue)
default: break
}
DisplayManager.shared.resetSwBrightnessForAllDisplays()
app.updateMenus()
#if DEBUG
os_log("Toggle fallback to software if no DDC: %{public}@", type: .info, sender.state == .on ? "on" : "off")
#endif
}
@IBAction func showAdvancedClicked(_ sender: NSButton) {
switch sender.state {
case .on:
self.prefs.set(true, forKey: Utils.PrefKeys.showAdvancedDisplays.rawValue)
case .off:
self.prefs.set(false, forKey: Utils.PrefKeys.showAdvancedDisplays.rawValue)
default: break
}
NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.displayListUpdate.rawValue), object: nil)
#if DEBUG
os_log("Show advanced settings in Display clicked: %{public}@", type: .info, sender.state == .on ? "on" : "off")
#endif
}
@IBAction func listenForChanged(_ sender: NSPopUpButton) {
self.prefs.set(sender.selectedTag(), forKey: Utils.PrefKeys.listenFor.rawValue)
#if DEBUG
os_log("Toggle keys listened for state state: %{public}@", type: .info, sender.selectedItem?.title ?? "")
#endif
NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.listenFor.rawValue), object: nil)
}
@available(macOS, deprecated: 10.10)
func resetSheetModalHander(modalResponse: NSApplication.ModalResponse) {
if modalResponse == NSApplication.ModalResponse.alertFirstButtonReturn {
NotificationCenter.default.post(name: Notification.Name(Utils.PrefKeys.preferenceReset.rawValue), object: nil)
self.populateSettings()
}
}
@available(macOS, deprecated: 10.10)
@IBAction func resetPrefsClicked(_: NSButton) {
let alert = NSAlert()
alert.messageText = NSLocalizedString("Reset Preferences?", comment: "Shown in the alert dialog")
alert.informativeText = NSLocalizedString("Are you sure you want to reset all preferences?", comment: "Shown in the alert dialog")
alert.addButton(withTitle: NSLocalizedString("Yes", comment: "Shown in the alert dialog"))
alert.addButton(withTitle: NSLocalizedString("No", comment: "Shown in the alert dialog"))
alert.alertStyle = NSAlert.Style.warning
if let window = self.view.window {
alert.beginSheetModal(for: window, completionHandler: { modalResponse in self.resetSheetModalHander(modalResponse: modalResponse) })
}
}
}

View file

@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>947</string>
<string>2866</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSBackgroundOnly</key>

View file

@ -1,21 +0,0 @@
#import "OSDUIHelperProtocol.h"
@class NSXPCConnection;
@interface OSDManager : NSObject <OSDUIHelperProtocol>
{
id <OSDUIHelperProtocol> _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 <OSDUIHelperProtocol> remoteObjectProxy; // @dynamic remoteObjectProxy;
@end

View file

@ -1,11 +0,0 @@
@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

View file

@ -1 +0,0 @@
Versions/Current/OSD

View file

@ -1 +0,0 @@
Versions/Current/Resources

Binary file not shown.

View file

@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>16B2657</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>OSD</string>
<key>CFBundleIdentifier</key>
<string>com.apple.OSD</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>OSD</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>9L173x</string>
<key>DTPlatformVersion</key>
<string>GM</string>
<key>DTSDKBuild</key>
<string>17A317</string>
<key>DTSDKName</key>
<string>macosx10.13internal</string>
<key>DTXcode</key>
<string>0900</string>
<key>DTXcodeBuild</key>
<string>9L173x</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2015 Apple Inc. All rights reserved.</string>
</dict>
</plist>

View file

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildAliasOf</key>
<string>OSDFramework</string>
<key>BuildVersion</key>
<string>487</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>ProjectName</key>
<string>OSDFramework</string>
<key>SourceVersion</key>
<string>27000000000000</string>
</dict>
</plist>

View file

@ -1,139 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>files</key>
<dict>
<key>Resources/Info.plist</key>
<data>
bTy7OXKIr2tY7ToPw28ekz1xUXU=
</data>
<key>Resources/version.plist</key>
<data>
d0I/dBV8v16urCBanZt9RaZvG1E=
</data>
</dict>
<key>files2</key>
<dict>
<key>Resources/Info.plist</key>
<dict>
<key>hash2</key>
<data>
uEmRq0D23jBsIWK+0+UH3bCcn16eQdAwKWglrQbTfQc=
</data>
</dict>
<key>Resources/version.plist</key>
<dict>
<key>hash2</key>
<data>
f4xR2tymy1G7xEyxX1+yXJmSgOrrndsypu67avrQ8Ss=
</data>
</dict>
</dict>
<key>rules</key>
<dict>
<key>^Resources/</key>
<true/>
<key>^Resources/.*\.lproj/</key>
<dict>
<key>optional</key>
<true/>
<key>weight</key>
<real>1000</real>
</dict>
<key>^Resources/.*\.lproj/locversion.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>1100</real>
</dict>
<key>^Resources/Base\.lproj/</key>
<dict>
<key>weight</key>
<real>1010</real>
</dict>
<key>^version.plist$</key>
<true/>
</dict>
<key>rules2</key>
<dict>
<key>.*\.dSYM($|/)</key>
<dict>
<key>weight</key>
<real>11</real>
</dict>
<key>^(.*/)?\.DS_Store$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>2000</real>
</dict>
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
<dict>
<key>nested</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^.*</key>
<true/>
<key>^Info\.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>20</real>
</dict>
<key>^PkgInfo$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>20</real>
</dict>
<key>^Resources/</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
<key>^Resources/.*\.lproj/</key>
<dict>
<key>optional</key>
<true/>
<key>weight</key>
<real>1000</real>
</dict>
<key>^Resources/.*\.lproj/locversion.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>1100</real>
</dict>
<key>^Resources/Base\.lproj/</key>
<dict>
<key>weight</key>
<real>1010</real>
</dict>
<key>^[^/]+$</key>
<dict>
<key>nested</key>
<true/>
<key>weight</key>
<real>10</real>
</dict>
<key>^embedded\.provisionprofile$</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
<key>^version\.plist$</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
</dict>
</dict>
</plist>

View file

@ -1 +0,0 @@
A

View file

@ -1 +0,0 @@
Versions/Current/XPCServices

123
README.md
View file

@ -1,66 +1,55 @@
<h1 align="center"> MonitorControl </h1>
<img src=".github/Icon-1024.png" width="175" alt="App icon" align="left"/>
<!-- subtext -->
<div align="center">
Control your external monitor brightness, contrast or volume directly from a menulet or with keyboard native keys.
</div>
<h2>MonitorControl - Now with Apple Silicon support!</h2>
<p>
<b>Control your external display brightness and volume!<br>
Use menulet sliders or the native Apple keyboard keys!<br>
Shows native brightness and volume OSDs as well!</b>
</p>
<br/>
<!-- Language emoji -->
<div align="center">
<p>Translations: :uk: :fr: :de: :it: :ru: :ukraine: :jp: :poland: </p>
</div>
<br/>
<!-- shields -->
<div align="center">
<!-- downloads -->
<a href="https://github.com/MonitorControl/MonitorControl/releases">
<img src="https://img.shields.io/github/downloads/MonitorControl/MonitorControl/total.svg" alt="downloads"/>
</a>
<!-- version -->
<a href="https://github.com/MonitorControl/MonitorControl/releases/latest">
<img src="https://img.shields.io/github/release/MonitorControl/MonitorControl.svg" alt="latest version"/>
</a>
<!-- license -->
<a href="https://github.com/MonitorControl/MonitorControl/blob/master/License.txt">
<img src="https://img.shields.io/github/license/MonitorControl/MonitorControl.svg" alt="license"/>
</a>
<!-- platform -->
<a href="https://github.com/MonitorControl/MonitorControl">
<img src="https://img.shields.io/badge/platform-macOS-lightgrey.svg" alt="platform"/>
</a>
</div>
<!-- downloads -->
<a href="https://github.com/MonitorControl/MonitorControl/releases">
<img src="https://img.shields.io/github/downloads/MonitorControl/MonitorControl/total.svg?style=flat" alt="downloads"/>
</a>
<!-- version -->
<a href="https://github.com/MonitorControl/MonitorControl/releases">
<img src="https://img.shields.io/github/release-pre/MonitorControl/MonitorControl.svg?style=flat" alt="latest version"/>
</a>
<!-- license -->
<a href="https://github.com/MonitorControl/MonitorControl/blob/master/License.txt">
<img src="https://img.shields.io/github/license/MonitorControl/MonitorControl.svg?style=flat" alt="license"/>
</a>
<!-- platform -->
<a href="https://github.com/MonitorControl/MonitorControl">
<img src="https://img.shields.io/badge/platform-macOS-lightgrey.svg?style=flat" alt="platform"/>
</a>
<!-- backers -->
<a href="https://opencollective.com/monitorcontrol">
<img src="https://opencollective.com/monitorcontrol/tiers/badge.svg" alt="backers"/>
</a>
<br/>
<br/>
<div align="center">
<img src="./.github/menulet.png" width="200" alt="menulet screenshot"/>
<br/><br/>
<img src="./.github/menugeneral.png" width="299" alt="general screenshot"/><img src="./.github/menukeys.png" width="299" alt="keys screenshot"/>
<img src="./.github/menudisplay.png" width="299" alt="display screenshot"/>
<img src="./.github/menuadvanced.png" width="299" alt="advanced screenshot"/>
<br/>
_Bonus: Using keyboard keys displays the native osd_
<img src="./.github/osd.jpg" width="500" align="center" alt="osd screenshot"/>
</div>
<img src=".github/screenshot.png" width="840" alt="Screenshot"/><br/>
<hr>
## Download
Go to [Release](https://github.com/MonitorControl/MonitorControl/releases/latest) and download the latest `.dmg`
Go to [Releases](https://github.com/MonitorControl/MonitorControl/releases) and download the latest `.dmg`
## Installing with Homebrew Cask
## Compatibility
You can also install MonitorControl with [Homebrew Cask](https://github.com/Homebrew/homebrew-cask).
```bash
$ brew install --cask monitorcontrol
```
- macOS Mojave (`10.14`) and up _(note: you can download [version 2.1.0](https://github.com/MonitorControl/MonitorControl/releases/tag/v2.1.0) for macOS Sierra `10.12` support)_
- Works with monitors controllable via [DDC](https://en.wikipedia.org/wiki/Display_Data_Channel) (or any other display via software dimming)
## How to help
@ -75,17 +64,19 @@ Open [issues](https://github.com/MonitorControl/MonitorControl/issues) if you ha
- [SwiftFormat](https://github.com/nicklockwood/SwiftFormat)
- [BartyCrouch](https://github.com/Flinesoft/BartyCrouch) (for updating localizations)
Clone the project
Clone the project via this Terminal command:
```sh
```
git clone https://github.com/MonitorControl/MonitorControl.git
```
Then dependencies will automatically get downloaded when opening the project, if they don't:
If you want to clone one of the branches, add `--single-branch --branch [branchname]` after the `clone` option.
`File > Swift Packages > Resolve Package Versions`
You're all set ! Now open the `MonitorControl.xcodeproj` with Xcode! The dependencies will automatically get downloaded once you open the project. If they don't:
You're all set ! Now open the `MonitorControl.xcodeproj` with Xcode
`File > Packages > Resolve Package Versions`
(In earlier XCode versions `Packages` menu is titled `Swift Packages`)
### Third party dependencies
@ -94,21 +85,21 @@ You're all set ! Now open the `MonitorControl.xcodeproj` with Xcode
- [DDC.swift](https://github.com/reitermarkus/DDC.swift)
- [SimplyCoreAudio](https://github.com/rnine/SimplyCoreAudio)
## Support
- macOS Sierra (`10.12`) and up.
- Works with monitors controllable via [DDC](https://en.wikipedia.org/wiki/Display_Data_Channel).
## Contributors
- [@the0neyouseek](https://github.com/the0neyouseek)
- [@reitermarkus](https://github.com/reitermarkus)
- [@JoniVR](https://github.com/JoniVR)
- [@waydabber](https://github.com/waydabber)
## Thanks
- [@bluejamesbond](https://github.com/bluejamesbond/) (Original developer)
- [@Tyilo](https://github.com/Tyilo/) (Fork)
- [@Bensge](https://github.com/Bensge/) - (Used some code from his project [NativeDisplayBrightness](https://github.com/Bensge/NativeDisplayBrightness))
- [@nhurden](https://github.com/nhurden/) (For the original MediaKeyTap)
- [@kfix](https://github.com/kfix/ddcctl) (For ddcctl)
- [@bluejamesbond](https://github.com/bluejamesbond/) (original developer)
- [@Tyilo](https://github.com/Tyilo/) (fork)
- [@Bensge](https://github.com/Bensge/) - (used some code from his project [NativeDisplayBrightness](https://github.com/Bensge/NativeDisplayBrightness))
- [@nhurden](https://github.com/nhurden/) (for the original MediaKeyTap)
- [@kfix](https://github.com/kfix/ddcctl) (for ddcctl)
- [@reitermarkus](https://github.com/reitermarkus) (for DDC.Swift)
- [@zhuowei](https://github.com/zhuowei) (figured out M1 I²C communication)
- [@tao-j](https://github.com/tao-j) (figured out M1 I²C write)
- [@alin23](https://github.com/alin23) (generally spearheaded M1 DDC support and figured out a many of the caveats)
- [javierocasio](https://www.deviantart.com/javierocasio) (app icon background)

1
docs/CNAME Normal file
View file

@ -0,0 +1 @@
monitorcontrol.app

15
docs/index.html Normal file
View file

@ -0,0 +1,15 @@
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="0; url=https://github.com/MonitorControl/MonitorControl/tree/experimental/apple-silicon#readme">
<script type="text/javascript">
window.location.href = "https://github.com/MonitorControl/MonitorControl/tree/experimental/apple-silicon#readme"
</script>
<title>MonitorControl - redirect</title>
</head>
<body>
<!-- Note: don't tell people to `click` the link, just tell them that it is a link. -->
If you are not redirected automatically, <a href='https://github.com/MonitorControl/MonitorControl/tree/experimental/apple-silicon#readme'>follow this link</a>!.
</body>
</html>