检测 Mac 是否有背光键盘

Detecting if Mac has a backlit keyboard

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

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

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

我通过反复试验得出以下结论:

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

作为 的附录,以下是我从 Apple 开发人员技术支持处获得的注释:

Calling I/O Kit from Swift is somewhat challenging. You have two strategies here:

  • You can wrap the I/O Kit API in a Swift-friendly wrapper and then use that to accomplish your task.
  • You can just go straight to your task, resulting in lots of ugly low-level Swift.

Pulling random properties out of the I/O Registry is not the best path to long-term binary compatibility. Our general policy here is that we only support properties that have symbolic constants defined in the headers (most notably IOKitKeys.h, but there are a bunch of others). KeyboardBacklight has no symbolic constant and thus isn’t supported.


Make sure you code defensively. This property might go away, change meaning, change its type, and so on. Your code must behave reasonable in all such scenarios.


Please make sure you file an enhancement request for a proper API to get this info, making sure to include a high-level description of your overall goal.