Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The Apple Fn Key #2179

Closed
fauxpark opened this issue Dec 20, 2017 · 35 comments
Closed

The Apple Fn Key #2179

fauxpark opened this issue Dec 20, 2017 · 35 comments

Comments

@fauxpark
Copy link
Member

fauxpark commented Dec 20, 2017

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.

@skullydazed
Copy link
Member

This is very cool, but I don't know how we possibly include this. Leaving this open to discus the possibility for now.

@drashna
Copy link
Member

drashna commented Mar 25, 2018

@skullydazed Short of maybe a feature option that overrides the normal 6KRO code. (eg "APPLE_NKRO", maybe).

But not sure how Apple would feel about us doing that, given that we have to use their VID and PID to get this working.

@fauxpark
Copy link
Member Author

There would have to be some kind of warning if the feature is enabled, reminding users that it won't work unless they change their VID/PID - putting those values into the repo, even for checking, is probably a bad idea. I can see this may not be very "QMK".

I've also found that the PID can determine functionality amongst Apple keyboards - on my 2011 MBP, the F4 key has a little gauge symbol on it and opens the Dashboard. On my 2017 MBP it has a different symbol, and opens Launchpad.

QMK is meant to be customised though, even if you can't push your cool "Apple" keyboard back to the repo, we should at least be able to say that it is technically possible.

@jsoltren
Copy link

I noticed that matias keyboards offer a Mac version with an fn key. So I picked up a matias wired aluminum keyboard, plugged it into my Mac, and checked out what happened.

This is really interesting:

`Matias Wired Keyboard:

Product ID: 0x024f
Vendor ID: 0x05ac (Apple Inc.)
Version: 1.91
Serial Number: FK318VUS
Speed: Up to 12 Mb/sec
Manufacturer: Matias Keyboard
Location ID: 0x14210000 / 16
Current Available (mA): 500
Current Required (mA): 100
Extra Operating Current (mA): 0`

Looks like they just straight up lie about their Vendor ID. 0x024f is not a known Apple product ID, in that it doesn't appear in pci.ids:

https://usb-ids.gowdy.us/read/UD/05ac
http://www.linux-usb.org/usb.ids

@Syzygies
Copy link

Syzygies commented Feb 26, 2020

Karabiner Elements can remap arbitrary keys to mission_control, launchpad, or other Mac uses for function keys.

It is good engineering to choose the right layer in which to work. I'm constantly revising VSCode-specific key mappings as I work, by editing a CSV file that updates Karabiner via Goku, and an on-screen crib sheet. One wants one's keyboard firmware to be fully functional in case a software layer like Karabiner isn't present, but it makes no sense to be reflashing a keyboard's firmware all the time. Rather, you're here to design a keyboard you can live with. So involving Karabiner is a good thing. For example, it can implement tap or hold without a timer, so the key fires on key-up no matter what the delay, if it isn't used as a modifier. I haven't figured out how to do this yet in QMK.

I use the Mac function key internally in Karabiner, as a modifier flag for internal use that I can be sure no application is expecting. I won't be using that trick with QMK. However, the Mac also equivalences left and right modifiers, so no app can be looking for both left control and right control, for example. This is another way that QMK can set modifiers to be trapped by Karabiner, without interfering with any downstream app. Karabiner sees the left, right distinctions, but apps don't.

@jsoltren
Copy link

Karabiner Elements does its remapping with a kernel driver. It's the "right" way, inasmuch as having to hack the kernel to work around the USB stack is considered right.

Apple is constantly trying to clamp down on kernel development. Karabiner Elements was itself a rewrite of Karabiner. In that regard QMK is more "stable" across OSes.

@Syzygies
Copy link

I'm likely to contribute to QMK once I get my sea legs. Yes, there was a lapse without Karabiner, and Apple is warning again of impending changes to kexts.

The "Oryx" key on an ErgoDox EZ or Planck EZ sets up two-way communication with QMK firmware. It would be ideal to continually tweak key macros on the fly, through a program that helped the user as the Oryx trainer does, without having to either reflash the keyboard or rely on kexts. The Proton C, for example, certainly has the memory and processing power. I can live without mission_control, and I'd love not to be worried about the future of kexts.

@Nuru
Copy link

Nuru commented Apr 19, 2020

