diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 8193d2de..5dc023e8 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,3 +1,4 @@ # These are supported funding model platforms +github: MonitorControl open_collective: monitorcontrol diff --git a/.swiftlint.yml b/.swiftlint.yml index 94df041b..bd69489e 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -3,6 +3,7 @@ disabled_rules: - function_body_length - identifier_name - trailing_comma + - large_tuple type_body_length: 500 file_length: 750 cyclomatic_complexity: @@ -10,4 +11,4 @@ cyclomatic_complexity: opening_brace: allow_multiline_func: true excluded: - - .build \ No newline at end of file + - .build diff --git a/MonitorControl.xcodeproj/project.pbxproj b/MonitorControl.xcodeproj/project.pbxproj index ff295b25..bb0d8cea 100644 --- a/MonitorControl.xcodeproj/project.pbxproj +++ b/MonitorControl.xcodeproj/project.pbxproj @@ -79,6 +79,9 @@ 17DE48C5273E9DC500A1779F /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InternetAccessPolicy.strings; sourceTree = ""; }; 17DE48C6273E9DC500A1779F /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; 28D1DDF1227FBE71004CB494 /* NSScreen+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSScreen+Extension.swift"; sourceTree = ""; }; + 2FBCCED52853930200C06A13 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Main.strings; sourceTree = ""; }; + 2FBCCED62853930200C06A13 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InternetAccessPolicy.strings; sourceTree = ""; }; + 2FBCCED72853930200C06A13 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; 56754EAB1D9A4016007BCDC5 /* MonitorControl.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MonitorControl.app; sourceTree = BUILT_PRODUCTS_DIR; }; 56754EAE1D9A4016007BCDC5 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = main.swift; sourceTree = ""; }; 56754EB01D9A4016007BCDC5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -448,6 +451,7 @@ "pt-BR", cs, pl, + ru, ); mainGroup = 56754EA21D9A4016007BCDC5; packageReferences = ( @@ -651,6 +655,7 @@ AA99E81527622EBE00413316 /* pt-BR */, AA90101E27C56A0E00CC1DF7 /* cs */, AAA4BEAA2825662C004781C3 /* pl */, + 2FBCCED52853930200C06A13 /* ru */, ); name = Main.storyboard; sourceTree = ""; @@ -672,6 +677,7 @@ AA99E81627622EBE00413316 /* pt-BR */, AA90101F27C56A0E00CC1DF7 /* cs */, AAA4BEAB2825662C004781C3 /* pl */, + 2FBCCED62853930200C06A13 /* ru */, ); name = InternetAccessPolicy.strings; sourceTree = ""; @@ -693,6 +699,7 @@ AA99E81727622EBE00413316 /* pt-BR */, AA90102027C56A0E00CC1DF7 /* cs */, AAA4BEAC2825662C004781C3 /* pl */, + 2FBCCED72853930200C06A13 /* ru */, ); name = Localizable.strings; sourceTree = ""; @@ -836,7 +843,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.14; - MARKETING_VERSION = 4.1.0; + MARKETING_VERSION = 4.2.0; PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControl; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -871,7 +878,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.14; - MARKETING_VERSION = 4.1.0; + MARKETING_VERSION = 4.2.0; PRODUCT_BUNDLE_IDENTIFIER = me.guillaumeb.MonitorControl; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/MonitorControl/Info.plist b/MonitorControl/Info.plist index 6eb2d209..f055581c 100644 --- a/MonitorControl/Info.plist +++ b/MonitorControl/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 7033 + 7048 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/MonitorControl/Model/OtherDisplay.swift b/MonitorControl/Model/OtherDisplay.swift index dee05ddb..d920990e 100644 --- a/MonitorControl/Model/OtherDisplay.swift +++ b/MonitorControl/Model/OtherDisplay.swift @@ -431,9 +431,9 @@ class OtherDisplay: Display { } DisplayManager.shared.globalDDCQueue.sync { if let unwrappedDelay = delay { - values = Arm64DDC.read(service: self.arm64avService, command: controlCode, tries: UInt8(min(tries, 255)), minReplyDelay: UInt32(unwrappedDelay / 1000)) + values = Arm64DDC.read(service: self.arm64avService, command: controlCode, readSleepTime: UInt32(unwrappedDelay / 1000), numOfRetryAttemps: UInt8(min(tries, 255))) } else { - values = Arm64DDC.read(service: self.arm64avService, command: controlCode, tries: UInt8(min(tries, 255))) + values = Arm64DDC.read(service: self.arm64avService, command: controlCode, numOfRetryAttemps: UInt8(min(tries, 255))) } } } else { diff --git a/MonitorControl/Support/AppDelegate.swift b/MonitorControl/Support/AppDelegate.swift index 7e6ea158..e6df6e62 100644 --- a/MonitorControl/Support/AppDelegate.swift +++ b/MonitorControl/Support/AppDelegate.swift @@ -41,7 +41,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { displaysPrefsVc!, aboutPrefsVc!, ], - style: preferencePaneStyle, + style: self.preferencePaneStyle, animated: true ) }() diff --git a/MonitorControl/Support/Arm64DDC.swift b/MonitorControl/Support/Arm64DDC.swift index dde44f28..b6e678a9 100644 --- a/MonitorControl/Support/Arm64DDC.swift +++ b/MonitorControl/Support/Arm64DDC.swift @@ -3,32 +3,52 @@ import Foundation import IOKit -class Arm64DDC: NSObject { - public struct DisplayService { - var displayID: CGDirectDisplayID = 0 - var service: IOAVService? - var serviceLocation: Int = 0 - var isDiscouraged: Bool = false - var isDummy: Bool = false - } +let ARM64_DDC_7BIT_ADDRESS: UInt8 = 0x37 // This works with DisplayPort devices +let ARM64_DDC_DATA_ADDRESS: UInt8 = 0x51 +class Arm64DDC: NSObject { #if arch(arm64) public static let isArm64: Bool = true #else public static let isArm64: Bool = false #endif + static let MAX_MATCH_SCORE: Int = 20 - // This matches Displays to the right IOAVService - public static func getServiceMatches(displayIDs: [CGDirectDisplayID]) -> [DisplayService] { + struct IOregService { + var edidUUID: String = "" + var manufacturerID: String = "" + var productName: String = "" + var serialNumber: Int64 = 0 + var alphanumericSerialNumber: String = "" + var location: String = "" + var ioDisplayLocation: String = "" + var transportUpstream: String = "" + var transportDownstream: String = "" + var service: IOAVService? + var serviceLocation: Int = 0 + var displayAttributes: NSDictionary? + } + + struct Arm64Service { + var displayID: CGDirectDisplayID = 0 + var service: IOAVService? + var serviceLocation: Int = 0 + var discouraged: Bool = false + var dummy: Bool = false + var serviceDetails: IOregService + var matchScore: Int = 0 + } + + static func getServiceMatches(displayIDs: [CGDirectDisplayID]) -> [Arm64Service] { let ioregServicesForMatching = self.getIoregServicesForMatching() - var matchedDisplayServices: [DisplayService] = [] - var scoredCandidateDisplayServices: [Int: [DisplayService]] = [:] + var matchedDisplayServices: [Arm64Service] = [] + var scoredCandidateDisplayServices: [Int: [Arm64Service]] = [:] 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 isDummy = self.checkIfDummy(ioregService: ioregServiceForMatching) - let displayService = DisplayService(displayID: displayID, service: ioregServiceForMatching.service, serviceLocation: ioregServiceForMatching.serviceLocation, isDiscouraged: isDiscouraged, isDummy: isDummy) + let score = self.ioregMatchScore(displayID: displayID, ioregEdidUUID: ioregServiceForMatching.edidUUID, ioDisplayLocation: ioregServiceForMatching.ioDisplayLocation, ioregProductName: ioregServiceForMatching.productName, ioregSerialNumber: ioregServiceForMatching.serialNumber, serviceLocation: ioregServiceForMatching.serviceLocation) + let discouraged = self.checkIfDiscouraged(ioregService: ioregServiceForMatching) + let dummy = self.checkIfDummy(ioregService: ioregServiceForMatching) + let displayService = Arm64Service(displayID: displayID, service: ioregServiceForMatching.service, serviceLocation: ioregServiceForMatching.serviceLocation, discouraged: discouraged, dummy: dummy, serviceDetails: ioregServiceForMatching, matchScore: score) if scoredCandidateDisplayServices[score] == nil { scoredCandidateDisplayServices[score] = [] } @@ -39,24 +59,21 @@ class Arm64DDC: NSObject { 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) - } + for candidateDisplayService in scoredCandidateDisplayService where !(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)? { + static func read(service: IOAVService?, command: UInt8, writeSleepTime: UInt32? = nil, numOfWriteCycles: UInt8? = nil, readSleepTime: UInt32? = nil, numOfRetryAttemps: UInt8? = nil, retrySleepTime: UInt32? = nil) -> (current: UInt16, max: UInt16)? { var values: (UInt16, UInt16)? var send: [UInt8] = [command] var reply = [UInt8](repeating: 0, count: 11) - if Arm64DDC.performDDCCommunication(service: service, send: &send, reply: &reply, readSleepTime: minReplyDelay, numOfRetryAttemps: tries) { + if Self.performDDCCommunication(service: service, send: &send, reply: &reply, writeSleepTime: writeSleepTime, numOfWriteCycles: numOfWriteCycles, readSleepTime: readSleepTime, numOfRetryAttemps: numOfRetryAttemps, retrySleepTime: retrySleepTime) { let max = UInt16(reply[6]) * 256 + UInt16(reply[7]) let current = UInt16(reply[8]) * 256 + UInt16(reply[9]) values = (current, max) @@ -66,64 +83,41 @@ class Arm64DDC: NSObject { return values } - // Perform DDC write - public static func write(service: IOAVService?, command: UInt8, value: UInt16) -> Bool { + static func write(service: IOAVService?, command: UInt8, value: UInt16, writeSleepTime: UInt32? = nil, numOfWriteCycles: UInt8? = nil, numOfRetryAttemps: UInt8? = nil, retrySleepTime: UInt32? = nil) -> Bool { var send: [UInt8] = [command, UInt8(value >> 8), UInt8(value & 255)] var reply: [UInt8] = [] - return Arm64DDC.performDDCCommunication(service: service, send: &send, reply: &reply) + return Self.performDDCCommunication(service: service, send: &send, reply: &reply, writeSleepTime: writeSleepTime, numOfWriteCycles: numOfWriteCycles, numOfRetryAttemps: numOfRetryAttemps, retrySleepTime: retrySleepTime) } - // 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 { + static func performDDCCommunication(service: IOAVService?, send: inout [UInt8], reply: inout [UInt8], writeSleepTime: UInt32? = nil, numOfWriteCycles: UInt8? = nil, readSleepTime: UInt32? = nil, numOfRetryAttemps: UInt8? = nil, retrySleepTime: UInt32? = nil) -> Bool { + let dataAddress = ARM64_DDC_DATA_ADDRESS var success = false guard service != nil else { return success } - var checkedsend: [UInt8] = [UInt8(0x80 | (send.count + 1)), UInt8(send.count)] + send + [0] - checkedsend[checkedsend.count - 1] = self.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 - } + var packet: [UInt8] = [UInt8(0x80 | (send.count + 1)), UInt8(send.count)] + send + [0] // Note: the last byte is the place of the checksum, see next line! + packet[packet.count - 1] = self.checksum(chk: send.count == 1 ? ARM64_DDC_7BIT_ADDRESS << 1 : ARM64_DDC_7BIT_ADDRESS << 1 ^ dataAddress, data: &packet, start: 0, end: packet.count - 2) + for _ in 1 ... (numOfRetryAttemps ?? 4) + 1 { + for _ in 1 ... max((numOfWriteCycles ?? 2) + 0, 1) { + usleep(writeSleepTime ?? 10000) + success = IOAVServiceWriteI2C(service, UInt32(ARM64_DDC_7BIT_ADDRESS), UInt32(dataAddress), &packet, UInt32(packet.count)) == 0 } - if reply.count > 0 { - usleep(readSleepTime) - if IOAVServiceReadI2C(service, 0x37, 0x51, &reply, UInt32(reply.count)) == 0 { - if self.checksum(chk: 0x50, data: &reply, start: 0, end: reply.count - 2) == reply[reply.count - 1] { - success = true - } else { - success = false - } + if !reply.isEmpty { + usleep(readSleepTime ?? 50000) + if IOAVServiceReadI2C(service, UInt32(ARM64_DDC_7BIT_ADDRESS), UInt32(dataAddress), &reply, UInt32(reply.count)) == 0 { + success = self.checksum(chk: 0x50, data: &reply, start: 0, end: reply.count - 2) == reply[reply.count - 1] } } if success { return success } - usleep(retrySleepTime) + usleep(retrySleepTime ?? 20000) } 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 - // DDC checksum calculator - private static func checksum(chk: UInt8, data: inout [UInt8], start: Int, end: Int) -> UInt8 { + 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] @@ -131,8 +125,7 @@ class Arm64DDC: NSObject { return chkd } - // 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 { + static func ioregMatchScore(displayID: CGDirectDisplayID, ioregEdidUUID: String, ioDisplayLocation: String = "", ioregProductName: String = "", ioregSerialNumber: Int64 = 0, serviceLocation _: Int = 0) -> Int { var matchScore = 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 { @@ -154,66 +147,69 @@ class Arm64DDC: NSObject { + 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 + matchScore += 1 } } + if ioDisplayLocation != "", let kIODisplayLocation = dictionary[kIODisplayLocationKey] as? String, ioDisplayLocation == kIODisplayLocation { + matchScore += 10 + } if ioregProductName != "", let nameList = dictionary["DisplayProductName"] as? [String: String], let name = nameList["en_US"] ?? nameList.first?.value, name.lowercased() == ioregProductName.lowercased() { - matchScore += 2 + matchScore += 1 } 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 = "" - var service: io_service_t = IO_OBJECT_NULL + static func ioregIterateToNextObjectOfInterest(interests: [String], iterator: inout io_iterator_t) -> (name: String, entry: io_service_t, preceedingEntry: io_service_t)? { + var entry: io_service_t = IO_OBJECT_NULL + var preceedingEntry: io_service_t = IO_OBJECT_NULL let name = UnsafeMutablePointer.allocate(capacity: MemoryLayout.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 + preceedingEntry = entry + entry = IOIteratorNext(iterator) + guard IORegistryEntryGetName(entry, name) == KERN_SUCCESS, entry != MACH_PORT_NULL else { break } - if String(cString: name) == "AppleCLCD2" || String(cString: name) == "DCPAVServiceProxy" { - objectName = String(cString: name) - return (objectName, service) + let nameString = String(cString: name) + for interest in interests where entry != IO_OBJECT_NULL && nameString.contains(interest) { + return (nameString, entry, preceedingEntry) } } 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 { + static func getIORegServiceAppleCDC2Properties(entry: 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 { + if let unmanagedEdidUUID = IORegistryEntryCreateCFProperty(entry, "EDID UUID" as CFString, 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 + let cpath = UnsafeMutablePointer.allocate(capacity: MemoryLayout.size) + IORegistryEntryGetPath(entry, kIOServicePlane, cpath) + ioregService.ioDisplayLocation = String(cString: cpath) + if let unmanagedDisplayAttrs = IORegistryEntryCreateCFProperty(entry, "DisplayAttributes" as CFString, kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively)), let displayAttrs = unmanagedDisplayAttrs.takeRetainedValue() as? NSDictionary { + ioregService.displayAttributes = displayAttrs + if 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 alphanumericSerialNumber = productAttrs.value(forKey: "AlphanumericSerialNumber") as? String { + ioregService.alphanumericSerialNumber = alphanumericSerialNumber + } } } - if let unmanagedTransport = IORegistryEntryCreateCFProperty(service, CFStringCreateWithCString(kCFAllocatorDefault, "Transport", kCFStringEncodingASCII), kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively)), let transport = unmanagedTransport.takeRetainedValue() as? NSDictionary { + if let unmanagedTransport = IORegistryEntryCreateCFProperty(entry, "Transport" as CFString, kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively)), let transport = unmanagedTransport.takeRetainedValue() as? NSDictionary { if let upstream = transport.value(forKey: "Upstream") as? String { ioregService.transportUpstream = upstream } @@ -224,69 +220,56 @@ class Arm64DDC: NSObject { 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 { + static func setIORegServiceDCPAVServiceProxy(entry: io_service_t, ioregService: inout IOregService) { + if let unmanagedLocation = IORegistryEntryCreateCFProperty(entry, "Location" as CFString, kCFAllocatorDefault, IOOptionBits(kIORegistryIterateRecursively)), let location = unmanagedLocation.takeRetainedValue() as? String { ioregService.location = location if location == "External" { - ioregService.service = IOAVServiceCreateWithService(kCFAllocatorDefault, service)?.takeRetainedValue() as IOAVService + ioregService.service = IOAVServiceCreateWithService(kCFAllocatorDefault, entry)?.takeRetainedValue() as IOAVService } } } - // Returns IOAVSerivces with associated display properties for matching logic - private static func getIoregServicesForMatching() -> [IOregService] { + static func getIoregServicesForMatching() -> [IOregService] { var serviceLocation = 0 var ioregServicesForMatching: [IOregService] = [] let ioregRoot: io_registry_entry_t = IORegistryGetRootEntry(kIOMasterPortDefault) + defer { + IOObjectRelease(ioregRoot) + } var iterator = io_iterator_t() + defer { + IOObjectRelease(iterator) + } var ioregService = IOregService() guard IORegistryEntryCreateIterator(ioregRoot, "IOService", IOOptionBits(kIORegistryIterateRecursively), &iterator) == KERN_SUCCESS else { return ioregServicesForMatching } + let keyDCPAVServiceProxy = "DCPAVServiceProxy" + let keysFramebuffer = ["AppleCLCD2", "IOMobileFramebufferShim"] 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 { + guard let objectOfInterest = ioregIterateToNextObjectOfInterest(interests: [keyDCPAVServiceProxy] + keysFramebuffer, iterator: &iterator) else { break } + if keysFramebuffer.contains(objectOfInterest.name) { + ioregService = self.getIORegServiceAppleCDC2Properties(entry: objectOfInterest.entry) + serviceLocation += 1 + ioregService.serviceLocation = serviceLocation + } else if objectOfInterest.name == keyDCPAVServiceProxy { + self.setIORegServiceDCPAVServiceProxy(entry: objectOfInterest.entry, ioregService: &ioregService) + ioregServicesForMatching.append(ioregService) + } } return ioregServicesForMatching } - // Check if display is a dummy - private static func checkIfDummy(ioregService: IOregService) -> Bool { - // This is a well known dummy plug + static func checkIfDummy(ioregService: IOregService) -> Bool { if ioregService.manufacturerID == "AOC", ioregService.productName == "28E850" { return true } return false } - // Check if it is problematic to enable DDC on the display - private static func checkIfDiscouraged(ioregService: IOregService) -> Bool { - var modelIdentifier = "" - 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) - } - // First service location of M1 Mac Mini & Macbook Pro HDMI is broken for DDC communication - let ddcBlockedModels = [ - "Macmini9", // Mac mini M1 2020 - "MacBookPro18", // Macbook Pro M1 Pro/Max 2021 (14", 16") - ] - let isBlockedModel = ddcBlockedModels.contains { $0.starts(with: modelIdentifier) } - if ioregService.transportDownstream == "HDMI", ioregService.serviceLocation == 1, isBlockedModel { - return true - } - return false + static func checkIfDiscouraged(ioregService _: IOregService) -> Bool { + false } } diff --git a/MonitorControl/Support/DisplayManager.swift b/MonitorControl/Support/DisplayManager.swift index 832258d2..c09be41e 100644 --- a/MonitorControl/Support/DisplayManager.swift +++ b/MonitorControl/Support/DisplayManager.swift @@ -40,8 +40,8 @@ class DisplayManager { self.gammaActivityEnforcer.orderFrontRegardless() } - internal var shades: [CGDirectDisplayID: NSWindow] = [:] - internal var shadeGrave: [NSWindow] = [] + var shades: [CGDirectDisplayID: NSWindow] = [:] + var shadeGrave: [NSWindow] = [] func isDisqualifiedFromShade(_ displayID: CGDirectDisplayID) -> Bool { if CGDisplayIsInHWMirrorSet(displayID) != 0 || CGDisplayIsInMirrorSet(displayID) != 0 { @@ -61,7 +61,7 @@ class DisplayManager { return false } - internal func createShadeOnDisplay(displayID: CGDirectDisplayID) -> NSWindow? { + func createShadeOnDisplay(displayID: CGDirectDisplayID) -> NSWindow? { if let screen = DisplayManager.getByDisplayID(displayID: displayID) { let shade = NSWindow(contentRect: .init(origin: NSPoint(x: 0, y: 0), size: .init(width: 10, height: 1)), styleMask: [], backing: .buffered, defer: false) shade.title = "Monitor Control Window Shade for Display " + String(displayID) @@ -312,10 +312,10 @@ class DisplayManager { for otherDisplay in self.getOtherDisplays() where otherDisplay.identifier == serviceMatch.displayID && serviceMatch.service != nil { otherDisplay.arm64avService = serviceMatch.service os_log("Display service match successful for display %{public}@", type: .info, String(serviceMatch.displayID)) - if serviceMatch.isDiscouraged { + if serviceMatch.discouraged { os_log("Display %{public}@ is flagged as discouraged by Arm64DDC.", type: .info, String(serviceMatch.displayID)) otherDisplay.isDiscouraged = true - } else if serviceMatch.isDummy { + } else if serviceMatch.dummy { os_log("Display %{public}@ is flagged as dummy by Arm64DDC.", type: .info, String(serviceMatch.displayID)) otherDisplay.isDiscouraged = true otherDisplay.isDummy = true diff --git a/MonitorControl/Support/KeyboardShortcutsManager.swift b/MonitorControl/Support/KeyboardShortcutsManager.swift index 0a7ab1c8..8a837ebb 100644 --- a/MonitorControl/Support/KeyboardShortcutsManager.swift +++ b/MonitorControl/Support/KeyboardShortcutsManager.swift @@ -37,22 +37,22 @@ class KeyboardShortcutsManager { self.mute() } KeyboardShortcuts.onKeyUp(for: .brightnessUp) { [self] in - disengage() + self.disengage() } KeyboardShortcuts.onKeyUp(for: .brightnessDown) { [self] in - disengage() + self.disengage() } KeyboardShortcuts.onKeyUp(for: .contrastUp) { [self] in - disengage() + self.disengage() } KeyboardShortcuts.onKeyUp(for: .contrastDown) { [self] in - disengage() + self.disengage() } KeyboardShortcuts.onKeyUp(for: .volumeUp) { [self] in - disengage() + self.disengage() } KeyboardShortcuts.onKeyUp(for: .volumeDown) { [self] in - disengage() + self.disengage() } } diff --git a/MonitorControl/UI/cs.lproj/Main.strings b/MonitorControl/UI/cs.lproj/Main.strings index 897c914a..2b6ea723 100644 --- a/MonitorControl/UI/cs.lproj/Main.strings +++ b/MonitorControl/UI/cs.lproj/Main.strings @@ -2,7 +2,7 @@ "0ca-DG-AgB.title" = "Synchronizovat změny jasu z vestavěného displeje a z displejů Apple"; /* Class = "NSMenuItem"; title = "Assume last saved settings are valid (recommended)"; ObjectID = "1in-79-6qm"; */ -"1in-79-6qm.title" = "Předpokládat, že poslední uloežná nastavení platí (doporučeno)"; +"1in-79-6qm.title" = "Předpokládat, že poslední uložená nastavení platí (doporučeno)"; /* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */ "1PJ-14-Bvn.title" = "MonitorControl"; @@ -14,7 +14,7 @@ "1zE-fg-xEm.title" = "DDC min."; /* Class = "NSTextFieldCell"; title = "Volume down"; ObjectID = "21s-bv-GTK"; */ -"21s-bv-GTK.title" = "Volume down"; +"21s-bv-GTK.title" = "Snížit hlasitost"; /* Class = "NSMenuItem"; title = "Show separate controls for each display in menu"; ObjectID = "3eO-bN-ZRl"; */ "3eO-bN-ZRl.title" = "V nabídce zobrazovat ovládání pro každý displej zvlášť"; @@ -26,10 +26,10 @@ "4CG-0I-anB.title" = "Vlastní klávesové zkratky"; /* Class = "NSTextFieldCell"; title = "Using window focus might not work properly with full screen apps."; ObjectID = "4dX-o1-xAc"; */ -"4dX-o1-xAc.title" = "¨Možnost s aktivním oknem nemusí fungovat správně u aplikací celou obrazovku"; +"4dX-o1-xAc.title" = "Možnost s aktivním oknem nemusí fungovat správně u aplikací na celou obrazovku"; /* Class = "NSTextFieldCell"; title = "Welcome to MonitorControl"; ObjectID = "5J0-BD-top"; */ -"5J0-BD-top.title" = "Welcome to MonitorControl"; +"5J0-BD-top.title" = "Vítá vás MonitorControl"; /* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "5yT-5F-X5R"; */ "5yT-5F-X5R.title" = "Resetovat předvolby"; @@ -50,7 +50,7 @@ "8Q8-57-xnT.title" = "Používat jemnější škálu pro jas a kontrast"; /* Class = "NSButtonCell"; title = "Start using MonitorControl"; ObjectID = "8WE-da-OZC"; */ -"8WE-da-OZC.title" = "Start using MonitorControl"; +"8WE-da-OZC.title" = "Začít používat MonitorControl"; /* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */ "95V-M4-2l5.title" = "Zvláštní poděkování našim přispěvatelům!"; @@ -71,7 +71,7 @@ "AqF-uD-KCY.title" = "Určit podle názvu zvukového zařízení"; /* Class = "NSTextFieldCell"; title = "Start at Login?"; ObjectID = "bA1-GF-Y2n"; */ -"bA1-GF-Y2n.title" = "Start at Login?"; +"bA1-GF-Y2n.title" = "Spouštět po přihlášení?"; /* Class = "NSMenuItem"; title = "Show sliders only for the display currently showing the menu"; ObjectID = "bbf-sS-uGv"; */ "bbf-sS-uGv.title" = "Zobrazovat posuvníky jen pro displej, na kterém je nabídka otevřená"; @@ -200,7 +200,7 @@ "j72-NF-zsW.title" = "Spustit po přihlášení"; /* Class = "NSTextFieldCell"; title = "Toggle Mute"; ObjectID = "jK7-7w-uib"; */ -"jK7-7w-uib.title" = "Toggle Mute"; +"jK7-7w-uib.title" = "Přepnout ztlumení"; /* Class = "NSMenuItem"; title = "Change for all screens"; ObjectID = "jSj-HB-T2t"; */ "jSj-HB-T2t.title" = "Ovládat všechny obrazovky"; @@ -209,7 +209,7 @@ "jVH-oc-rUi.title" = "Vyhledat aktualizace"; /* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "JWJ-OY-VtE"; */ -"JWJ-OY-VtE.title" = "Start MonitorControl at Login"; +"JWJ-OY-VtE.title" = "Spouštět MonitorControl po přihlášení"; /* Class = "NSTextFieldCell"; title = "Note: you can press Shift during startup for 'Safe mode' to restore defaults and avoid reading or setting anything."; ObjectID = "Jx2-gO-nq9"; */ "Jx2-gO-nq9.title" = "Poznámka: Když běhěm spouštění podržíte Shift, aktivuje se tzv. ‚bezpečný režim‘ – načtou se výchozí hodnoty a z displejů se nebude nic číst ani zapisovat."; @@ -218,7 +218,7 @@ "K6A-4z-1aQ.title" = "Povolit i pro vestavěný displej a pro monitory Apple"; /* Class = "NSTextFieldCell"; title = "MonitorControl needs access to \"accessibility\" to use macOS native keys to control your display.\nYou can enable it by adding MonitorControl in System Preferences > Security and Privacy > Accessibility."; ObjectID = "kBJ-Zf-1k2"; */ -"kBJ-Zf-1k2.title" = "MonitorControl needs access to \"accessibility\" to use macOS native keys to control your display.\nYou can enable it by adding MonitorControl in System Preferences > Security and Privacy > Accessibility."; +"kBJ-Zf-1k2.title" = "Pokud chcete ovládat displeje výchozími macOS klávesami, MonitorControl pořebuje přístup ke \„zpřístupnění\“. \nMůžete ho udělit tím, že přidáte MonitorControl do sekce Předvolby systému > Zabezpečení a soukromí > Zpřístupnění."; /* Class = "NSTextFieldCell"; title = "Screen to control:"; ObjectID = "Kfj-WK-aSL"; */ "Kfj-WK-aSL.title" = "Kterou obrazovku ovládat:"; @@ -239,7 +239,7 @@ "ltL-gR-K3Z.title" = "Kterou obrazovku ovládat:"; /* Class = "NSTextFieldCell"; title = "Control your external displays brightness, contrast and volume directly from your Mac, using menulet sliders or the keyboard, including native Apple keys."; ObjectID = "Mh5-1A-apq"; */ -"Mh5-1A-apq.title" = "Control your external displays brightness, contrast and volume directly from your Mac, using menulet sliders or the keyboard, including native Apple keys."; +"Mh5-1A-apq.title" = "Ovládejte jas, kontrast a hlasitost svých externích displejů přímo z vašeho Macu pomocí posuvníků v nabídce a/nebo kláves, včetně výchozích kláves Apple."; /* Class = "NSButtonCell"; title = "Enable slider snapping"; ObjectID = "MlU-hl-d46"; */ "MlU-hl-d46.title" = "Povolit přichytávání posuvníku"; @@ -260,10 +260,10 @@ "na6-mS-MPi.title" = "Vyhnout se změnám gamy"; /* Class = "NSTextFieldCell"; title = "Ensure MonitorControl is always running when you need it by launching the app at startup."; ObjectID = "nk6-Gh-Mfs"; */ -"nk6-Gh-Mfs.title" = "Ensure MonitorControl is always running when you need it by launching the app at startup."; +"nk6-Gh-Mfs.title" = "Spouštět MonitorControl po přihlášení, aby byl vždy po ruce."; /* Class = "NSTextFieldCell"; title = "Brightness up"; ObjectID = "nty-g6-Sde"; */ -"nty-g6-Sde.title" = "Brightness up"; +"nty-g6-Sde.title" = "Zvýšit jas"; /* Class = "NSButtonCell"; title = "Separate scales for combined hardware & software dimming"; ObjectID = "O8o-hI-8eR"; */ "O8o-hI-8eR.title" = "Oddělené škály pro hardwarové a pro softwarové ztmívání zvlášť"; @@ -293,13 +293,13 @@ "psF-vX-AFB.title" = "DDC max."; /* Class = "NSButtonCell"; title = "Open System Preferences…"; ObjectID = "pVc-wG-Bdh"; */ -"pVc-wG-Bdh.title" = "Open System Preferences…"; +"pVc-wG-Bdh.title" = "Otevřít Předvolby systému…"; /* Class = "NSTextFieldCell"; title = "Use software dimming after the display reached zero hardware brightness for extended range. Works for DDC controlled displays only."; ObjectID = "PyY-p9-3NP"; */ "PyY-p9-3NP.title" = "Ztmívat přes software jakmile hardwarový jas dosáhne nuly, pro širší rozsah. Funguje jen na displejích ovládaných přes DDC."; /* Class = "NSTextFieldCell"; title = "Brightness down"; ObjectID = "q5a-Ix-Hjs"; */ -"q5a-Ix-Hjs.title" = "Brightness down"; +"q5a-Ix-Hjs.title" = "Snížit jas"; /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "QDG-SA-mRX"; */ "QDG-SA-mRX.title" = "Standardní i vlastní zkratky"; @@ -320,7 +320,7 @@ "r76-Zc-x09.title" = "Zkombinovat ztmívání přes hardware a přes software"; /* Class = "NSTextFieldCell"; title = "Enable Apple keyboard native key access"; ObjectID = "RBj-pU-aen"; */ -"RBj-pU-aen.title" = "Enable Apple keyboard native key access"; +"RBj-pU-aen.title" = "Povolit přístup k výchozím klávesám"; /* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */ "Riq-uM-bTs.title" = "Normální"; @@ -398,7 +398,7 @@ "Ytd-mg-N5E.title" = "Podle toho, kde je kurzor myši"; /* Class = "NSTextFieldCell"; title = "Volume up"; ObjectID = "Z3w-eR-qDF"; */ -"Z3w-eR-qDF.title" = "Volume up"; +"Z3w-eR-qDF.title" = "Zvýšit hlasitost"; /* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */ "ZdU-gV-V05.title" = "Používat DDC ovládání přes hardware"; diff --git a/MonitorControl/UI/de.lproj/Main.strings b/MonitorControl/UI/de.lproj/Main.strings index d19b8076..52c4bf15 100644 --- a/MonitorControl/UI/de.lproj/Main.strings +++ b/MonitorControl/UI/de.lproj/Main.strings @@ -218,7 +218,7 @@ "K6A-4z-1aQ.title" = "Auch für Apple und eingebaute Monitore aktivieren"; /* Class = "NSTextFieldCell"; title = "MonitorControl needs access to \"accessibility\" to use macOS native keys to control your display.\nYou can enable it by adding MonitorControl in System Preferences > Security and Privacy > Accessibility."; ObjectID = "kBJ-Zf-1k2"; */ -"kBJ-Zf-1k2.title" = "MonitorControl benötigt Zugriff auf \"Bedienungshilfen\", um die Tasten deines Macs zur Steuerung deines Bildschirms zu verwenden.\nDu kannst die Steuerung akivieren, indem du MonitorControl in Systemeinstellungen > Sicherheit und Datenschutz > Bedienungshilfen hinzufügst."; +"kBJ-Zf-1k2.title" = "MonitorControl benötigt Zugriff auf \"Bedienungshilfen\", um die Tasten deines Macs zur Steuerung deines Bildschirms zu verwenden.\nDu kannst die Steuerung akivieren, indem du MonitorControl in Systemeinstellungen > Datenschutz und Sicherheit > Bedienungshilfen hinzufügst."; /* Class = "NSTextFieldCell"; title = "Screen to control:"; ObjectID = "Kfj-WK-aSL"; */ "Kfj-WK-aSL.title" = "Monitor für Steuerung:"; diff --git a/MonitorControl/UI/it.lproj/Main.strings b/MonitorControl/UI/it.lproj/Main.strings index af93f64a..5db71429 100644 --- a/MonitorControl/UI/it.lproj/Main.strings +++ b/MonitorControl/UI/it.lproj/Main.strings @@ -374,7 +374,7 @@ "xjq-hs-wWB.title" = "Aggiorna le impostazioni leggendole dal monitor. Potrebbe non funzionare con alcuni hardware."; /* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ -"xLa-PN-rsq.title" = "Solo e è presente almeno uno slider"; +"xLa-PN-rsq.title" = "Solo se è presente almeno uno slider"; /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ "xQJ-aJ-VhH.title" = "Entrambe le abbreviazioni standard e personalizzate"; diff --git a/MonitorControl/UI/ko.lproj/InternetAccessPolicy.strings b/MonitorControl/UI/ko.lproj/InternetAccessPolicy.strings index 3e49b691..0013c6e2 100644 --- a/MonitorControl/UI/ko.lproj/InternetAccessPolicy.strings +++ b/MonitorControl/UI/ko.lproj/InternetAccessPolicy.strings @@ -1,8 +1,8 @@ /* General application description */ -"ApplicationDescription" = "MonitorControl allows you to control external displays brightness and volume"; +"ApplicationDescription" = "MonitorControl를 통해 외부 디스플레이의 밝기와 음량을 제어할 수 있습니다."; /* Sofware update deny consequences */ -"SoftwareUpdateDenyConsequences" = "If you deny these connections, you will not be notified about new versions and security updates. Security updates are important in order to defend against malware attacks."; +"SoftwareUpdateDenyConsequences" = "이러한 연결을 거부하면 새로운 버전과 보안 업데이트에 대한 알림을 받지 못합니다. 보안 업데이트는 멀웨어 공격을 방어하는데 중요합니다."; /* Software update purpose */ -"SoftwareUpdatePurpose" = "MonitorControl checks for new versions and security updates."; +"SoftwareUpdatePurpose" = "MonitorControl은 새로운 버전과 보안 업데이트를 확인합니다."; diff --git a/MonitorControl/UI/ko.lproj/Localizable.strings b/MonitorControl/UI/ko.lproj/Localizable.strings index 4f1c1d43..36ff5ebe 100644 --- a/MonitorControl/UI/ko.lproj/Localizable.strings +++ b/MonitorControl/UI/ko.lproj/Localizable.strings @@ -2,7 +2,7 @@ "About" = "정보"; /* Shown in the alert dialog */ -"An other app seems to change the brightness or colors which causes issues.\n\nTo solve this, you need to quit the other app or disable gamma control for your displays in MonitorControl!" = "An other app seems to change the brightness or colors which causes issues.\n\nTo solve this, you need to quit the other app or disable gamma control for your displays in MonitorControl!"; +"An other app seems to change the brightness or colors which causes issues.\n\nTo solve this, you need to quit the other app or disable gamma control for your displays in MonitorControl!" = "다른 앱이 밝기 또는 색상을 변경하여 문제를 일으키는 것 같습니다.\n\n이 문제를 해결하려면 다른 앱을 종료하거나 MonitorControl에서 디스플레이에 대한 감마 제어를 비활성화해야 합니다!"; /* Shown in the main prefs window */ "App menu" = "앱 메뉴"; @@ -56,7 +56,7 @@ "Hardware (DDC)" = "하드웨어 (DDC)"; /* Shown in the alert dialog */ -"I'll quit the other app" = "I'll quit the other app"; +"I'll quit the other app" = "다른 앱을 종료합니다."; /* Shown in the alert dialog */ "Incompatible previous version" = "호환되지 않는 이전 버전"; @@ -65,7 +65,7 @@ "Increase" = "증가"; /* Shown in the alert dialog */ -"Is f.lux or similar running?" = "Is f.lux or similar running?"; +"Is f.lux or similar running?" = "f.lux 또는 이와 유사한 기능이 실행되고 있습니까?"; /* Shown in the main prefs window */ "Keyboard" = "키보드"; @@ -83,10 +83,10 @@ "Other Display" = "그 외 디스플레이"; /* Shown in the alert dialog */ -"Preferences for an incompatible previous app version detected. Default preferences are reloaded." = "호환되지 않는 이전 앱 버전에 대한 기본 설정이 감지되었습니다. 기본 환경 설정을 다시 불러옵니다."; +"Preferences for an incompatible previous app version detected. Default preferences are reloaded." = "호환되지 않는 이전 앱 버전에 대한 기본 설정이 감지되었습니다. 기본 환경설정을 다시 불러옵니다."; /* Shown in menu */ -"Preferences…" = "환경 설정…"; +"Preferences…" = "환경설정…"; /* Shown in menu */ "Quit" = "종료"; @@ -143,10 +143,10 @@ "Virtual Display" = "가상 디스플레이"; /* Shown in menu */ -"Volume" = "볼륨"; +"Volume" = "음량"; /* Shown in the alert dialog */ "Yes" = "예"; /* Shown in the alert dialog */ -"You need to enable MonitorControl in System Preferences > Security and Privacy > Accessibility for the keyboard shortcuts to work" = "단축키가 동작하기 위해서는 시스템 환경설정 > 보안 및 개인 정보 보호 > 손쉬운 사용에서 MonitorControl 항목을 체크해야 합니다."; +"You need to enable MonitorControl in System Preferences > Security and Privacy > Accessibility for the keyboard shortcuts to work" = "단축키가 동작하기 위해서는 시스템 환경설정 > 개인정보 보호 및 보안 > 손쉬운 사용에서 MonitorControl을 활성화해야 합니다."; diff --git a/MonitorControl/UI/ko.lproj/Main.strings b/MonitorControl/UI/ko.lproj/Main.strings index 2b8e0884..d1e9ef67 100644 --- a/MonitorControl/UI/ko.lproj/Main.strings +++ b/MonitorControl/UI/ko.lproj/Main.strings @@ -8,13 +8,13 @@ "1PJ-14-Bvn.title" = "MonitorControl"; /* Class = "NSMenuItem"; title = "Standard keyboard volume and mute keys"; ObjectID = "1sy-Kd-WL5"; */ -"1sy-Kd-WL5.title" = "표준 키보드 볼륨 및 음소거 키"; +"1sy-Kd-WL5.title" = "표준 키보드 음량 및 음소거 키"; /* Class = "NSTextFieldCell"; title = "DDC min"; ObjectID = "1zE-fg-xEm"; */ "1zE-fg-xEm.title" = "DDC 최솟값"; /* Class = "NSTextFieldCell"; title = "Volume down"; ObjectID = "21s-bv-GTK"; */ -"21s-bv-GTK.title" = "Volume down"; +"21s-bv-GTK.title" = "음량 줄이기"; /* Class = "NSMenuItem"; title = "Show separate controls for each display in menu"; ObjectID = "3eO-bN-ZRl"; */ "3eO-bN-ZRl.title" = "메뉴에서 각 디스플레이에 대해 각각의 컨트롤 표시"; @@ -29,10 +29,10 @@ "4dX-o1-xAc.title" = "활성화된 창을 기준으로 하면 전체 화면 앱에서 제대로 동작하지 않을 수 있습니다."; /* Class = "NSTextFieldCell"; title = "Welcome to MonitorControl"; ObjectID = "5J0-BD-top"; */ -"5J0-BD-top.title" = "Welcome to MonitorControl"; +"5J0-BD-top.title" = "MonitorControl에 오신 것을 환영합니다"; /* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "5yT-5F-X5R"; */ -"5yT-5F-X5R.title" = "환경 설정 초기화"; +"5yT-5F-X5R.title" = "환경설정 초기화"; /* Class = "NSMenuItem"; title = "Always hide"; ObjectID = "6mo-7S-oOO"; */ "6mo-7S-oOO.title" = "항상 숨김"; @@ -50,7 +50,7 @@ "8Q8-57-xnT.title" = "미세한 OSD 스케일 사용"; /* Class = "NSButtonCell"; title = "Start using MonitorControl"; ObjectID = "8WE-da-OZC"; */ -"8WE-da-OZC.title" = "Start using MonitorControl"; +"8WE-da-OZC.title" = "MonitorControl 시작하기"; /* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */ "95V-M4-2l5.title" = "기여자에게 특별한 감사를 드립니다!"; @@ -65,13 +65,13 @@ "A8P-vn-DEJ.title" = "정확도를 위해 0%, 25%, 50%, 75% 및 100%에 눈금을 표시합니다."; /* Class = "NSTextFieldCell"; title = "Use brightness, volume and other settings from last time or use defaults. Values will be applied to the display upon first change by the user."; ObjectID = "an7-Aj-3fZ"; */ -"an7-Aj-3fZ.title" = "최근의 밝기, 볼륨 및 기타 설정을 사용하거나 기본값을 사용합니다. 값은 사용자가 처음 변경할 때 디스플레이에 적용됩니다."; +"an7-Aj-3fZ.title" = "최근의 밝기, 음량 및 기타 설정을 사용하거나 기본값을 사용합니다. 값은 사용자가 처음 변경할 때 디스플레이에 적용됩니다."; /* Class = "NSMenuItem"; title = "Use audio device name to determine which display to control"; ObjectID = "AqF-uD-KCY"; */ "AqF-uD-KCY.title" = "오디오 장치 이름을 사용하여 제어할 디스플레이 결정"; /* Class = "NSTextFieldCell"; title = "Start at Login?"; ObjectID = "bA1-GF-Y2n"; */ -"bA1-GF-Y2n.title" = "Start at Login?"; +"bA1-GF-Y2n.title" = "로그인 시 실행"; /* Class = "NSMenuItem"; title = "Show sliders only for the display currently showing the menu"; ObjectID = "bbf-sS-uGv"; */ "bbf-sS-uGv.title" = "현재 메뉴를 보여주는 디스플레이에 대한 슬라이더만 표시"; @@ -86,7 +86,7 @@ "bIe-6O-xEH.title" = "하드웨어 (DDC) 제어 디스플레이 전용. 결과는 다를 수 있습니다."; /* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */ -"bkM-Px-U3b.title" = "macOS 볼륨 OSD 비활성화"; +"bkM-Px-U3b.title" = "macOS 음량 OSD 비활성화"; /* Class = "NSTextFieldCell"; title = "OSD scale:"; ObjectID = "bP4-GJ-vhJ"; */ "bP4-GJ-vhJ.title" = "OSD 스케일:"; @@ -101,7 +101,7 @@ "bZq-0d-lJa.title" = "음소거 DDC 커맨드 활성화"; /* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "c9D-MB-lma"; */ -"c9D-MB-lma.title" = "메뉴에서 볼륨 슬라이더 표시"; +"c9D-MB-lma.title" = "메뉴에서 음량 슬라이더 표시"; /* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */ "Cle-DD-vR7.title" = "사용자 설정"; @@ -146,7 +146,7 @@ "fe9-Ia-t9m.title" = "밝기 조절:"; /* Class = "NSTextFieldCell"; title = "Volume:"; ObjectID = "FER-Ri-4UO"; */ -"FER-Ri-4UO.title" = "볼륨:"; +"FER-Ri-4UO.title" = "음량:"; /* Class = "NSButtonCell"; title = "Allow zero brightness via software or combined dimming"; ObjectID = "FjB-XL-fG5"; */ "FjB-XL-fG5.title" = "소프트웨어 또는 통합된 밝기 조절을 통해 밝기 0 허용"; @@ -194,13 +194,13 @@ "IK4-u5-qjf.title" = "부드러운 밝기 전환 활성화"; /* Class = "NSButtonCell"; title = "Use fine OSD scale for volume"; ObjectID = "J3L-MW-iJL"; */ -"J3L-MW-iJL.title" = "볼륨에 미세한 OSD 스케일 사용"; +"J3L-MW-iJL.title" = "음량에 미세한 OSD 스케일 사용"; /* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */ -"j72-NF-zsW.title" = "로그인 시 시작"; +"j72-NF-zsW.title" = "로그인 시 실행"; /* Class = "NSTextFieldCell"; title = "Toggle Mute"; ObjectID = "jK7-7w-uib"; */ -"jK7-7w-uib.title" = "Toggle Mute"; +"jK7-7w-uib.title" = "음소거 토글"; /* Class = "NSMenuItem"; title = "Change for all screens"; ObjectID = "jSj-HB-T2t"; */ "jSj-HB-T2t.title" = "모든 화면에 대해 변경"; @@ -209,7 +209,7 @@ "jVH-oc-rUi.title" = "업데이트 확인"; /* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "JWJ-OY-VtE"; */ -"JWJ-OY-VtE.title" = "Start MonitorControl at Login"; +"JWJ-OY-VtE.title" = "로그인 시 MonitorControl 실행"; /* Class = "NSTextFieldCell"; title = "Note: you can press Shift during startup for 'Safe mode' to restore defaults and avoid reading or setting anything."; ObjectID = "Jx2-gO-nq9"; */ "Jx2-gO-nq9.title" = "참고: 시작하는 동안 Shift 키를 눌러 '안전 모드'를 실행할 수 있으며, 이는 기본값을 복원하고 어떠한 것이든 읽거나 설정하지 않도록 할 수 있습니다."; @@ -218,7 +218,7 @@ "K6A-4z-1aQ.title" = "Apple 전용 및 내장 디스플레이에도 활성화"; /* Class = "NSTextFieldCell"; title = "MonitorControl needs access to \"accessibility\" to use macOS native keys to control your display.\nYou can enable it by adding MonitorControl in System Preferences > Security and Privacy > Accessibility."; ObjectID = "kBJ-Zf-1k2"; */ -"kBJ-Zf-1k2.title" = "MonitorControl needs access to \"accessibility\" to use macOS native keys to control your display.\nYou can enable it by adding MonitorControl in System Preferences > Security and Privacy > Accessibility."; +"kBJ-Zf-1k2.title" = "MonitorControl이 macOS 기본 키를 사용하여 디스플레이를 제어하려면 \"손쉬운 사용\"에 접근할 수 있어야 합니다.\n시스템 환경설정 > 개인정보 보호 및 보안 > 손쉬운 사용에서 MonitorControl을 추가하여 이 기능을 활성화할 수 있습니다."; /* Class = "NSTextFieldCell"; title = "Screen to control:"; ObjectID = "Kfj-WK-aSL"; */ "Kfj-WK-aSL.title" = "제어할 화면:"; @@ -239,7 +239,7 @@ "ltL-gR-K3Z.title" = "제어할 화면:"; /* Class = "NSTextFieldCell"; title = "Control your external displays brightness, contrast and volume directly from your Mac, using menulet sliders or the keyboard, including native Apple keys."; ObjectID = "Mh5-1A-apq"; */ -"Mh5-1A-apq.title" = "Control your external displays brightness, contrast and volume directly from your Mac, using menulet sliders or the keyboard, including native Apple keys."; +"Mh5-1A-apq.title" = "메뉴 막대 슬라이더 또는 기본 Apple 키를 포함한 키보드를 사용하여 Mac에서 직접 외부 디스플레이의 밝기, 대비 및 음량을 제어합니다."; /* Class = "NSButtonCell"; title = "Enable slider snapping"; ObjectID = "MlU-hl-d46"; */ "MlU-hl-d46.title" = "슬라이더 정렬 활성화"; @@ -251,7 +251,7 @@ "MMk-S2-yJN.title" = "대비:"; /* Class = "NSTextFieldCell"; title = "Volume:"; ObjectID = "mue-fa-8z6"; */ -"mue-fa-8z6.title" = "볼륨:"; +"mue-fa-8z6.title" = "음량:"; /* Class = "NSButtonCell"; title = "Show brightness slider in menu"; ObjectID = "MWo-6I-s9L"; */ "MWo-6I-s9L.title" = "메뉴에 밝기 슬라이더 표시"; @@ -260,10 +260,10 @@ "na6-mS-MPi.title" = "감마 테이블 조절 방지"; /* Class = "NSTextFieldCell"; title = "Ensure MonitorControl is always running when you need it by launching the app at startup."; ObjectID = "nk6-Gh-Mfs"; */ -"nk6-Gh-Mfs.title" = "Ensure MonitorControl is always running when you need it by launching the app at startup."; +"nk6-Gh-Mfs.title" = "로그인 시 앱을 실행하여 필요할 때 MonitorControl을 사용할 수 있도록 항상 실행된 상태를 유지합니다."; /* Class = "NSTextFieldCell"; title = "Brightness up"; ObjectID = "nty-g6-Sde"; */ -"nty-g6-Sde.title" = "Brightness up"; +"nty-g6-Sde.title" = "밝기 높이기"; /* Class = "NSButtonCell"; title = "Separate scales for combined hardware & software dimming"; ObjectID = "O8o-hI-8eR"; */ "O8o-hI-8eR.title" = "통합된 하드웨어 및 소프트웨어 밝기 조절을 위한 별도의 스케일"; @@ -293,13 +293,13 @@ "psF-vX-AFB.title" = "DDC 최댓값"; /* Class = "NSButtonCell"; title = "Open System Preferences…"; ObjectID = "pVc-wG-Bdh"; */ -"pVc-wG-Bdh.title" = "Open System Preferences…"; +"pVc-wG-Bdh.title" = "시스템 환경설정 열기…"; /* Class = "NSTextFieldCell"; title = "Use software dimming after the display reached zero hardware brightness for extended range. Works for DDC controlled displays only."; ObjectID = "PyY-p9-3NP"; */ "PyY-p9-3NP.title" = "디스플레이가 확장된 범위에 대해 하드웨어 밝기가 0에 도달한 후 소프트웨어 밝기 조절을 사용합니다. DDC 제어 디스플레이에서만 동작합니다."; /* Class = "NSTextFieldCell"; title = "Brightness down"; ObjectID = "q5a-Ix-Hjs"; */ -"q5a-Ix-Hjs.title" = "Brightness down"; +"q5a-Ix-Hjs.title" = "밝기 낮추기"; /* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "QDG-SA-mRX"; */ "QDG-SA-mRX.title" = "표준 및 사용자 정의 단축키 둘 다"; @@ -311,7 +311,7 @@ "qO0-dB-yUs.title" = "메뉴에 대비 슬라이더 표시"; /* Class = "NSTextFieldCell"; title = "Volume control (DDC only):"; ObjectID = "qoh-Gn-f11"; */ -"qoh-Gn-f11.title" = "볼륨 조절 (DDC 전용):"; +"qoh-Gn-f11.title" = "음량 조절 (DDC 전용):"; /* Class = "NSTextFieldCell"; title = "Show percentage next to slider for more precision."; ObjectID = "qXy-CL-Wf1"; */ "qXy-CL-Wf1.title" = "정확도를 높이기 위해 슬라이더 옆에 백분율을 표시합니다."; @@ -320,7 +320,7 @@ "r76-Zc-x09.title" = "하드웨어 및 소프트웨어 밝기 조절 통합"; /* Class = "NSTextFieldCell"; title = "Enable Apple keyboard native key access"; ObjectID = "RBj-pU-aen"; */ -"RBj-pU-aen.title" = "Enable Apple keyboard native key access"; +"RBj-pU-aen.title" = "Apple 키보드의 기본 키 접근 활성화"; /* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */ "Riq-uM-bTs.title" = "보통"; @@ -338,7 +338,7 @@ "UBq-Od-SIB.title" = "고급 설정 표시"; /* Class = "NSTextFieldCell"; title = "Works if an audio device is selected with no native volume control."; ObjectID = "uF5-a9-Ngz"; */ -"uF5-a9-Ngz.title" = "기본 볼륨 컨트롤 없이 오디오 장치를 선택한 경우 동작합니다."; +"uF5-a9-Ngz.title" = "기본 음량 컨트롤 없이 오디오 장치를 선택한 경우 동작합니다."; /* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */ "UqR-WE-jHl.title" = "디스플레이 키보드 제어 활성화"; @@ -368,7 +368,7 @@ "wjv-tq-iUx.title" = "조도 센서로 인해 변경되었거나 Touch Bar, 제어 센터, 시스템 환경설정을 사용하여 변경한 사항은 모든 디스플레이에 적용됩니다."; /* Class = "NSMenuItem"; title = "Change volume for all screens"; ObjectID = "Xih-P5-NyM"; */ -"Xih-P5-NyM.title" = "모든 화면의 볼륨 변경"; +"Xih-P5-NyM.title" = "모든 화면의 음량 변경"; /* Class = "NSTextFieldCell"; title = "Update settings from the display. May not work with some hardware."; ObjectID = "xjq-hs-wWB"; */ "xjq-hs-wWB.title" = "디스플레이에서 설정을 업데이트합니다. 일부 하드웨어에서는 동작하지 않을 수 있습니다."; @@ -398,7 +398,7 @@ "Ytd-mg-N5E.title" = "마우스 포인터 위치에 따라 다름"; /* Class = "NSTextFieldCell"; title = "Volume up"; ObjectID = "Z3w-eR-qDF"; */ -"Z3w-eR-qDF.title" = "Volume up"; +"Z3w-eR-qDF.title" = "음량 높이기"; /* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */ "ZdU-gV-V05.title" = "하드웨어 DDC 제어 사용"; diff --git a/MonitorControl/UI/ru.lproj/InternetAccessPolicy.strings b/MonitorControl/UI/ru.lproj/InternetAccessPolicy.strings new file mode 100644 index 00000000..57d905b1 --- /dev/null +++ b/MonitorControl/UI/ru.lproj/InternetAccessPolicy.strings @@ -0,0 +1,8 @@ +/* General application description */ +"ApplicationDescription" = "MonitorControl позволяет управлять яркостью и громкостью внешних дисплеев"; + +/* Sofware update deny consequences */ +"SoftwareUpdateDenyConsequences" = "Если вы откажетесь, то не будете получать уведомления о новых версиях и обновлениях системы безопасности. Обновления системы безопасности важны для защиты от вредоносных атак."; + +/* Software update purpose */ +"SoftwareUpdatePurpose" = "MonitorControl проверяет наличие новых версий и обновлений безопасности."; diff --git a/MonitorControl/UI/ru.lproj/Localizable.strings b/MonitorControl/UI/ru.lproj/Localizable.strings new file mode 100644 index 00000000..2f355372 --- /dev/null +++ b/MonitorControl/UI/ru.lproj/Localizable.strings @@ -0,0 +1,152 @@ +/* Shown in the main prefs window */ +"About" = "Информация"; + +/* Shown in the alert dialog */ +"An other app seems to change the brightness or colors which causes issues.\n\nTo solve this, you need to quit the other app or disable gamma control for your displays in MonitorControl!" = "Похоже другое приложение изменяет яркость или цвета, что вызывает проблемы.\n\nЧтобы это решить, вам нужно выйти из другого приложения или отключить управление гаммой для ваших дисплеев в MonitorControl!"; + +/* Shown in the main prefs window */ +"App menu" = "Меню"; + +/* 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." = "Вы уверены, что хотите включить более длительную задержку? Это может привести к зависанию вашей системы и потребовать перезагрузки. Эта функция будет отключена при входе в систему в качестве меры безопасности."; + +/* Shown in the alert dialog */ +"Are you sure you want to reset all preferences?" = "Вы уверены, что хотите сбросить все настройки?"; + +/* Shown in menu */ +"Brightness" = "Яркость"; + +/* Build */ +"Build" = "Релиз"; + +/* Shown in the Display Preferences */ +"Built-in Display" = "Встроенный дисплей"; + +/* Shown in menu */ +"Check for updates…" = "Проверить наличие обновлений…"; + +/* Shown in menu */ +"Contrast" = "Контраст"; + +/* Version */ +"Copyright Ⓒ MonitorControl, " = "Copyright Ⓒ MonitorControl, "; + +/* Shown in record shortcut box */ +"Decrease" = "Уменьшить"; + +/* Shown in the alert dialog */ +"Disable gamma control for my displays" = "Отключите управление гаммой для своих дисплеев"; + +/* Shown in the main prefs window */ +"Displays" = "Дисплеи"; + +/* Shown in the alert dialog */ +"Enable Longer Delay?" = "Включить более длительную задержку?"; + +/* Shown in the Display Preferences */ +"External Display" = "Внешний дисплей"; + +/* Shown in the main prefs window */ +"General" = "Основные"; + +/* Shown in the Display Preferences */ +"Hardware (Apple)" = "Оборудование (Apple)"; + +/* Shown in the Display Preferences */ +"Hardware (DDC)" = "Оборудование (DDC)"; + +/* Shown in the alert dialog */ +"I'll quit the other app" = "Я выйду из другого приложения"; + +/* Shown in the alert dialog */ +"Incompatible previous version" = "Несовместимая предыдущая версия"; + +/* Shown in record shortcut box */ +"Increase" = "Увеличить"; + +/* Shown in the alert dialog */ +"Is f.lux or similar running?" = "Работает ли f.lux или аналогичный?"; + +/* Shown in the main prefs window */ +"Keyboard" = "Клавиатура"; + +/* Shown in record shortcut box */ +"Mute" = "Беззвучный"; + +/* Shown in the alert dialog */ +"No" = "Нет"; + +/* Shown in the Display Preferences */ +"No Control" = "Не контролируемый"; + +/* Shown in the Display Preferences */ +"Other Display" = "Другой дисплей"; + +/* Shown in the alert dialog */ +"Preferences for an incompatible previous app version detected. Default preferences are reloaded." = "Обнаружены настройки для несовместимой предыдущей версии приложения. Настройки по умолчанию будут перезагружены."; + +/* Shown in menu */ +"Preferences…" = "Персональные настройки…"; + +/* Shown in menu */ +"Quit" = "Выйти"; + +/* Shown in the alert dialog */ +"Reset Preferences?" = "Сбросить настройки?"; + +/* Shown in the alert dialog */ +"Safe Mode Activated" = "Активирован безопасный режим"; + +/* Shown in the alert dialog */ +"Shift was pressed during launch. MonitorControl started in safe mode. Default preferences are reloaded, DDC read is blocked." = "Shift был нажат во время запуска. MonitorControl запущен в безопасном режиме. Настройки по умолчанию перезагружены, чтение DDC заблокировано."; + +/* Shown in the alert dialog */ +"Shortcuts not available" = "Быстрые команды недоступны"; + +/* Shown in the Display Preferences */ +"Software (gamma)" = "Программное обеспечение (гамма)"; + +/* Shown in the Display Preferences */ +"Software (gamma, forced)" = "Программное обеспечение (гамма, принудительно)"; + +/* Shown in the Display Preferences */ +"Software (shade)" = "Программное обеспечение (тень)"; + +/* Shown in the Display Preferences */ +"Software (shade, forced)" = "Программное обеспечение (тень, принудительно)"; + +/* Shown in the Display Preferences */ +"This display allows for software brightness control via gamma table manipulation or shade as it does not support hardware control. Reasons for this might be using the HDMI port of a Mac mini (which blocks hardware DDC control) or having a blacklisted display." = "Этот дисплей позволяет программно регулировать яркость с помощью манипуляций с таблицей гаммы или оттенков, поскольку он не поддерживает аппаратное управление. Причинами этого может быть использование порта HDMI Mac mini (который блокирует аппаратное управление DDC) или наличие дисплея, занесенного в черный список."; + +/* Shown in the Display Preferences */ +"This display has an unspecified control status." = "Этот дисплей имеет неопределенный статус управления."; + +/* Shown in the Display Preferences */ +"This display is reported to support hardware DDC control but the current settings allow for software control only." = "Сообщается, что этот дисплей поддерживает аппаратное управление DDC, но текущие настройки допускают только программное управление."; + +/* Shown in the Display Preferences */ +"This display is reported to support hardware DDC control. If you encounter issues, you can disable hardware DDC control to force software control." = "Сообщается, что этот дисплей поддерживает аппаратное управление DDC. Если у вас возникнут проблемы, вы можете отключить аппаратное управление DDC, чтобы принудительно управлять программным обеспечением."; + +/* Shown in the Display Preferences */ +"This display supports native Apple brightness protocol. This allows macOS to control this display without MonitorControl as well." = "Этот дисплей поддерживает собственный протокол Apple brightness protocol. Это позволяет macOS также управлять этим дисплеем без MonitorControl."; + +/* Shown in the Display Preferences */ +"This is a virtual display (examples: AirPlay, Sidecar, display connected via a DisplayLink Dock or similar) which does not allow hardware or software gammatable control. Shading is used as a substitute but only in non-mirror scenarios. Mouse cursor will be unaffected and artifacts may appear when entering/leaving full screen mode." = "Это виртуальный дисплей (примеры: AirPlay, Sidecar, дисплей, подключенный через док-станцию DisplayLink или аналогичный), который не допускает аппаратного или программного управления с возможностью воспроизведения. Затенение используется в качестве замены, но только в незеркальных сценариях. Курсор мыши не будет затронут, и при входе/выходе из полноэкранного режима могут появляться артефакты.."; + +/* Unknown display name */ +"Unknown" = "Неизвестно"; + +/* Version */ +"Version" = "Версия"; + +/* Shown in the Display Preferences */ +"Virtual Display" = "Виртуальный дисплей"; + +/* Shown in menu */ +"Volume" = "Громкость"; + +/* Shown in the alert dialog */ +"Yes" = "Да"; + +/* Shown in the alert dialog */ +"You need to enable MonitorControl in System Preferences > Security and Privacy > Accessibility for the keyboard shortcuts to work" = "Вам необходимо включить MonitorControl в разделе Системные настройки > Безопасность и конфиденциальность > Специальные возможности, чтобы сочетания клавиш работали"; diff --git a/MonitorControl/UI/ru.lproj/Main.strings b/MonitorControl/UI/ru.lproj/Main.strings new file mode 100644 index 00000000..b6128ab7 --- /dev/null +++ b/MonitorControl/UI/ru.lproj/Main.strings @@ -0,0 +1,416 @@ +/* Class = "NSButtonCell"; title = "Sync brightness changes from Built-in and Apple displays"; ObjectID = "0ca-DG-AgB"; */ +"0ca-DG-AgB.title" = "Синхронизация яркости встроенных дисплеев и дисплеев Apple"; + +/* Class = "NSMenuItem"; title = "Assume last saved settings are valid (recommended)"; ObjectID = "1in-79-6qm"; */ +"1in-79-6qm.title" = "Предположим, что последние сохраненные настройки действительны (рекомендуется)"; + +/* Class = "NSTextFieldCell"; title = "MonitorControl"; ObjectID = "1PJ-14-Bvn"; */ +"1PJ-14-Bvn.title" = "MonitorControl"; + +/* Class = "NSMenuItem"; title = "Standard keyboard volume and mute keys"; ObjectID = "1sy-Kd-WL5"; */ +"1sy-Kd-WL5.title" = "Стандартные клавиши регулировки громкости и отключения звука на клавиатуре"; + +/* Class = "NSTextFieldCell"; title = "DDC min"; ObjectID = "1zE-fg-xEm"; */ +"1zE-fg-xEm.title" = "DDC min"; + +/* Class = "NSTextFieldCell"; title = "Volume down"; ObjectID = "21s-bv-GTK"; */ +"21s-bv-GTK.title" = "Уменьшенить громкость"; + +/* Class = "NSMenuItem"; title = "Show separate controls for each display in menu"; ObjectID = "3eO-bN-ZRl"; */ +"3eO-bN-ZRl.title" = "Показывать отдельные элементы управления для каждого дисплея в меню"; + +/* Class = "NSMenuItem"; title = "Apply last saved values to the display"; ObjectID = "3Jr-bW-YYq"; */ +"3Jr-bW-YYq.title" = "Применить последние сохраненные значения к дисплею"; + +/* Class = "NSMenuItem"; title = "Custom keyboard shortcuts"; ObjectID = "4CG-0I-anB"; */ +"4CG-0I-anB.title" = "Пользовательские сочетания клавиш"; + +/* Class = "NSTextFieldCell"; title = "Using window focus might not work properly with full screen apps."; ObjectID = "4dX-o1-xAc"; */ +"4dX-o1-xAc.title" = "Использование фокуса окна может неправильно работать с полноэкранными приложениями."; + +/* Class = "NSTextFieldCell"; title = "Welcome to MonitorControl"; ObjectID = "5J0-BD-top"; */ +"5J0-BD-top.title" = "Добро пожаловать в MonitorControl"; + +/* Class = "NSButtonCell"; title = "Reset Preferences"; ObjectID = "5yT-5F-X5R"; */ +"5yT-5F-X5R.title" = "Сброс настроек"; + +/* Class = "NSMenuItem"; title = "Always hide"; ObjectID = "6mo-7S-oOO"; */ +"6mo-7S-oOO.title" = "Всегда скрывать"; + +/* Class = "NSTextFieldCell"; title = "Slider behavior:"; ObjectID = "75n-7M-1mS"; */ +"75n-7M-1mS.title" = "Поведение слайдера:"; + +/* Class = "NSButtonCell"; title = "Show slider tick marks"; ObjectID = "7zf-m1-gJO"; */ +"7zf-m1-gJO.title" = "Показывать деления ползунка"; + +/* Class = "NSTextFieldCell"; title = "Slider knob will snap to 0%, 25%, 50%, 75% and 100% when in proximity making setting these values easier. Disable for finer control."; ObjectID = "8Gx-Ya-zhp"; */ +"8Gx-Ya-zhp.title" = "Ползунок прилипает на 0%, 25%, 50%, 75% и 100% при непосредственной близости, что упрощает настройку этих значений. Отключите для более точного управления."; + +/* Class = "NSButtonCell"; title = "Use fine OSD scale for brightness and contrast"; ObjectID = "8Q8-57-xnT"; */ +"8Q8-57-xnT.title" = "Используйте тонкую экранную шкалу для определения яркости и контрастности"; + +/* Class = "NSButtonCell"; title = "Start using MonitorControl"; ObjectID = "8WE-da-OZC"; */ +"8WE-da-OZC.title" = "Начать использовать MonitorControl"; + +/* Class = "NSButtonCell"; title = "Special thanks to our contributors!"; ObjectID = "95V-M4-2l5"; */ +"95V-M4-2l5.title" = "Особая благодарность нашим контрибьютерам!"; + +/* Class = "NSMenuItem"; title = "Custom keyboard shortcuts"; ObjectID = "9eC-PD-FHl"; */ +"9eC-PD-FHl.title" = "Пользовательские сочетания клавиш"; + +/* Class = "NSMenuItem"; title = "Attempt to read display settings"; ObjectID = "9yL-no-aWa"; */ +"9yL-no-aWa.title" = "Попытка считывания настроек дисплея"; + +/* Class = "NSTextFieldCell"; title = "Show tick marks at 0%, 25%, 50%, 75% and 100% for accuracy."; ObjectID = "A8P-vn-DEJ"; */ +"A8P-vn-DEJ.title" = "Показывать деления на 0%, 25%, 50%, 75% и 100% для точности."; + +/* Class = "NSTextFieldCell"; title = "Use brightness, volume and other settings from last time or use defaults. Values will be applied to the display upon first change by the user."; ObjectID = "an7-Aj-3fZ"; */ +"an7-Aj-3fZ.title" = "Используйте яркость, громкость и другие настройки, установленные в прошлый раз, или используйте настройки по умолчанию. Значения будут применены к дисплею при первом изменении пользователем."; + +/* Class = "NSMenuItem"; title = "Use audio device name to determine which display to control"; ObjectID = "AqF-uD-KCY"; */ +"AqF-uD-KCY.title" = "Используйте имя аудиоустройства, чтобы определить, каким дисплеем управлять"; + +/* Class = "NSTextFieldCell"; title = "Start at Login?"; ObjectID = "bA1-GF-Y2n"; */ +"bA1-GF-Y2n.title" = "Запускать при входе в систему?"; + +/* Class = "NSMenuItem"; title = "Show sliders only for the display currently showing the menu"; ObjectID = "bbf-sS-uGv"; */ +"bbf-sS-uGv.title" = "Показывать ползунки только для дисплея, на котором в данный момент отображается меню"; + +/* Class = "NSTextFieldCell"; title = "Brightness:"; ObjectID = "Bhb-6l-uPQ"; */ +"Bhb-6l-uPQ.title" = "Яркость:"; + +/* Class = "NSTextFieldCell"; title = "(Software->DDC)"; ObjectID = "Bid-UL-blc"; */ +"Bid-UL-blc.title" = "(Программное обеспечение->DDC)"; + +/* Class = "NSTextFieldCell"; title = "For hardware (DDC) controlled displays only. Results may vary."; ObjectID = "bIe-6O-xEH"; */ +"bIe-6O-xEH.title" = "Только для дисплеев с аппаратным управлением (DDC). Результаты могут быть разными."; + +/* Class = "NSButtonCell"; title = "Disable macOS volume OSD"; ObjectID = "bkM-Px-U3b"; */ +"bkM-Px-U3b.title" = "Отключить экранное меню громкости macOS"; + +/* Class = "NSTextFieldCell"; title = "OSD scale:"; ObjectID = "bP4-GJ-vhJ"; */ +"bP4-GJ-vhJ.title" = "Экранная шкала:"; + +/* Class = "NSTextFieldCell"; title = "OSD scale:"; ObjectID = "Bqc-s3-C0w"; */ +"Bqc-s3-C0w.title" = "Экранная шкала:"; + +/* Class = "NSButtonCell"; title = "Reset settings"; ObjectID = "BYS-7Y-bRz"; */ +"BYS-7Y-bRz.title" = "Сброс настроек"; + +/* Class = "NSButtonCell"; title = "Enable Mute DDC command"; ObjectID = "bZq-0d-lJa"; */ +"bZq-0d-lJa.title" = "Включить команду отключения звука DDC"; + +/* Class = "NSButtonCell"; title = "Show volume slider in menu"; ObjectID = "c9D-MB-lma"; */ +"c9D-MB-lma.title" = "Показать ползунок громкости в меню"; + +/* Class = "NSMenuItem"; title = "Custom"; ObjectID = "Cle-DD-vR7"; */ +"Cle-DD-vR7.title" = "Пользовательский"; + +/* Class = "NSTextFieldCell"; title = "Upon startup or wake:"; ObjectID = "cNt-Cq-vK4"; */ +"cNt-Cq-vK4.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" = "⚠️ Внимание! Изменение некоторых из этих настроек может привести к зависанию системы или неожиданному поведению!"; + +/* Class = "NSTextFieldCell"; title = "Alternative keys are the F14/F15 (Scroll Lock and Pause on PC keyboards, brightness keys on some Logitech keyboards)."; ObjectID = "D4H-hU-FLn"; */ +"D4H-hU-FLn.title" = "Альтернативными клавишами являются клавиши F14 / F15 (блокировка прокрутки и пауза на клавиатурах ПК, клавиши яркости на некоторых клавиатурах Logitech)."; + +/* Class = "NSTextFieldCell"; title = "VCP list"; ObjectID = "D9t-vT-gNJ"; */ +"D9t-vT-gNJ.title" = "Список VCP"; + +/* Class = "NSTextFieldCell"; title = "You can override audio device name under Displays (advanced) if needed."; ObjectID = "Dha-Tm-cDM"; */ +"Dha-Tm-cDM.title" = "При необходимости вы можете переопределить имя аудиоустройства в разделе Дисплеи (дополнительно)."; + +/* Class = "NSTextFieldCell"; title = "You can disable smooth transitions for a more direct, immediate control."; ObjectID = "ENt-mP-0yH"; */ +"ENt-mP-0yH.title" = "Вы можете отключить плавные переходы для более прямого и немедленного управления."; + +/* Class = "NSMenuItem"; title = "Minimal"; ObjectID = "Eq3-z9-yIo"; */ +"Eq3-z9-yIo.title" = "Минимальный"; + +/* Class = "NSTextFieldCell"; title = "Scale mapping curve"; ObjectID = "Eui-5S-JR6"; */ +"Eui-5S-JR6.title" = "Кривая масштабного отображения"; + +/* Class = "NSTextFieldCell"; title = "Mute:"; ObjectID = "EvN-FT-vdZ"; */ +"EvN-FT-vdZ.title" = "Беззвучный:"; + +/* Class = "NSTextFieldCell"; title = "Normally keyboard controls change one OSD chiclet worth of value and Shift+Option allows fine control. This makes fine control default."; ObjectID = "f6J-Ui-uMB"; */ +"f6J-Ui-uMB.title" = "Обычно элементы управления с клавиатуры меняют значение одного экранного меню, а опция Shift + обеспечивает точное управление. Это делает fine control по умолчанию."; + +/* Class = "NSButtonCell"; title = "Reset Name"; ObjectID = "f9g-8s-gdd"; */ +"f9g-8s-gdd.title" = "Сбросить имя"; + +/* Class = "NSButtonCell"; title = "Automatically check for updates"; ObjectID = "Faf-9L-TXx"; */ +"Faf-9L-TXx.title" = "Автоматическая проверка наличия обновлений"; + +/* Class = "NSTextFieldCell"; title = "Brightness control:"; ObjectID = "fe9-Ia-t9m"; */ +"fe9-Ia-t9m.title" = "Регулировка яркости:"; + +/* Class = "NSTextFieldCell"; title = "Volume:"; ObjectID = "FER-Ri-4UO"; */ +"FER-Ri-4UO.title" = "Громкость:"; + +/* Class = "NSButtonCell"; title = "Allow zero brightness via software or combined dimming"; ObjectID = "FjB-XL-fG5"; */ +"FjB-XL-fG5.title" = "Разрешить нулевую яркость с помощью программного обеспечения или комбинированного затемнения"; + +/* Class = "NSTextFieldCell"; title = "Apple and built-in displays already have a brightness slider in Control Center."; ObjectID = "fmZ-HI-Mdc"; */ +"fmZ-HI-Mdc.title" = "Apple и встроенные дисплеи уже имеют ползунок яркости в Центре управления."; + +/* Class = "NSMenuItem"; title = "None"; ObjectID = "FoA-yh-Yx3"; */ +"FoA-yh-Yx3.title" = "Нет"; + +/* Class = "NSMenuItem"; title = "Show as icons"; ObjectID = "fR3-kq-cps"; */ +"fR3-kq-cps.title" = "Показывать в виде значков"; + +/* Class = "NSMenuItem"; title = "Show as text"; ObjectID = "fWd-Es-zsy"; */ +"fWd-Es-zsy.title" = "Показать в виде текста"; + +/* Class = "NSTextFieldCell"; title = "Invert"; ObjectID = "G5A-y3-eZz"; */ +"G5A-y3-eZz.title" = "Инвертировать"; + +/* Class = "NSMenuItem"; title = "Use window focus to determine which display to control"; ObjectID = "gTR-FW-FHc"; */ +"gTR-FW-FHc.title" = "Используйте фокус окна, чтобы определить, каким дисплеем управлять"; + +/* Class = "NSTextFieldCell"; title = "Brightness slider for hardware or software controlled displays or TVs."; ObjectID = "gXH-HL-ZOL"; */ +"gXH-HL-ZOL.title" = "Регулятор яркости для дисплеев или телевизоров с аппаратным или программным управлением."; + +/* Class = "NSTextFieldCell"; title = "Override audio device name:"; ObjectID = "H9X-it-sXs"; */ +"H9X-it-sXs.title" = "Переопределить имя аудиоустройства:"; + +/* Class = "NSTextFieldCell"; title = "Relaunch the app to access Preferences if the menu option is not accessible. Use the button below to quit the app."; ObjectID = "hF7-fM-aKr"; */ +"hF7-fM-aKr.title" = "Перезапустите приложение, чтобы получить доступ к настройкам, если пункт меню недоступен. Используйте кнопку ниже, чтобы выйти из приложения."; + +/* Class = "NSButtonCell"; title = "Get current"; ObjectID = "hkC-vq-IcD"; */ +"hkC-vq-IcD.title" = "Получить текущее значение"; + +/* Class = "NSMenuItem"; title = "Hide"; ObjectID = "HUT-Qc-kuu"; */ +"HUT-Qc-kuu.title" = "Скрыть"; + +/* Class = "NSTextFieldCell"; title = "Additional controls:"; ObjectID = "i5X-M5-Tf5"; */ +"i5X-M5-Tf5.title" = "Дополнительные элементы управления:"; + +/* Class = "NSTextFieldCell"; title = "Brightness:"; ObjectID = "IJB-mO-e8I"; */ +"IJB-mO-e8I.title" = "Яркость:"; + +/* Class = "NSButtonCell"; title = "Enable smooth brightness transitions"; ObjectID = "IK4-u5-qjf"; */ +"IK4-u5-qjf.title" = "Включить плавные переходы яркости"; + +/* Class = "NSButtonCell"; title = "Use fine OSD scale for volume"; ObjectID = "J3L-MW-iJL"; */ +"J3L-MW-iJL.title" = "Используйте тонкую экранную шкалу для определения громкости"; + +/* Class = "NSButtonCell"; title = "Start at Login"; ObjectID = "j72-NF-zsW"; */ +"j72-NF-zsW.title" = "Запуск при входе в систему"; + +/* Class = "NSTextFieldCell"; title = "Toggle Mute"; ObjectID = "jK7-7w-uib"; */ +"jK7-7w-uib.title" = "Отключить звук"; + +/* Class = "NSMenuItem"; title = "Change for all screens"; ObjectID = "jSj-HB-T2t"; */ +"jSj-HB-T2t.title" = "Изменение для всех экранов"; + +/* Class = "NSButtonCell"; title = "Check for updates"; ObjectID = "jVH-oc-rUi"; */ +"jVH-oc-rUi.title" = "Проверить наличие обновлений"; + +/* Class = "NSButtonCell"; title = "Start MonitorControl at Login"; ObjectID = "JWJ-OY-VtE"; */ +"JWJ-OY-VtE.title" = "Запуск MonitorControl при входе в систему"; + +/* Class = "NSTextFieldCell"; title = "Note: you can press Shift during startup for 'Safe mode' to restore defaults and avoid reading or setting anything."; ObjectID = "Jx2-gO-nq9"; */ +"Jx2-gO-nq9.title" = "Примечание: вы можете нажать Shift во время запуска для'Безопасного режима', чтобы восстановить значения по умолчанию и избежать чтения или настройки чего-либо."; + +/* Class = "NSButtonCell"; title = "Enable for Apple branded and built-in displays as well"; ObjectID = "K6A-4z-1aQ"; */ +"K6A-4z-1aQ.title" = "Включить также для фирменных и встроенных дисплеев Apple"; + +/* Class = "NSTextFieldCell"; title = "MonitorControl needs access to \"accessibility\" to use macOS native keys to control your display.\nYou can enable it by adding MonitorControl in System Preferences > Security and Privacy > Accessibility."; ObjectID = "kBJ-Zf-1k2"; */ +"kBJ-Zf-1k2.title" = "MonitorControl нуждается в доступе к \"специальным возможностям\", чтобы использовать собственные клавиши macOS для управления вашим дисплеем.\nВы можете включить его, добавив MonitorControl в Системные настройки > Безопасность и конфиденциальность > Специальные возможности."; + +/* Class = "NSTextFieldCell"; title = "Screen to control:"; ObjectID = "Kfj-WK-aSL"; */ +"Kfj-WK-aSL.title" = "Экран для управления:"; + +/* Class = "NSMenuItem"; title = "Depends on mouse pointer position"; ObjectID = "km4-hK-auM"; */ +"km4-hK-auM.title" = "Зависит от положения указателя мыши"; + +/* Class = "NSMenuItem"; title = "Use combined slider for all displays"; ObjectID = "lA0-tv-qRs"; */ +"lA0-tv-qRs.title" = "Использовать комбинированный ползунок для всех дисплеев"; + +/* Class = "NSTextFieldCell"; title = "Brightness and contrast:"; ObjectID = "LO4-4k-gxY"; */ +"LO4-4k-gxY.title" = "Яркость и контрастность:"; + +/* Class = "NSTextFieldCell"; title = "Display type:"; ObjectID = "lSJ-6w-KJ2"; */ +"lSJ-6w-KJ2.title" = "Тип дисплея:"; + +/* Class = "NSTextFieldCell"; title = "Screen to control:"; ObjectID = "ltL-gR-K3Z"; */ +"ltL-gR-K3Z.title" = "Экран для управления:"; + +/* Class = "NSTextFieldCell"; title = "Control your external displays brightness, contrast and volume directly from your Mac, using menulet sliders or the keyboard, including native Apple keys."; ObjectID = "Mh5-1A-apq"; */ +"Mh5-1A-apq.title" = "Управляйте яркостью, контрастностью и громкостью внешних дисплеев непосредственно с вашего Mac, используя ползунки меню или клавиатуру, включая собственные клавиши Apple."; + +/* Class = "NSButtonCell"; title = "Enable slider snapping"; ObjectID = "MlU-hl-d46"; */ +"MlU-hl-d46.title" = "Включить прилипание слайдера"; + +/* Class = "NSMenuItem"; title = "Always show in the menu bar"; ObjectID = "MM0-Lf-VgF"; */ +"MM0-Lf-VgF.title" = "Всегда отображать в строке меню"; + +/* Class = "NSTextFieldCell"; title = "Contrast:"; ObjectID = "MMk-S2-yJN"; */ +"MMk-S2-yJN.title" = "Контраст:"; + +/* Class = "NSTextFieldCell"; title = "Volume:"; ObjectID = "mue-fa-8z6"; */ +"mue-fa-8z6.title" = "Громкость:"; + +/* Class = "NSButtonCell"; title = "Show brightness slider in menu"; ObjectID = "MWo-6I-s9L"; */ +"MWo-6I-s9L.title" = "Показать ползунок яркости в меню"; + +/* Class = "NSButtonCell"; title = "Avoid gamma table manipulation"; ObjectID = "na6-mS-MPi"; */ +"na6-mS-MPi.title" = "Избегайте манипуляций с гамма-таблицей"; + +/* Class = "NSTextFieldCell"; title = "Ensure MonitorControl is always running when you need it by launching the app at startup."; ObjectID = "nk6-Gh-Mfs"; */ +"nk6-Gh-Mfs.title" = "Убедитесь, что MonitorControl всегда работает, когда вам это нужно, запустив приложение при запуске системы."; + +/* Class = "NSTextFieldCell"; title = "Brightness up"; ObjectID = "nty-g6-Sde"; */ +"nty-g6-Sde.title" = "Увеличить яркость"; + +/* Class = "NSButtonCell"; title = "Separate scales for combined hardware & software dimming"; ObjectID = "O8o-hI-8eR"; */ +"O8o-hI-8eR.title" = "Отдельные шкалы для комбинированного аппаратного и программного затемнения"; + +/* Class = "NSMenuItem"; title = "Disable keyboard"; ObjectID = "oHf-Gh-68c"; */ +"oHf-Gh-68c.title" = "Отключить клавиатуру"; + +/* Class = "NSTextFieldCell"; title = "Application:"; ObjectID = "okD-DG-pYa"; */ +"okD-DG-pYa.title" = "Приложение:"; + +/* Class = "NSMenuItem"; title = "Standard keyboard brightness keys"; ObjectID = "Oke-bW-cb1"; */ +"Oke-bW-cb1.title" = "Стандартные клавиши яркости клавиатуры"; + +/* Class = "NSTextFieldCell"; title = "count:"; ObjectID = "Orv-yj-Nad"; */ +"Orv-yj-Nad.title" = "число:"; + +/* Class = "NSTextFieldCell"; title = "Use the brightness keys of your Apple keyboard to control brightness. You can hold Control to adjust the built-in display, Control+Command to adjust external displays. Hold Shift+Option for fine control. Control+Option+Command adjusts contrast on DDC compatible displays."; ObjectID = "pa0-Hz-ace"; */ +"pa0-Hz-ace.title" = "Используйте клавиши яркости на клавиатуре Apple для управления яркостью. Вы можете удерживать клавишу Control для настройки встроенного дисплея, Control+Command для настройки внешних дисплеев. Удерживайте клавишу Shift +Option для точного управления. Control+Option+Command регулирует контрастность на дисплеях, совместимых с DDC."; + +/* Class = "NSTextFieldCell"; title = "Control method:"; ObjectID = "PaK-1f-DsW"; */ +"PaK-1f-DsW.title" = "Способ контроля:"; + +/* Class = "NSButtonCell"; title = "Longer delay during DDC read operations"; ObjectID = "pF5-Sw-7BR"; */ +"pF5-Sw-7BR.title" = "Более длительная задержка во время операций чтения DDC"; + +/* Class = "NSTextFieldCell"; title = "DDC max"; ObjectID = "psF-vX-AFB"; */ +"psF-vX-AFB.title" = "DDC max"; + +/* Class = "NSButtonCell"; title = "Open System Preferences…"; ObjectID = "pVc-wG-Bdh"; */ +"pVc-wG-Bdh.title" = "Откройте системные настройки…"; + +/* Class = "NSTextFieldCell"; title = "Use software dimming after the display reached zero hardware brightness for extended range. Works for DDC controlled displays only."; ObjectID = "PyY-p9-3NP"; */ +"PyY-p9-3NP.title" = "Используйте программное затемнение после того, как аппаратная яркость дисплея достигла нуля, для расширения диапазона. Работает только для дисплеев, управляемых DDC."; + +/* Class = "NSTextFieldCell"; title = "Brightness down"; ObjectID = "q5a-Ix-Hjs"; */ +"q5a-Ix-Hjs.title" = "Уменьшение яркости"; + +/* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "QDG-SA-mRX"; */ +"QDG-SA-mRX.title" = "Как стандартные, так и пользовательские сочетания клавиш"; + +/* Class = "NSButtonCell"; title = "Quit application"; ObjectID = "qlb-wH-qr4"; */ +"qlb-wH-qr4.title" = "Выйти из приложения"; + +/* Class = "NSButtonCell"; title = "Show contrast slider in menu"; ObjectID = "qO0-dB-yUs"; */ +"qO0-dB-yUs.title" = "Показать ползунок контраста в меню"; + +/* Class = "NSTextFieldCell"; title = "Volume control (DDC only):"; ObjectID = "qoh-Gn-f11"; */ +"qoh-Gn-f11.title" = "Регулятор громкости (только DDC):"; + +/* Class = "NSTextFieldCell"; title = "Show percentage next to slider for more precision."; ObjectID = "qXy-CL-Wf1"; */ +"qXy-CL-Wf1.title" = "Показать процент рядом с ползунком для большей точности."; + +/* Class = "NSButtonCell"; title = "Combine hardware and software dimming"; ObjectID = "r76-Zc-x09"; */ +"r76-Zc-x09.title" = "Комбинируйте аппаратное и программное затемнение"; + +/* Class = "NSTextFieldCell"; title = "Enable Apple keyboard native key access"; ObjectID = "RBj-pU-aen"; */ +"RBj-pU-aen.title" = "Включить доступ к встроенным клавишам Apple keyboard"; + +/* Class = "NSMenuItem"; title = "Normal"; ObjectID = "Riq-uM-bTs"; */ +"Riq-uM-bTs.title" = "Обычный"; + +/* Class = "NSTextFieldCell"; title = "General menu items style:"; ObjectID = "thh-DG-ecH"; */ +"thh-DG-ecH.title" = "Общий стиль пунктов меню:"; + +/* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)"; ObjectID = "TKd-J8-Iyk"; */ +"TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)"; + +/* Class = "NSTextFieldCell"; title = "Menu Icon:"; ObjectID = "u6s-Pb-BCG"; */ +"u6s-Pb-BCG.title" = "Значок меню:"; + +/* Class = "NSButtonCell"; title = "Show advanced settings"; ObjectID = "UBq-Od-SIB"; */ +"UBq-Od-SIB.title" = "Показать дополнительные настройки"; + +/* Class = "NSTextFieldCell"; title = "Works if an audio device is selected with no native volume control."; ObjectID = "uF5-a9-Ngz"; */ +"uF5-a9-Ngz.title" = "Работает, если выбрано аудиоустройство без встроенного регулятора громкости."; + +/* Class = "NSButtonCell"; title = "Enable keyboard control for display"; ObjectID = "UqR-WE-jHl"; */ +"UqR-WE-jHl.title" = "Включить управление дисплеем с клавиатуры"; + +/* Class = "NSTextFieldCell"; title = "Contrast (DDC):"; ObjectID = "urd-Rh-aiL"; */ +"urd-Rh-aiL.title" = "Контраст (DDC):"; + +/* Class = "NSButtonCell"; title = "Do not use alternative brightness keys"; ObjectID = "vd2-Lk-neX"; */ +"vd2-Lk-neX.title" = "Не использовать альтернативные клавиши регулировки яркости"; + +/* Class = "NSMenuItem"; title = "Heavy"; ObjectID = "vik-vN-bJe"; */ +"vik-vN-bJe.title" = "Тяжелый"; + +/* Class = "NSTextFieldCell"; title = "Multiple displays:"; ObjectID = "vri-pv-tJ4"; */ +"vri-pv-tJ4.title" = "Несколько дисплеев:"; + +/* Class = "NSTextFieldCell"; title = "DDC read polling mode:"; ObjectID = "vwm-hY-on5"; */ +"vwm-hY-on5.title" = "Режим опроса чтения DDC:"; + +/* Class = "NSTextFieldCell"; title = "General options:"; ObjectID = "W58-ch-j69"; */ +"W58-ch-j69.title" = "Основные настройки:"; + +/* Class = "NSTextFieldCell"; title = "Useful when a display tends to reset its settings during sleep."; ObjectID = "w8B-x6-sq5"; */ +"w8B-x6-sq5.title" = "Полезно, когда дисплей имеет тенденцию сбрасывать свои настройки во время сна."; + +/* Class = "NSTextFieldCell"; title = "Changes that are caused by the Ambient light sensor or made using Touch Bar, Control Center, System Preferences will be replicated to all displays."; ObjectID = "wjv-tq-iUx"; */ +"wjv-tq-iUx.title" = "Изменения, вызванные датчиком внешней освещенности или внесенные с помощью сенсорной панели, Центра управления, системных настроек, будут воспроизведены на всех дисплеях."; + +/* Class = "NSMenuItem"; title = "Change volume for all screens"; ObjectID = "Xih-P5-NyM"; */ +"Xih-P5-NyM.title" = "Изменять громкость для всех экранов"; + +/* Class = "NSTextFieldCell"; title = "Update settings from the display. May not work with some hardware."; ObjectID = "xjq-hs-wWB"; */ +"xjq-hs-wWB.title" = "Обновите настройки с дисплея. Может не работать с некоторым оборудованием."; + +/* Class = "NSMenuItem"; title = "Only if at least one slider is present"; ObjectID = "xLa-PN-rsq"; */ +"xLa-PN-rsq.title" = "Только при наличии хотя бы одного ползунка"; + +/* Class = "NSMenuItem"; title = "Both standard and custom shortcuts"; ObjectID = "xQJ-aJ-VhH"; */ +"xQJ-aJ-VhH.title" = "Как стандартные, так и пользовательские ярлыки"; + +/* Class = "NSTextFieldCell"; title = "Works best with various syncing and 'control all' keyboard settings enabled."; ObjectID = "XU4-Bn-bwH"; */ +"XU4-Bn-bwH.title" = "Лучше всего работает с включенными различными настройками синхронизации и 'управление всеми' настройками клавиатуры"; + +/* Class = "NSTextFieldCell"; title = "Available"; ObjectID = "yBJ-5d-I7e"; */ +"yBJ-5d-I7e.title" = "Доступно"; + +/* Class = "NSTextFieldCell"; title = "Full OSD scale will be available for hardware brightness control and after reaching 0 brightness, further software dimming will be used."; ObjectID = "YHZ-VL-QJ3"; */ +"YHZ-VL-QJ3.title" = "Для аппаратного управления яркостью будет доступна полная шкала экранного меню, а после достижения 0 яркости будет использоваться дальнейшее программное затемнение."; + +/* Class = "NSTextFieldCell"; title = "Warning! With this option enabled, you might find yourself in a position when you end up with a blank display. This, combined with disabled keyboard controls can be frustrating."; ObjectID = "yi3-e1-wsL"; */ +"yi3-e1-wsL.title" = "Внимание! Если эта опция включена, вы можете оказаться в положении, когда в итоге получите пустой дисплей. Это в сочетании с отключенным управлением с клавиатуры может привести к разочарованию."; + +/* Class = "NSTextFieldCell"; title = "Identifier:"; ObjectID = "YqZ-LS-YvR"; */ +"YqZ-LS-YvR.title" = "Идентификатор:"; + +/* Class = "NSMenuItem"; title = "Depends on mouse pointer position"; ObjectID = "Ytd-mg-N5E"; */ +"Ytd-mg-N5E.title" = "Зависит от положения указателя мыши"; + +/* Class = "NSTextFieldCell"; title = "Volume up"; ObjectID = "Z3w-eR-qDF"; */ +"Z3w-eR-qDF.title" = "Увеличить громкость"; + +/* Class = "NSButtonCell"; title = "Use hardware DDC control"; ObjectID = "ZdU-gV-V05"; */ +"ZdU-gV-V05.title" = "Использовать аппаратное управление DDC"; + +/* Class = "NSMenuItem"; title = "Disable keyboard"; ObjectID = "zHa-xo-XPW"; */ +"zHa-xo-XPW.title" = "Отключить клавиатуру"; + +/* Class = "NSButtonCell"; title = "Donate"; ObjectID = "ZKk-ve-rS4"; */ +"ZKk-ve-rS4.title" = "Пожертвовать"; + +/* Class = "NSButtonCell"; title = "Show percentages"; ObjectID = "ZUu-MR-XwA"; */ +"ZUu-MR-XwA.title" = "Показать проценты"; + +/* Class = "NSTextFieldCell"; title = "Combined dimming switchover point:"; ObjectID = "zv8-pZ-OPy"; */ +"zv8-pZ-OPy.title" = "Комбинированная точка переключения затемнения:"; diff --git a/MonitorControl/UI/zh-Hans.lproj/Localizable.strings b/MonitorControl/UI/zh-Hans.lproj/Localizable.strings index 1b159bc9..6a47f5d0 100644 --- a/MonitorControl/UI/zh-Hans.lproj/Localizable.strings +++ b/MonitorControl/UI/zh-Hans.lproj/Localizable.strings @@ -35,7 +35,7 @@ "Decrease" = "降低"; /* Shown in the alert dialog */ -"Disable gamma control for my displays" = "禁用我显示器的伽马值控制"; +"Disable gamma control for my displays" = "禁用显示器的伽马值控制"; /* Shown in the main prefs window */ "Displays" = "显示器"; @@ -89,7 +89,7 @@ "Preferences…" = "设置…"; /* Shown in menu */ -"Quit" = "关闭"; +"Quit" = "退出"; /* Shown in the alert dialog */ "Reset Preferences?" = "重置所有设置?"; @@ -128,7 +128,7 @@ "This display is reported to support hardware DDC control. If you encounter issues, you can disable hardware DDC control to force software control." = "这个显示器报告支持DDC控制。如果使用遇到问题,您可以禁用硬件DDC控制以强制软件控制。"; /* Shown in the Display Preferences */ -"This display supports native Apple brightness protocol. This allows macOS to control this display without MonitorControl as well." = "这个显示器支持苹果原生的亮度设置。MacOS也可以不通过MonitorControl控制此屏幕。"; +"This display supports native Apple brightness protocol. This allows macOS to control this display without MonitorControl as well." = "这个显示器支持苹果原生的亮度设置,macOS无需通过MonitorControl控制此屏幕。"; /* Shown in the Display Preferences */ "This is a virtual display (examples: AirPlay, Sidecar, display connected via a DisplayLink Dock or similar) which does not allow hardware or software gammatable control. Shading is used as a substitute but only in non-mirror scenarios. Mouse cursor will be unaffected and artifacts may appear when entering/leaving full screen mode." = "这个是虚拟显示器(例如:AirPlay、Sidecar、通过DisplayLink Dock或类似软件连接的屏幕),不允许硬件或软件伽马值控制。只能在非镜像的情况下以遮光(Shading)作为代替设置方案。进入/离开全屏幕模式时,鼠标将不受影响,并且可能会出现残影。"; diff --git a/MonitorControl/UI/zh-Hans.lproj/Main.strings b/MonitorControl/UI/zh-Hans.lproj/Main.strings index e2b10322..6280a29c 100644 --- a/MonitorControl/UI/zh-Hans.lproj/Main.strings +++ b/MonitorControl/UI/zh-Hans.lproj/Main.strings @@ -239,13 +239,13 @@ "ltL-gR-K3Z.title" = "控制的显示器:"; /* Class = "NSTextFieldCell"; title = "Control your external displays brightness, contrast and volume directly from your Mac, using menulet sliders or the keyboard, including native Apple keys."; ObjectID = "Mh5-1A-apq"; */ -"Mh5-1A-apq.title" = "Control your external displays brightness, contrast and volume directly from your Mac, using menulet sliders or the keyboard, including native Apple keys."; +"Mh5-1A-apq.title" = "使用菜单上的滑杆或者键盘(支持Apple原生快捷键),直接从Mac控制外接显示器的亮度、对比度和音量。"; /* Class = "NSButtonCell"; title = "Enable slider snapping"; ObjectID = "MlU-hl-d46"; */ "MlU-hl-d46.title" = "启用滑杆定位"; /* Class = "NSMenuItem"; title = "Always show in the menu bar"; ObjectID = "MM0-Lf-VgF"; */ -"MM0-Lf-VgF.title" = "永久显示于选项列"; +"MM0-Lf-VgF.title" = "永久置于菜单栏"; /* Class = "NSTextFieldCell"; title = "Contrast:"; ObjectID = "MMk-S2-yJN"; */ "MMk-S2-yJN.title" = "对比度:"; @@ -326,13 +326,13 @@ "Riq-uM-bTs.title" = "正常"; /* Class = "NSTextFieldCell"; title = "General menu items style:"; ObjectID = "thh-DG-ecH"; */ -"thh-DG-ecH.title" = "通用选项的风格"; +"thh-DG-ecH.title" = "菜单栏选项样式"; /* Class = "NSTextFieldCell"; title = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)"; ObjectID = "TKd-J8-Iyk"; */ "TKd-J8-Iyk.title" = "@the0neyouseek (Guillaume B.)\n@JoniVR (Joni Van Roost)\n@waydabber (István T.)"; /* Class = "NSTextFieldCell"; title = "Menu Icon:"; ObjectID = "u6s-Pb-BCG"; */ -"u6s-Pb-BCG.title" = "选项图标:"; +"u6s-Pb-BCG.title" = "菜单栏图标:"; /* Class = "NSButtonCell"; title = "Show advanced settings"; ObjectID = "UBq-Od-SIB"; */ "UBq-Od-SIB.title" = "显示高级选项"; diff --git a/MonitorControl/UI/zh-Hant-TW.lproj/Main.strings b/MonitorControl/UI/zh-Hant-TW.lproj/Main.strings index a181bb8a..3785d5a5 100644 --- a/MonitorControl/UI/zh-Hant-TW.lproj/Main.strings +++ b/MonitorControl/UI/zh-Hant-TW.lproj/Main.strings @@ -239,7 +239,7 @@ "ltL-gR-K3Z.title" = "控制的螢幕:"; /* Class = "NSTextFieldCell"; title = "Control your external displays brightness, contrast and volume directly from your Mac, using menulet sliders or the keyboard, including native Apple keys."; ObjectID = "Mh5-1A-apq"; */ -"Mh5-1A-apq.title" = "Control your external displays brightness, contrast and volume directly from your Mac, using menulet sliders or the keyboard, including native Apple keys."; +"Mh5-1A-apq.title" = "使用菜單上的滑桿或者鍵盤(支持Apple原生快捷鍵),直接從Mac控制外接螢幕的亮度、對比度和音量。"; /* Class = "NSButtonCell"; title = "Enable slider snapping"; ObjectID = "MlU-hl-d46"; */ "MlU-hl-d46.title" = "啟用滑桿定位"; diff --git a/MonitorControlHelper/Info.plist b/MonitorControlHelper/Info.plist index 2b3d0900..5b9f772c 100644 --- a/MonitorControlHelper/Info.plist +++ b/MonitorControlHelper/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 7033 + 7048 LSApplicationCategoryType public.app-category.utilities LSBackgroundOnly diff --git a/README.md b/README.md index a92b5cd4..01a80442 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,10 @@ Use menulet sliders or the keyboard, including native Apple keys!

