【问题标题】:Detecting if Mac has a backlit keyboard检测 Mac 是否有背光键盘
【发布时间】:2022-01-18 10:20:24
【问题描述】:

很容易检测 Mac 是否在命令行中带有 ioreg 的发光键盘:

ioreg -c IOResources -d 3 | grep '"KeyboardBacklight" =' | sed 's/^.*= //g'

但是如何使用最新的 Swift 以编程方式获取这个 IOKit 布尔属性?我正在寻找一些示例代码。

【问题讨论】:

  • 你总是可以用 NSTask 运行这个 shell 命令。
  • @idmean 这正是我现在正在做的事情。

标签: swift macos hardware iokit


【解决方案1】:

经过反复试验,我发现了以下几点:

  • 从 IO 注册表中获取“IOResources”节点。
  • 从该节点获取“KeyboardBacklight”属性。
  • (有条件地)将属性值转换为布尔值。

我在 MacBook Air(带键盘背光)和 iMac(不带键盘背光)上对此进行了测试,在这两种情况下都产生了正确的结果。

import Foundation
import IOKit

func keyboardHasBacklight() -> Bool {
    let port: mach_port_t
    if #available(macOS 12.0, *) {
        port = kIOMainPortDefault // New name as of macOS 12
    } else {
        port = kIOMasterPortDefault // Old name up to macOS 11
    }
    let service = IOServiceGetMatchingService(port, IOServiceMatching(kIOResourcesClass))
    guard service != IO_OBJECT_NULL else {
        // Could not read IO registry node. You have to decide whether
        // to treat this as a fatal error or not.
        return false
    }
    guard let cfProp = IORegistryEntryCreateCFProperty(service, "KeyboardBacklight" as CFString,
                                                       kCFAllocatorDefault, 0)?.takeRetainedValue(),
          let hasBacklight = cfProp as? Bool
    else {
        // "KeyboardBacklight" property not present, or not a boolean.
        // This happens on Macs without keyboard backlight.
        return false
    }
    // Successfully read boolean "KeyboardBacklight" property:
    return hasBacklight
}

【讨论】:

  • 你发帖后我做了一些研究,我想知道你为什么不使用IOServiceMatchingIOServiceGetMatchingServices?由于我需要 macOS 12 或更高版本,我将使用最新的 kIOMainPortDefault 而不是旧的 kIOMasterPortDefault。谢谢!
  • @Tzar:你说得对,IOServiceGetMatchingService(..., IOServiceMatching("IOResources")) 也可以。 IORegistryEntryFromPath(...) 是我设法运行的第一个版本。我怀疑是否存在功能差异,所以选择你的选择:) – 我仍在 macOS 11.6 上,因此我没有注意到重命名的属性。您当然可以改用 kIOMainPortDefault。
  • @Tzar:重写为在 macOS 12 上使用 kIOMainPortDefault,并且 IOServiceMatching 使用预定义的常量而不是文字字符串。
【解决方案2】:

作为Martin’s excellent answer 的附录,以下是我从 Apple 开发者技术支持处获得的说明:

从 Swift 调用 I/O Kit 有点挑战性。你有 这里有两种策略:

  • 您可以将 I/O Kit API 包装在一个对 Swift 友好的包装器中,然后使用它来完成您的任务。
  • 您可以直接执行您的任务,从而产生许多丑陋的低级 Swift。

从 I/O 注册表中提取随机属性不是最佳路径 长期二进制兼容性。我们的一般政策是,我们 仅支持在 标头(最值得注意的是IOKitKeys.h,但还有很多其他的)。 KeyboardBacklight 没有符号常量,因此不受支持。


确保您进行防御性编码。此属性可能会消失,请更改 意义,改变它的类型,等等。您的代码必须表现得合理 在所有此类情况下。


请确保提交enhancement request 以获得适当的 API 获取此信息,确保包含您的高级描述 总体目标。

【讨论】:

  • 更新后的代码应该满足这个要求(如果可用,使用预定义的常量,防御性代码):)
猜你喜欢
  • 2022-12-05
  • 1970-01-01
  • 2019-07-02
  • 2023-03-18
  • 2012-04-04
  • 2012-07-10
  • 2011-11-24
  • 2011-05-03
  • 1970-01-01
相关资源
最近更新 更多