It's April 2020 and things seem to have changed. I have a 2019 MacBook Pro with a Microsoft full-size ANSI keyboard:

  Product ID:	0x00db
  Vendor ID:	0x045e  (Microsoft Corporation)
  Version:	1.73

and it has the "Insert" key mapped to the "fn" key under macOS 10.15 Catalina. Even the Mac Keyboard Viewer shows the insert key as labeled "fn" (under El Capitan, the keycap was labeled "?⃝" for "Help"). I also note that the "fn" key on the built-in keyboard sends a keycode just like every other key; it does not seem to be special in any way.

So I would hope that QMK can now map a key to "fn", or failing that, can map a key in such a way that Karabiner can map it to "fn". At the moment, the Dygma Raise (using QMK) can do neither, and is not going to try, citing this QMK issue as the reason. It would be great to have this feature at least workable if not fully supported.

@skullydazed
Copy link
Member

@Nuru That's an interesting observation. Do you have the microsoft software installed for your keyboard?

@jsoltren
Copy link

@Nuru that's really interesting. I wonder if this is related to particular keyboards, particular versions of the macOS, particular systems (can't rule out macOS behaving differently on your 2019 system), or if this indicates kernel level change in the macOS. I did not see this behavior on earlier versions of macOS 10.15.

I have a Mid-2012 MacBook Air running 10.15.4. I definitely don't see this behavior with my Novatouch.

Could it be specific to the VID/PID mentioned earlier? It would be a good experiment to flash a QMK keyboard with this VID/PID to see if we can reproduce this result.

@Nuru
Copy link

Nuru commented Apr 19, 2020

@skullydazed No, I do not have any special software installed for the keyboard.
I realize now that I do have Karabiner-Elements 12.9.0 installed, and that is handling the mapping of "Insert" to "fn" somehow. I don't know if/how it is changing the keycap in the keyboard viewer. I did spend a lot of time in the past trying to get the "fn" key on the Dygma Raise to work as an "fn" key, without success, so I may have set this up, but it seems unlike me to choose the "Insert" key as the key to map to "fn". I would tend to choose a completely unused key like "Scroll Lock" or "Print Screen" rather than "Insert", which still is used by some applications.

@jsoltren I have an 2013 MacBook running 10.14 Mojave and the "fn" key sends a keydown and keyup event. It is not just some internal modifier.

Also, I just got my 34 key keypad

  Product ID:	0x2012
  Vendor ID:	0x05c7  (Qtronix Corp)
  Version:	1.00

and Karabiner maps its "Insert" key to "fn" no problem.

It's possible a lot of this is being done by the Karabiner kernel extension. I have quit the application and seen the mapping go away, but the keycap stays and the built-in keyboard's function key stays the same. I have not tried fully uninstalling Karabiner yet.

The other interesting thing is that Karabiner-EventViewer reports the "fn" keycode as 65538. That is outside the range of a 16 bit number. It is binary 1 0000 0000 0000 0010. This suggest the kernel extension is at play.

My general attitude about all this is that Karabiner is a thing, lots of people use Macs, and it is not unreasonable to ask QMK to implement a feature that only works in conjunction with Karabiner. It would be great if QMK could get the "fn" key to work without Karabiner, but if that is too hard, it would still be helpful for QMK to support a special keycode that you then feed into Karabiner as "fn" so that I don't have to give up an existing key for it.

@jsoltren
Copy link

@Nuru Karabiner, being implemented with an actual kernel extension, enables emulation of the true fn key at the kernel level. I use this myself on some systems and I've glanced at the Karabiner sources.

@skullydazed may have a different opinion but my view is that the firmware should not be doing anything special for some particular kernel or user program. You can program any key to send any key code, and catch that in kernel or user space for your need. This seems sufficient to me.

What I do support, is an optional build flag for faking an Apple VID/PID. Apple wouldn't be too happy about this shipping, but what you do on your own keyboard is between you and your console.

@Nuru, if you have a chance, could you try completely uninstalling Karabiner, restarting, and trying again? There are instructions for a full Karabiner uninstall (which is necessary in this case) on pqrs.org.

@Nuru
Copy link

Nuru commented Apr 20, 2020

At the very least, I can say that one thing that has changed since this issue was created is that it is no longer true that "there are no third-party keyboards with Apple Fn keys".

@jsoltren I did a full uninstall of Karabiner and rebooted, and nothing changed that didn't change when I quit Karabiner.

