-
-
Notifications
You must be signed in to change notification settings - Fork 42.4k
Description
I've made this an issue instead of a PR because it probably warrants some discussion on whether or not to add this feature into QMK, but either way I think it's a good idea to at least put it in the documentation in the event that it's not implemented, so that anyone sufficiently determined can at least get some pointers on how to do so on their own. Anyway...
I wanted to see if I could get QMK to send the infamous "Apple Fn" key. It turns out I can, and it's fairly simple.
First of all, I discovered this interesting Xcode project called HID Explorer, which details all of the usage pages and usages of all your HID devices, and shows their current values. You may want to be somewhat familiar with Xcode and Objective-C to use it, though -- I had to do a little fiddling to get it to compile. Someone should really fork this and patch it up!
If you look at an Apple keyboard in HID Explorer, you can see that right at the bottom of the list is a strange entry: page 0xFF, usage 0x03. This just so happens to correspond to the usage page AppleVendorTopCase and the usage KeyboardFn, which Apple has kindly documented for us. Sure enough, pressing the Fn key causes the value of this usage to become 1.
You can also see the keyboard is indeed 5KRO as has been mentioned in previous discussions on this key. The reason for this is because the keyboard report has an extra field for the Fn key, which replaces the sixth keycode:
| Byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|---|
| Mods | Reserved | 1 | 2 | 3 | 4 | 5 | Fn |
But it doesn't have to take up a keycode slot. Because the report descriptor tells the host how to interpret the report, we can just repurpose the reserved byte for the Fn key field and it will work perfectly fine, at least within macOS. I don't know why Apple didn't just do this considering it doesn't have to deal with old BIOSes.
So, I set about replacing the declaration of the reserved byte with the Fn key descriptor elements. Then, I created a new action, ACT_APPLE_FN, and a new keycode KC_APPLE_FN and glued it all together, with an additional check in add_key_to_report() and del_key_from_report() so that they modify keyboard_report->reserved instead. In my keymap I added KC_APFN and KC_F3, compiled & flashed, and wouldn't you know it, I can toggle Exposé!
Here is the diff - it's only a proof of concept, but IMO it's pretty minimal.
But there's a catch. And it's a big one. The keyboard's vendor and product ID need to match those of a real Apple keyboard -- probably only ones with a Fn key. The product ID also seems to determine whether certain F-keys work eg. Launchpad/Mission Control and keyboard backlighting. The Manufacturer and Product strings can still be whatever you like, but this explains why there are no third-party keyboards with Apple Fn keys, and most likely rules out QMK compatible PCB/keyboard sellers from shipping boards with the key available out of the box too. I can imagine that being a bit of a dealbreaker.
Lastly, something funny I discovered: with my WASD V2 in Mac mode, it shows up in HID Explorer with the Fn key usage. When you press 6 keys at once, the value of this "Fn key" becomes the keycode of the sixth key! It looks as if WASD simply copied and pasted the report descriptor from a real Apple keyboard, but kept the same report format. So you still only get 5KRO in Mac mode, and the Fn key also does not trigger, because the vendor and product IDs are not Apple's.