macos iokit在swift中通过属性名称获得服务

发布于 2025-01-21 14:18:11 字数 4064 浏览 3 评论 0原文

我想获得所有包含特定属性的服务。

 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)
}

I would like to get all services that contain specific properties.

 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
| | | |   |   |     }

Eg. every service that contains the child property "BatteryPercent".

I know that I can get specific service by using IOServiceNameMatching and then IOServiceGetMatchingServices, but this seems to not be working on the properties inside the service. Is it possible to that? I want to match by BatteryPercent and then also get ProductName.

EDIT: This is the code I'm currently using to get the trackpad battery.

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)
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

把人绕傻吧 2025-01-28 14:18:11

真的不知道Swift,所以我的示例是在Objective-C中

(对不起,我 能够做自己追求的事情。在匹配词典中使用它,将匹配结果限制为具有给定属性的IOKIT服务。例如:

    CFDictionaryRef match_dict =
        (__bridge_retained CFDictionaryRef)
        @{ @kIOPropertyExistsMatchKey : @"BatteryPercent" };

    io_service_t service = IOServiceGetMatchingService(
        kIOMasterPortDefault, match_dict);

请注意,IOKIT属性在大多数情况下都不标准化,因此,除非您知道特定服务(Super-)类以您的代码可以处理的方式发布属性,否任意名称,不一定映射到您期望的含义。因此,您可能需要以这种方式将您处理的注册表条目限制为ioservice类的特定允许名单。 (通过添加“ ioproviderClass”/kioproviderClassKey匹配匹配词典的键,这也是ioserviceMatching() spits of of。)在解释未知服务类的数据时,您可能需要警告用户。

在swift(可能是错误的)中:

对于 i/o注册表条目,带有“ batterypercent”属性,请尝试以下操作:(

    […]
    let matchingDict = [ kIOPropertyExistsMatchKey: "BatteryPercent" ] as NSDictionary
    let kernResult = IOServiceGetMatchingServices(masterPort, matchingDict, &iterator)
    […]

您需要>进口基础能够使用nsdictionary。)

仅用于将这些对象返回特定类(此处:appledevicemanagementhidehideventserventservice “ Batterypercent”属性:

    […]
    let matchingDict = IOServiceMatching("AppleDeviceManagementHIDEventService")
    CFDictionarySetValue(matchingDict, kIOPropertyExistsMatchKey, "BatteryPercent")
    let kernResult = IOServiceGetMatchingServices(masterPort, matchingDict, &iterator)
    […]

(Sorry, I don't really know Swift, so my example is in Objective-C and I've attempted to provide it in Swift too but it might not be right.)

The kIOPropertyExistsMatchKey matching key should be able to do what you're after. Use it in your matching dictionary to constrain the match results to IOKit services which have the property given. For example:

    CFDictionaryRef match_dict =
        (__bridge_retained CFDictionaryRef)
        @{ @kIOPropertyExistsMatchKey : @"BatteryPercent" };

    io_service_t service = IOServiceGetMatchingService(
        kIOMasterPortDefault, match_dict);

Note that IOKit properties are for the most part not standardised, so unless you know that a specific service (super-)class publishes the property in a way that your code can process, services could export just about any data via properties with arbitrary names, which does not necessarily map to the meaning you were expecting. So you might want to constrain the registry entries you process in this way to a specific allow-list of IOService classes. (By adding the "IOProviderClass"/kIOProviderClassKey matching key to your match dictionary, which is also what IOServiceMatching() spits out.) At minimum you might want to warn the user when interpreting data from an unknown service class.

In Swift (may be wrong):

For returning all I/O registry entries with the "BatteryPercent" property, try something like:

    […]
    let matchingDict = [ kIOPropertyExistsMatchKey: "BatteryPercent" ] as NSDictionary
    let kernResult = IOServiceGetMatchingServices(masterPort, matchingDict, &iterator)
    […]

(You'll need to import Foundation to be able to use NSDictionary.)

For only returning those objects with a specific class (here: AppleDeviceManagementHIDEventService) and the "BatteryPercent" property:

    […]
    let matchingDict = IOServiceMatching("AppleDeviceManagementHIDEventService")
    CFDictionarySetValue(matchingDict, kIOPropertyExistsMatchKey, "BatteryPercent")
    let kernResult = IOServiceGetMatchingServices(masterPort, matchingDict, &iterator)
    […]
〆凄凉。 2025-01-28 14:18:11

首先,有一个错字,替换

while percent == 0

while object != 0

您只有一个百分比和一个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
}

First of all there is a typo, replace

while percent == 0

with

while object != 0

As you have only one percent and one productName property I assume that you expect only one match. If so, add a break statement after extracting both values. My suggestion is this code

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)
}

If you want to retrieve multiple matches remove the break statement, create an array of a custom struct and append the matches

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文