I recall now that what got me started down this path was seeing Apple's external Magic Keyboard with Numeric Keypad, which I thought was a normal USB keyboard, has the "fn" key where ANSI keyboards have the "Insert" key. So I thought any USB keyboard could do it.

Now I realize that (1) it is a Bluetooth keyboard, not USB, and (2) Apple provides special treatment for their own peripherals. It does, at least, explain how "fn" ended up on the "Insert" key on the Keyboard viewer and why I tried that mapping in Karabiner.

On the other hand, I note that the Logitech Wireless Solar Keyboard K750 (Mac version) also has the "fn" key in the same place (replacing the "Insert" key), so it is not strictly limited to Apple keyboards, and although that keyboard is wireless, it wirelessly connects to its own USB dongle, so it connects to the computer via USB, not Bluetooth. And it says it requires no software installation, so it is not using its own kernel extension.

I don't know how to sniff the USB connection between the Logitech Keyboard and the computer to see what its "fn" key is generating on the bus, but I'm hoping someone else can sniff that and see about duplicating it in QMK. The Logitech keyboard is sold by Apple, so it is certainly possible it has special support of some kind, but if you need to go down the route of faking a Vendor ID, it might be safer to fake Logitech than to fake Apple.

@fauxpark
Copy link
Member Author

Wireshark on macOS is able to sniff USB packets, though from Mojave or Catalina onwards you need to disable SIP for the interfaces to show up (and then you have to ifconfig <blah> up them).

adammck added a commit to adammck/kc60 that referenced this issue Jun 19, 2020
This is hack. These keys are unused by the default macOS keybindings, so
I'm sending these when pressing the equivalent of the Mission Control
and Launchpad keys (i.e. Fn+3, Fn+4) so they can be configured to do the
thing. Both can be set in System Preferences > Keyboard.

Why exactly these keys don't have normal codes is explained here:
qmk/qmk_firmware#2179
tldr: Apple ignores the codes unless the USB vendor and product ID match
one of their keyboards.
galudino added a commit to galudino/qmk_firmware that referenced this issue Nov 15, 2020
qmk#2179

From Issue qmk#2179 of qmk/qmk_firmware, user fauxpark mentions how to enable the Apple 'fn' key in QMK.

A link to applefn.patch is in the issue link above,
and was patched into qmk_firmware with this command:
(applefn.patch was already copied into ./qmk_firmware)

```c
% cd qmk_firmware
% patch -ruN -d ./ < applefn.patch
```

In order to be able to use the Apple fn key keycode --
KC_APPLE_FN, or alternatively, KC_APFN,
you must define the following directives in the config.h
file for your keyboard's config.h:

```c
#define VENDOR_ID 0x05ac
#define PRODUCT_ID 0x024f
#define APPLE_FN_ENABLE
```

macOS must "think" your keyboard is one of their own -- the PRODUCT_ID corresponds to the Apple Pro Keyboard.

This commit already has the patch applied,
so the KC_APPLE_FN (KC_APFN) keycode may be used
in all layouts from here on out.
@uchuugaka
Copy link

Were these merged in by a PR at all?
I was able to use the changes in https://gist.github.com/fauxpark/010dcf5d6377c3a71ac98ce37414c6c4
in my own local and it worked like a charm to turn a keyboard into having a proper Fn key as macOS keyboards use them and as a knock on effect makes the F keys work as media keys without extra effort when Fn is used (or reverse depending on OS settings).
The changes were well enough #ifdef isolated and pretty clear. The diff itself also ends up being a quick and dirty tour of where things really happen in QMK and how. Almost a nice intro tutorial. (providing the consumer of the tutorial has a mac)

@fauxpark
Copy link
Member Author

@uchuugaka unfortunately due to the legal implications of imitating an Apple device (by setting their VID and PID), this probably won't be able to be merged. Unless you have managed to get it working using some other VID, in which case that is quite interesting.

@Nuru
Copy link

Nuru commented Nov 29, 2020

@fauxpark @uchuugaka FWIW I have the Fn key working on my Mac running Catalina with a Microsoft keyboard, Vendor ID 1118, PID 219. Not that imitating Microsoft is legally better than imitating Apple, but just to say that I does not have to be an Apple device to work.

@fauxpark
Copy link
Member Author

Maybe things have changed since High Sierra. I think that was when I last properly tested this. I'll try it again in the morning.