## Download -Go to [Releases](https://github.com/MonitorControl/MonitorControl/releases) and download the latest `.dmg` +Go to [Releases](https://github.com/MonitorControl/MonitorControl/releases) and download the latest `.dmg`, or you can install via Homebrew: +```shell +brew install MonitorControl +``` ## Major features @@ -57,17 +60,17 @@ Go to [Releases](https://github.com/MonitorControl/MonitorControl/releases) and - Allows dimming to full black (advanced feature). - Support for custom keyboard shortcuts as well as standard brightness and media keys on Apple keyboards. - Dozens of customization options to tweak the inner workings of the app to suit your hardware and needs (don't forget to enable `Show advanced settings` in app Preferences). -- Modern, stylish and highly customizable menulet reflecting the design of Control Control introduced in Big Sur. -- Simple, unobstrusive UI to blend in to the general aesthetics of macOS (even the menu icon can be hidden). +- Modern, stylish and highly customizable menulet reflecting the design of Control Center introduced in Big Sur. +- Simple, unobtrusive UI to blend in to the general aesthetics of macOS (even the menu icon can be hidden). - Supports automatic updates for a hassle-free experience. -- The best app of its kind, completely FREE ([donations welcome](https://opencollective.com/monitorcontrol)) with the source code transparently available! +- **The best app of its kind, completely FREE ([donations welcome](https://opencollective.com/monitorcontrol)) with the source code transparently available!** ## How to install and use the app 1. [Download the app](https://github.com/MonitorControl/MonitorControl/releases) 2. Copy the MonitorControl app file from the .DMG to your Applications folder 3. Click on the `MonitorControl` app file -4. Add the app to `Accessibility` under `System Preferences` » `Security & Privacy` » `Privacy` as prompted (this is required only if you wish to use the native Apple keyboard brightness and media keys - if this is not the case, you can safely skip this step). +4. Add the app to `Accessibility` under `System Preferences` » `Privacy & Security` » `Privacy` as prompted (this is required only if you wish to use the native Apple keyboard brightness and media keys - if this is not the case, you can safely skip this step). 5. Use your keyboard or the sliders in the app menu (a brightness symbol in the macOS menubar as shown on the screenshot above) to control your displays. 6. Open `Preferences...` for customization options (enable `Show advanced settings` for even more options). 7. You can set up custom keyboard shortcuts under the `Keyboard` in Preferences (the app uses Apple media keys by default).