检测Mac是否有背光键盘

11

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

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

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


你可以使用NSTask直接运行这个shell命令。 - idmean
@idmean 这正是我现在正在做的。 - Tzar
2个回答

9

我通过一些试错,得出了以下结论:

  • 从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
1
@Tzar:你说得对,IOServiceGetMatchingService(..., IOServiceMatching("IOResources"))也可以工作。 IORegistryEntryFromPath(...)是我设法运行的第一个版本。 我怀疑没有功能上的区别,所以选择你自己喜欢的 :) - 我仍然在macOS 11.6上,因此我没有注意到已重命名的属性。 当然,您可以使用kIOMainPortDefault。 - Martin R
1
@Tzar:已重写为在macOS 12上使用kIOMainPortDefault,并使用预定义常量而非文字字符串的IOServiceMatching。 - Martin R

1
作为 Martin优秀答案 的补充,这里是我从苹果开发技术支持处获得的笔记:

使用Swift调用I/O Kit有一定的挑战性。在这里,您有两种策略:

  • 您可以将I/O Kit API包装在Swift友好的封装器中,然后使用该封装器来完成您的任务。
  • 您可以直接执行任务,导致大量丑陋的低级Swift代码。

从I/O注册表中随机提取属性并不是确保长期二进制兼容性的最佳方法。我们的一般政策是只支持在头文件中定义了符号常量的属性(尤其是IOKitKeys.h,但还有其他一些)。KeyboardBacklight没有符号常量,因此不受支持。
确保你的代码具有防御性。这个属性可能会消失、改变意义、改变类型等等。你的代码必须在所有这些情况下都表现得合理。
请确保您提交一个“增强请求”的申请,以获取适当的API来获取此信息,并确保包括您整体目标的高级描述。enhancement request

1
更新后的代码应该满足这些要求(如果有预定义常量,请使用它们,进行防御性编程):) - Martin R

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接