@uchuugaka
Copy link

I'd be surprised if it were an issue since Matias has been using the vendor ID for decades.
The product ID does not have any effect in my observations.
If the Microsoft vendor ID also works, that implies there are some IDs that work as known to Apple (or more likely, they're formally registered vendor IDs with usb.org or with somehow registered with Apple.
https://www.usb.org/getting-vendor-id
As far as I know it is quite literally just a formality that donates money to usb.org (USB-IF) and earns the rights to using official USB logos and stuff.
(it also gives you a 16 bit integer's worth of product IDs with usb.org https://hackaday.com/2015/04/03/usb-pids-for-all/ )

Effectively, it's like registering a port number like 666 the port for Doom for network play. Nobody can or will really chase it because it is 100% spoofable like a web browser's User Agent string or Caller ID.

The USB standard also handles this because each device gets a unique ID assigned automagically by the bus itself and no OS in their right mind would predicate anything secure against VID or PID.

FWIW, Apple even share it in constants…
https://developer.apple.com/documentation/usbdriverkit/3295284-apple_s_vendor_id/kiousbapplevendorid
https://developer.apple.com/documentation/usbdriverkit/usb_device_descriptors
https://opensource.apple.com/source/IOUSBFamily/IOUSBFamily-396.4.7/IOUSBFamily/Headers/USBSpec.h.auto.html

If it helps, the driver is 100% Apple's HID device driver unless you provide something via their DriverKit.
All USB keyboards are the same except what scan codes they produce unless you provide additional software via DriverKit.
(like Karabiner does and an interposer)
By default Apple's USB HID stack loads drivers that match the device type.

@fauxpark
Copy link
Member Author

I'm aware of all that - my suspicion is more that Apple maintains a list of "allowed" VIDs that the Fn key will work on. It feels very in keeping with them to do something like that. Obviously it's not meant to be "secure", just a first-level deterrent against impersonating Apple.

RE Matias, it seems as though they have/had some kind of relationship with Apple, if this (admittedly quite old) press release is anything to go by. So it is possible they have been granted permission to use Apple's VID, or Apple has whitelisted Matias devices somehow.

@tzarc
Copy link
Member

tzarc commented Nov 30, 2020

Dunno if this changes anything, but they made a change to how they’re reported:

https://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git/commit/?h=for-next&id=e433be929e63265b7412478eb7ff271467aee2d7

@fauxpark
Copy link
Member Author

Makes sense, the HPVENDOR2 usage page has a value of 0xFF01 but as you can see from AppleHIDUsageTables.h, they call it AppleVendorKeyboard, and it just so happens to also have a Fn key usage at 0x0003, just like AppleVendorTopCase (0x00FF). So I guess newer Magic Keyboards are simply using a more sensible usage page for the Fn key.

@azzlack
Copy link

azzlack commented Dec 14, 2020

I can confirm that the path works without modifying VID using my Idobao ID80v2 and MacOS Big Sur.
If this is proven to work on more boards, would it be possible to merge the patch? After all, the patch itself does not mess with any of Apple's stuff.

This is what I'm running

#define VENDOR_ID       0x6964
#define PRODUCT_ID      0x0080
#define DEVICE_VER      0x0001

azzlack added a commit to azzlack/qmk_firmware that referenced this issue Dec 14, 2020
@dkjer
Copy link

dkjer commented Jan 2, 2021

I can also confirm that this patch works without modifying VID on the DURGOD Taurus K320 on MacOS Catalina.

This is what I'm running

#define VENDOR_ID       0x2f68
#define PRODUCT_ID      0xb381
#define DEVICE_VER      0x0003

dkjer added a commit to dkjer/qmk_firmware that referenced this issue Jan 10, 2021
@LazaroFilm
Copy link

Can someone explain how to use the patch? Thanks.

@dmoles
Copy link

dmoles commented Jan 21, 2021

@LazaroFilm I haven't tried it, but my guess is you could clone @dkjer’s fork (qmk clone dkjer/qmk_firmware --branch apple_fn_k320 <some-directory>) and build from there.

dkjer added a commit to dkjer/qmk_firmware that referenced this issue Jan 21, 2021
dkjer added a commit to dkjer/qmk_firmware that referenced this issue Jan 21, 2021
@8va
Copy link

8va commented Feb 4, 2021

As a macOS user who has recently gotten into mechanical keyboards but basically doesn't understand almost any of the things described here, except how complicated the Apple "fn" key is, would anyone be able to clear up a few things for me?

  1. What exactly does the Apple "fn" key do differently than a third party "fn" key? I imagine it has something to do with Apple's special function row, but is it not possible to take advantage of the actual functions (such as volume up/down, media pause/play/forward/back, etc.) by remapping a key to talk to macOS and trigger those actions? I believe the app BetterTouchTool is able to map any key command to those functions.
  2. I know of some keyboards that replicate the functionality of the special Apple function row functions, such as Keychron keyboards and the Varmilo V87Mac. Are they somehow recreating the Apple function key to do that?
  3. If someone wanted to build their own keyboard from a PCB design, are you saying it's not possible to put Apple's "fn" key anywhere? (In which case, I circle back to my question of how Keychron and Varmilo are able to do it).
  4. Maybe most to the point, is it currently possible to buy just about any mechanical keyboard and remap the "fn" key to the right of the spacebar to be "option" and remap the "Ins" key to be the Apple "fn" key? I read here that someone did this with Karabiner, but I keep reading mixed things about this.
  5. If I were able to remap, e.g. the Ins key to the Apple "fn" key, would that also be able to function as the keyboard's own specific "fn" key? For instance to control keyboard backlight settings.

Thanks so much!

@fauxpark
Copy link
Member Author

fauxpark commented Feb 4, 2021

What exactly does the Apple "fn" key do differently than a third party "fn" key? I imagine it has something to do with Apple's special function row, but is it not possible to take advantage of the actual functions (such as volume up/down, media pause/play/forward/back, etc.) by remapping a key to talk to macOS and trigger those actions? I believe the app BetterTouchTool is able to map any key command to those functions.

Other implementations of the Fn key usually are done through ACPI (you often see this on laptops since the keyboard is integrated anyway), or are completely internal to the keyboard (eg. Corsair).
Apple does a unique thing here though; when you press the Fn key, something is actually sent over the wire and is handled by macOS, although it is not exactly a keycode in itself as there is no such thing in the HID spec. Pressing the function row keys with Fn held doesn't change the keycodes that are sent, but macOS knows that the Fn key is held and will decide what to do based on that. This is how Karabiner and BetterTouchTool are able to mess with Fn key actions.

I know of some keyboards that replicate the functionality of the special Apple function row functions, such as Keychron keyboards and the Varmilo V87Mac. Are they somehow recreating the Apple function key to do that?

Some of them may simply be sending the standard media keys instead of the F-row keys when the Fn key (which does not send anything to the host) is pressed. Volume up/down/mute as well as play/pause/rewind/forward are all part of the HID spec and are quite well supported on all OSes.

If someone wanted to build their own keyboard from a PCB design, are you saying it's not possible to put Apple's "fn" key anywhere? (In which case, I circle back to my question of how Keychron and Varmilo are able to do it).

The main issue with my patch is that it requires you to trick macOS into thinking the board is an actual Apple keyboard - in my testing it did not want to recognise the Fn key event unless the USB vendor and product IDs were ones it "allowed". My theory is that this was done to prevent Apple keyboard clones by way of possible legal repercussions from using their USB vendor ID.

Maybe most to the point, is it currently possible to buy just about any mechanical keyboard and remap the "fn" key to the right of the spacebar to be "option" and remap the "Ins" key to be the Apple "fn" key? I read here that someone did this with Karabiner, but I keep reading mixed things about this.

I'm pretty sure Karabiner has the ability to map the Fn key on a keyboard that does not otherwise have it. It doesn't change anything about the keyboard, just hooks into the keyboard events and intercepts them before they hit the kernel (my vague understanding).

If I were able to remap, e.g. the Ins key to the Apple "fn" key, would that also be able to function as the keyboard's own specific "fn" key? For instance to control keyboard backlight settings.

Probably not. For keyboards with internal Fn keys, nothing will be sent to the host (and nothing would be received), so it cannot be picked up by Karabiner or BTT. And if you're mapping Insert to the Apple Fn, all the keyboard is doing is sending Insert, which Karabiner simply intercepts and turns into a Fn event.

@uchuugaka
Copy link

uchuugaka commented Feb 4, 2021 via email

@jsoltren
Copy link

jsoltren commented Feb 4, 2021 via email

@drashna
Copy link
Member

drashna commented Feb 4, 2021

So... this can be done from software side, meaning no modification to the firmware is needed...

Or, you can make the changes in your own fork, and compile it.

But having this in the official repo ... I'm actively opposed to. "i've been doing it for years" is not a defense if Apple decides to take you to court. And if that were to happen to QMK, who would be willing to help pay the astronomical legal fees?

Not worth the risk, especially when you can do this yourself in several ways.

@jsoltren
Copy link

jsoltren commented Feb 4, 2021 via email

@8va
Copy link

8va commented Feb 4, 2021

Other implementations of the Fn key usually are done through ACPI (you often see this on laptops since the keyboard is integrated anyway), or are completely internal to the keyboard (eg. Corsair).
Apple does a unique thing here though; when you press the Fn key, something is actually sent over the wire and is handled by macOS, although it is not exactly a keycode in itself as there is no such thing in the HID spec. Pressing the function row keys with Fn held doesn't change the keycodes that are sent, but macOS knows that the Fn key is held and will decide what to do based on that. This is how Karabiner and BetterTouchTool are able to mess with Fn key actions.

This is extremely helpful, thank you! I don't understand ACPI (read up a little bit and I'm lost), but it sounds like, in a nutshell, Fn keys don't usually send anything to the computer because there is no "Fn" keycode, but Apple sends a non-keycode piece of data with theirs.

I know of some keyboards that replicate the functionality of the special Apple function row functions, such as Keychron keyboards and the Varmilo V87Mac. Are they somehow recreating the Apple function key to do that?

Some of them may simply be sending the standard media keys instead of the F-row keys when the Fn key (which does not send anything to the host) is pressed. Volume up/down/mute as well as play/pause/rewind/forward are all part of the HID spec and are quite well supported on all OSes.

So if I understand this right, this is what happens when you press Fn+F8, assuming System Prefs is set to use F1, F2, etc. as standard function keys:

  • On an Apple keyboard, it sends a "Fn" non-keycode piece of data + a regular F8 keycode, macOS sees "Fn+F8" and converts it to the Play/Pause command.
  • On a third-party keyboard with a random key set to "Fn" using Karabiner, Karabiner sends nothing to the OS when that mapped "Fn" key is held, but converts the F8 keycode into the Play/Pause command itself. macOS ends up just seeing "Play/Pause" instead of "Fn+F8".
  • On a third-party keyboard with their own Fn key and their own implementation of the media keys, they do the conversion in the keyboard and just send macOS the "Play/Pause" command.
  • On a Matias keyboard, they do send the special non-keycode "Fn" data to macOS by (falsely) using an Apple vendor ID.

So, I could use Karabiner to map Fn to the Ins key and still wind up with the same practical functionality as a real Apple Fn key.

But if I wanted a third-party keyboard with just Command+Option+Control to the right of the spacebar, I'm stuck on how to change a keyboard's non-Apple "Fn" key (which is always to the right of the spacebar) to be the "Option" key. Is it the circuitry/PCB that makes it the keyboard's own Fn key, or is it something in the firmware? Can QMK change a QMK-compatible keyboard's "Fn" key to be "Option"?

Cannot thank all of you enough for all of the incredibly insightful info!

@Nuru
Copy link

Nuru commented Feb 7, 2021

But having this in the official repo ... I'm actively opposed to. "i've been doing it for years" is not a defense if Apple decides to take you to court.

I am not a lawyer and you should check with one, but AFAIK the doctrine of laches says "I've been doing it for years" is a completely valid defense for something like this. Also, in practice, Apple or any company is not likely to go from zero to filing a lawsuit over something like this. First step would be to send you a "cease and desist" letter demanding you stop doing whatever it is they don't like, and generally if you then comply with the terms of the notice, that is the end of it. The bad publicity from Apple abusing an open-source project by suing them is just not worth it.

@skullydazed
Copy link
Member

Thanks for the active and healthy debate here everyone. At this point I think all sides have had a fair chance to be heard. Our official position is that we do not use VIDs we don't have permission for regardless of legality. We have always sought permission before including a VID we know is owned by an organization, and at times have coordinated with the owner to select the proper PID as well. Since it is exceedingly unlikely we will get this permission from Apple, or any other company that can send the Fn key, I'm going to close this issue to further comments.

@qmk qmk locked as resolved and limited conversation to collaborators Feb 7, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests