Recent Apple products have the Globe (🌐︎) key on the keyboard. At the AppKit level, it is actually just a fn key that behaves as NSEvent.ModifierFlags.function
. But is there any way to know whether the keyboard that the user currently uses has the Globe key or just the fn key?
It seems that the system somehow knows it since the shortcut key display in the menu changes depending on the keyboard. The Globe symbol is shown only when the keyboard actually has the Globe key. Otherwise, it shows "fn".
But, so far, I have not found a way to detect it programmatically in the AppKit/SwiftUI world. I'd like to implement displaying keyboard shortcuts for those menu commands in my own view.
The I/O registry seems to have information about whether a globe key exists ("SupportsGlobeKey" = Yes
or No
).
In my environment (MacBook Pro 2023), ioreg -rln AppleHIDKeyboardEventDriverV2
gives the following results.
(I don't have a desktop machine, so I can't verify the absence of the Globe key).
$ ioreg -rln AppleHIDKeyboardEventDriverV2
+-o AppleHIDKeyboardEventDriverV2 <class AppleHIDKeyboardEventDriverV2, id 0x100000ba5, registered, matched, active, busy 0 (0 ms), retain 10>
| {
| "LocationID" = 49
| "IOPersonalityPublisher" = "com.apple.driver.AppleTopCaseDriverV2"
| "Keyboard" = {"Elements"=({"VariableSize"=0,"UnitExponent"=0,"IsRelative"=No,"UsagePage"=7,"Max"=1,"IsArray"=No,"Type"=2,"Size"=1,"Min"=0,"Flags"=134217730,"ReportID"=1,"Usage"=224,"ReportCount"=1,"Unit"=0,"Ha$
| "IOMatchCategory" = "IODefaultMatchCategory"
| "CapsLockLanguageSwitch" = No
| "HIDServiceSupport" = Yes
*snip*
| "KeyboardEnabled" = Yes
| "PrimaryUsagePage" = 1
| "CFBundleIdentifierKernel" = "com.apple.driver.AppleHIDKeyboard"
| "SupportsGlobeKey" = Yes
| "SensorProperties" = {}
| "ProductID" = 0
*snip*
To get I/O registry information programmatically, use IOKit
.
For example, to get whether a globe key exists, use the following code.
import IOKit
let entry = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("AppleHIDKeyboardEventDriverV2"))
if let property = IORegistryEntryCreateCFProperty(entry, "SupportsGlobeKey" as CFString, kCFAllocatorDefault, 0)?.takeRetainedValue() {
print(property) // => 1
}
IOObjectRelease(entry)