MacOS IOkit 在 Swift 中按 属性 名称获取服务
MacOS IOkit get services by property name in Swift
我想获取所有包含特定属性的服务。
AppleDeviceManagementHIDEventService <class AppleDeviceManagementHIDEventService, id 0x100000a79, registered, matched, active, busy 0 (0 ms), retain 7>
| | | | | | {
| | | | | | "IOMatchedAtBoot" = Yes
| | | | | | "LowBatteryNotificationPercentage" = 2
| | | | | | "PrimaryUsagePage" = 65280
| | | | | | "BatteryFaultNotificationType" = "TPBatteryFault"
| | | | | | "HasBattery" = Yes
| | | | | | "VendorID" = 76
| | | | | | "VersionNumber" = 0
| | | | | | "Built-In" = No
| | | | | | "DeviceAddress" = "10-94-bb-ab-b9-53"
| | | | | | "WakeReason" = "Host (0x01)"
| | | | | | "Product" = "Magic Trackpad"
| | | | | | "SerialNumber" = "10-94-bb-ab-b9-53"
| | | | | | "Transport" = "Bluetooth"
| | | | | | "BatteryLowNotificationType" = "TPLowBattery"
| | | | | | "ProductID" = 613
| | | | | | "DeviceUsagePairs" = ({"DeviceUsagePage"=65280,"DeviceUsage"=11},{"DeviceUsagePage"=65280,"DeviceUsage"=20})
| | | | | | "IOPersonalityPublisher" = "com.apple.driver.AppleTopCaseHIDEventDriver"
| | | | | | "MTFW Version" = 920
| | | | | | "BD_ADDR" = <1094bbabb953>
| | | | | | "BatteryPercent" = 42
| | | | | | "BatteryStatusNotificationType" = "BatteryStatusChanged"
| | | | | | "CriticallyLowBatteryNotificationPercentage" = 1
| | | | | | "ReportInterval" = 11250
| | | | | | "RadioFW Version" = 368
| | | | | | "VendorIDSource" = 1
| | | | | | "STFW Version" = 2144
| | | | | | "CFBundleIdentifier" = "com.apple.driver.AppleTopCaseHIDEventDriver"
| | | | | | "IOProviderClass" = "IOHIDInterface"
| | | | | | "LocationID" = 1001109843
| | | | | | "BluetoothDevice" = Yes
| | | | | | "IOClass" = "AppleDeviceManagementHIDEventService"
| | | | | | "HIDServiceSupport" = No
| | | | | | "CFBundleIdentifierKernel" = "com.apple.driver.AppleTopCaseHIDEventDriver"
| | | | | | "ProductIDArray" = (613)
| | | | | | "BatteryStatusFlags" = 0
| | | | | | "ColorID" = 5
| | | | | | "IOMatchCategory" = "IODefaultMatchCategory"
| | | | | | "CountryCode" = 0
| | | | | | "IOProbeScore" = 7175
| | | | | | "PrimaryUsage" = 11
| | | | | | "IOGeneralInterest" = "IOCommand is not serializable"
| | | | | | "BTFW Version" = 368
| | | | | | }
例如。每个包含子项的服务 属性 "BatteryPercent"
.
我知道我可以通过使用 IOServiceNameMatching
然后 IOServiceGetMatchingServices
获得特定服务,但这似乎不适用于服务内的属性。有可能吗?我想通过 BatteryPercent 进行匹配,然后还获取 ProductName。
编辑:这是我目前用来获取触控板电池的代码。
func getTrackpadBattery() -> (String, Int) {
var serialPortIterator = io_iterator_t()
var object : io_object_t
var percent: Int = 0
var productName: String = ""
let masterPort: mach_port_t = kIOMainPortDefault
let matchingDict : CFDictionary = IOServiceMatching("AppleDeviceManagementHIDEventService")
let kernResult = IOServiceGetMatchingServices(masterPort, matchingDict, &serialPortIterator)
if KERN_SUCCESS == kernResult {
repeat {
object = IOIteratorNext(serialPortIterator)
if object != 0 {
let percentProperty = IORegistryEntryCreateCFProperty(object, "BatteryPercent" as CFString, kCFAllocatorDefault, 0)
if (percentProperty != nil) {
percent = (percentProperty?.takeRetainedValue() as? Int)!
productName = (IORegistryEntryCreateCFProperty(object, "Product" as CFString, kCFAllocatorDefault, 0).takeRetainedValue() as? String)!
}
}
} while percent == 0
IOObjectRelease(object)
}
IOObjectRelease(serialPortIterator)
return (productName, percent)
}
(抱歉,我真的不知道 Swift,所以我的示例在 Objective-C 中,我也尝试在 Swift 中提供它,但它可能不是对。)
kIOPropertyExistsMatchKey
匹配键应该可以完成您想要的操作。在您的匹配字典中使用它来将匹配结果限制为具有给定 属性 的 IOKit 服务。例如:
CFDictionaryRef match_dict =
(__bridge_retained CFDictionaryRef)
@{ @kIOPropertyExistsMatchKey : @"BatteryPercent" };
io_service_t service = IOServiceGetMatchingService(
kIOMasterPortDefault, match_dict);
请注意,IOKit 属性大部分未标准化,因此除非您知道特定服务(超级)class 以您的代码可以处理的方式发布 属性,服务可以通过具有任意名称的属性导出几乎任何数据,这不一定映射到您期望的含义。因此,您可能希望将以这种方式处理的注册表项限制为特定的 allow-list of IOService classes。 (通过将 "IOProviderClass"
/kIOProviderClassKey
匹配键添加到你的匹配字典中,这也是 IOServiceMatching()
吐出的内容。)至少你可能希望在解释来自未知的数据时警告用户服务 class.
在Swift(可能有误):
要返回带有 "BatteryPercent"
属性 的 all I/O 注册表项,请尝试以下内容:
[…]
let matchingDict = [ kIOPropertyExistsMatchKey: "BatteryPercent" ] as NSDictionary
let kernResult = IOServiceGetMatchingServices(masterPort, matchingDict, &iterator)
[…]
(您需要 import Foundation
才能使用 NSDictionary
。)
仅返回具有特定 class(此处:AppleDeviceManagementHIDEventService
)和 "BatteryPercent"
属性 的对象:
[…]
let matchingDict = IOServiceMatching("AppleDeviceManagementHIDEventService")
CFDictionarySetValue(matchingDict, kIOPropertyExistsMatchKey, "BatteryPercent")
let kernResult = IOServiceGetMatchingServices(masterPort, matchingDict, &iterator)
[…]
首先有错字,替换
while percent == 0
和
while object != 0
因为你只有一个 percent
和一个 productName
属性 我假设你只期望一场比赛。如果是这样,请在提取两个值后添加 break
语句。我的建议是这段代码
func getTrackpadBattery() -> (String, Int) {
var serialPortIterator = io_iterator_t()
var object : io_object_t
var percent = 0
var productName = ""
let masterPort: mach_port_t = kIOMainPortDefault
let matchingDict : CFDictionary = IOServiceMatching("AppleDeviceManagementHIDEventService")
let kernResult = IOServiceGetMatchingServices(masterPort, matchingDict, &serialPortIterator)
if KERN_SUCCESS == kernResult {
repeat {
object = IOIteratorNext(serialPortIterator)
if object != 0 {
if let percentProperty = IORegistryEntryCreateCFProperty(object, "BatteryPercent" as CFString, kCFAllocatorDefault, 0) {
percent = percentProperty.takeRetainedValue() as! Int
}
if let productProperty = IORegistryEntryCreateCFProperty(object, "Product" as CFString, kCFAllocatorDefault, 0) {
productName = productProperty.takeRetainedValue() as! String
}
break
}
} while object != 0
IOObjectRelease(object)
}
IOObjectRelease(serialPortIterator)
return (productName, percent)
}
如果要检索多个匹配项,请删除 break
语句,创建自定义结构数组并附加匹配项
struct Device {
let name : String
let batteryPercent : Int
}
func getTrackpadBattery() -> [Device] {
var serialPortIterator = io_iterator_t()
var object : io_object_t
var devices = [Device]()
let masterPort: mach_port_t = kIOMainPortDefault
let matchingDict : CFDictionary = IOServiceMatching("AppleDeviceManagementHIDEventService")
let kernResult = IOServiceGetMatchingServices(masterPort, matchingDict, &serialPortIterator)
if KERN_SUCCESS == kernResult {
repeat {
object = IOIteratorNext(serialPortIterator)
if object != 0 {
var percent = 0
var productName = ""
if let percentProperty = IORegistryEntryCreateCFProperty(object, "BatteryPercent" as CFString, kCFAllocatorDefault, 0) {
percent = percentProperty.takeRetainedValue() as! Int
}
if let productProperty = IORegistryEntryCreateCFProperty(object, "Product" as CFString, kCFAllocatorDefault, 0) {
productName = productProperty.takeRetainedValue() as! String
}
devices.append(Device(name: productName, batteryPercent: percent))
}
} while object != 0
IOObjectRelease(object)
}
IOObjectRelease(serialPortIterator)
return devices
}
我想获取所有包含特定属性的服务。
AppleDeviceManagementHIDEventService <class AppleDeviceManagementHIDEventService, id 0x100000a79, registered, matched, active, busy 0 (0 ms), retain 7>
| | | | | | {
| | | | | | "IOMatchedAtBoot" = Yes
| | | | | | "LowBatteryNotificationPercentage" = 2
| | | | | | "PrimaryUsagePage" = 65280
| | | | | | "BatteryFaultNotificationType" = "TPBatteryFault"
| | | | | | "HasBattery" = Yes
| | | | | | "VendorID" = 76
| | | | | | "VersionNumber" = 0
| | | | | | "Built-In" = No
| | | | | | "DeviceAddress" = "10-94-bb-ab-b9-53"
| | | | | | "WakeReason" = "Host (0x01)"
| | | | | | "Product" = "Magic Trackpad"
| | | | | | "SerialNumber" = "10-94-bb-ab-b9-53"
| | | | | | "Transport" = "Bluetooth"
| | | | | | "BatteryLowNotificationType" = "TPLowBattery"
| | | | | | "ProductID" = 613
| | | | | | "DeviceUsagePairs" = ({"DeviceUsagePage"=65280,"DeviceUsage"=11},{"DeviceUsagePage"=65280,"DeviceUsage"=20})
| | | | | | "IOPersonalityPublisher" = "com.apple.driver.AppleTopCaseHIDEventDriver"
| | | | | | "MTFW Version" = 920
| | | | | | "BD_ADDR" = <1094bbabb953>
| | | | | | "BatteryPercent" = 42
| | | | | | "BatteryStatusNotificationType" = "BatteryStatusChanged"
| | | | | | "CriticallyLowBatteryNotificationPercentage" = 1
| | | | | | "ReportInterval" = 11250
| | | | | | "RadioFW Version" = 368
| | | | | | "VendorIDSource" = 1
| | | | | | "STFW Version" = 2144
| | | | | | "CFBundleIdentifier" = "com.apple.driver.AppleTopCaseHIDEventDriver"
| | | | | | "IOProviderClass" = "IOHIDInterface"
| | | | | | "LocationID" = 1001109843
| | | | | | "BluetoothDevice" = Yes
| | | | | | "IOClass" = "AppleDeviceManagementHIDEventService"
| | | | | | "HIDServiceSupport" = No
| | | | | | "CFBundleIdentifierKernel" = "com.apple.driver.AppleTopCaseHIDEventDriver"
| | | | | | "ProductIDArray" = (613)
| | | | | | "BatteryStatusFlags" = 0
| | | | | | "ColorID" = 5
| | | | | | "IOMatchCategory" = "IODefaultMatchCategory"
| | | | | | "CountryCode" = 0
| | | | | | "IOProbeScore" = 7175
| | | | | | "PrimaryUsage" = 11
| | | | | | "IOGeneralInterest" = "IOCommand is not serializable"
| | | | | | "BTFW Version" = 368
| | | | | | }
例如。每个包含子项的服务 属性 "BatteryPercent"
.
我知道我可以通过使用 IOServiceNameMatching
然后 IOServiceGetMatchingServices
获得特定服务,但这似乎不适用于服务内的属性。有可能吗?我想通过 BatteryPercent 进行匹配,然后还获取 ProductName。
编辑:这是我目前用来获取触控板电池的代码。
func getTrackpadBattery() -> (String, Int) {
var serialPortIterator = io_iterator_t()
var object : io_object_t
var percent: Int = 0
var productName: String = ""
let masterPort: mach_port_t = kIOMainPortDefault
let matchingDict : CFDictionary = IOServiceMatching("AppleDeviceManagementHIDEventService")
let kernResult = IOServiceGetMatchingServices(masterPort, matchingDict, &serialPortIterator)
if KERN_SUCCESS == kernResult {
repeat {
object = IOIteratorNext(serialPortIterator)
if object != 0 {
let percentProperty = IORegistryEntryCreateCFProperty(object, "BatteryPercent" as CFString, kCFAllocatorDefault, 0)
if (percentProperty != nil) {
percent = (percentProperty?.takeRetainedValue() as? Int)!
productName = (IORegistryEntryCreateCFProperty(object, "Product" as CFString, kCFAllocatorDefault, 0).takeRetainedValue() as? String)!
}
}
} while percent == 0
IOObjectRelease(object)
}
IOObjectRelease(serialPortIterator)
return (productName, percent)
}
(抱歉,我真的不知道 Swift,所以我的示例在 Objective-C 中,我也尝试在 Swift 中提供它,但它可能不是对。)
kIOPropertyExistsMatchKey
匹配键应该可以完成您想要的操作。在您的匹配字典中使用它来将匹配结果限制为具有给定 属性 的 IOKit 服务。例如:
CFDictionaryRef match_dict =
(__bridge_retained CFDictionaryRef)
@{ @kIOPropertyExistsMatchKey : @"BatteryPercent" };
io_service_t service = IOServiceGetMatchingService(
kIOMasterPortDefault, match_dict);
请注意,IOKit 属性大部分未标准化,因此除非您知道特定服务(超级)class 以您的代码可以处理的方式发布 属性,服务可以通过具有任意名称的属性导出几乎任何数据,这不一定映射到您期望的含义。因此,您可能希望将以这种方式处理的注册表项限制为特定的 allow-list of IOService classes。 (通过将 "IOProviderClass"
/kIOProviderClassKey
匹配键添加到你的匹配字典中,这也是 IOServiceMatching()
吐出的内容。)至少你可能希望在解释来自未知的数据时警告用户服务 class.
在Swift(可能有误):
要返回带有 "BatteryPercent"
属性 的 all I/O 注册表项,请尝试以下内容:
[…]
let matchingDict = [ kIOPropertyExistsMatchKey: "BatteryPercent" ] as NSDictionary
let kernResult = IOServiceGetMatchingServices(masterPort, matchingDict, &iterator)
[…]
(您需要 import Foundation
才能使用 NSDictionary
。)
仅返回具有特定 class(此处:AppleDeviceManagementHIDEventService
)和 "BatteryPercent"
属性 的对象:
[…]
let matchingDict = IOServiceMatching("AppleDeviceManagementHIDEventService")
CFDictionarySetValue(matchingDict, kIOPropertyExistsMatchKey, "BatteryPercent")
let kernResult = IOServiceGetMatchingServices(masterPort, matchingDict, &iterator)
[…]
首先有错字,替换
while percent == 0
和
while object != 0
因为你只有一个 percent
和一个 productName
属性 我假设你只期望一场比赛。如果是这样,请在提取两个值后添加 break
语句。我的建议是这段代码
func getTrackpadBattery() -> (String, Int) {
var serialPortIterator = io_iterator_t()
var object : io_object_t
var percent = 0
var productName = ""
let masterPort: mach_port_t = kIOMainPortDefault
let matchingDict : CFDictionary = IOServiceMatching("AppleDeviceManagementHIDEventService")
let kernResult = IOServiceGetMatchingServices(masterPort, matchingDict, &serialPortIterator)
if KERN_SUCCESS == kernResult {
repeat {
object = IOIteratorNext(serialPortIterator)
if object != 0 {
if let percentProperty = IORegistryEntryCreateCFProperty(object, "BatteryPercent" as CFString, kCFAllocatorDefault, 0) {
percent = percentProperty.takeRetainedValue() as! Int
}
if let productProperty = IORegistryEntryCreateCFProperty(object, "Product" as CFString, kCFAllocatorDefault, 0) {
productName = productProperty.takeRetainedValue() as! String
}
break
}
} while object != 0
IOObjectRelease(object)
}
IOObjectRelease(serialPortIterator)
return (productName, percent)
}
如果要检索多个匹配项,请删除 break
语句,创建自定义结构数组并附加匹配项
struct Device {
let name : String
let batteryPercent : Int
}
func getTrackpadBattery() -> [Device] {
var serialPortIterator = io_iterator_t()
var object : io_object_t
var devices = [Device]()
let masterPort: mach_port_t = kIOMainPortDefault
let matchingDict : CFDictionary = IOServiceMatching("AppleDeviceManagementHIDEventService")
let kernResult = IOServiceGetMatchingServices(masterPort, matchingDict, &serialPortIterator)
if KERN_SUCCESS == kernResult {
repeat {
object = IOIteratorNext(serialPortIterator)
if object != 0 {
var percent = 0
var productName = ""
if let percentProperty = IORegistryEntryCreateCFProperty(object, "BatteryPercent" as CFString, kCFAllocatorDefault, 0) {
percent = percentProperty.takeRetainedValue() as! Int
}
if let productProperty = IORegistryEntryCreateCFProperty(object, "Product" as CFString, kCFAllocatorDefault, 0) {
productName = productProperty.takeRetainedValue() as! String
}
devices.append(Device(name: productName, batteryPercent: percent))
}
} while object != 0
IOObjectRelease(object)
}
IOObjectRelease(serialPortIterator)
return devices
}