Skip to content

Commit fa33382

Browse files
PlomboJiri Kosina
authored andcommitted
HID: apple: Properly handle function keys on Keychron keyboards
Keychron's C-series and K-series of keyboards copy the vendor and product IDs of an Apple keyboard, but only behave like that device when set to "Mac" mode. In "Windows" mode, the Fn key doesn't generate a scancode, so it's impossible to use the F1-F12 keys when fnmode is set to its default value of 1. To fix this, make fnmode default to the new value of 3, which behaves like fnmode=2 for Keychron keyboards and like fnmode=1 for actual Apple keyboards. This way, Keychron devices are fully usable in both "Windows" and "Mac" modes, while behavior is unchanged for everything else. Signed-off-by: Bryan Cain <[email protected]> Reviewed-by: Hans de Goede <[email protected]> Tested-by: José Expósito <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 5e20645 commit fa33382

File tree

1 file changed

+18
-4
lines changed

1 file changed

+18
-4
lines changed

drivers/hid/hid-apple.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/module.h>
2222
#include <linux/slab.h>
2323
#include <linux/timer.h>
24+
#include <linux/string.h>
2425

2526
#include "hid-ids.h"
2627

@@ -35,16 +36,17 @@
3536
#define APPLE_NUMLOCK_EMULATION BIT(8)
3637
#define APPLE_RDESC_BATTERY BIT(9)
3738
#define APPLE_BACKLIGHT_CTL BIT(10)
39+
#define APPLE_IS_KEYCHRON BIT(11)
3840

3941
#define APPLE_FLAG_FKEY 0x01
4042

4143
#define HID_COUNTRY_INTERNATIONAL_ISO 13
4244
#define APPLE_BATTERY_TIMEOUT_MS 60000
4345

44-
static unsigned int fnmode = 1;
46+
static unsigned int fnmode = 3;
4547
module_param(fnmode, uint, 0644);
4648
MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, "
47-
"[1] = fkeyslast, 2 = fkeysfirst)");
49+
"1 = fkeyslast, 2 = fkeysfirst, [3] = auto)");
4850

4951
static int iso_layout = -1;
5052
module_param(iso_layout, int, 0644);
@@ -349,6 +351,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
349351
const struct apple_key_translation *trans, *table;
350352
bool do_translate;
351353
u16 code = 0;
354+
unsigned int real_fnmode;
352355

353356
u16 fn_keycode = (swap_fn_leftctrl) ? (KEY_LEFTCTRL) : (KEY_FN);
354357

@@ -359,7 +362,13 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
359362
return 1;
360363
}
361364

362-
if (fnmode) {
365+
if (fnmode == 3) {
366+
real_fnmode = (asc->quirks & APPLE_IS_KEYCHRON) ? 2 : 1;
367+
} else {
368+
real_fnmode = fnmode;
369+
}
370+
371+
if (real_fnmode) {
363372
if (hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI ||
364373
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO ||
365374
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS ||
@@ -406,7 +415,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
406415

407416
if (!code) {
408417
if (trans->flags & APPLE_FLAG_FKEY) {
409-
switch (fnmode) {
418+
switch (real_fnmode) {
410419
case 1:
411420
do_translate = !asc->fn_on;
412421
break;
@@ -660,6 +669,11 @@ static int apple_input_configured(struct hid_device *hdev,
660669
asc->quirks &= ~APPLE_HAS_FN;
661670
}
662671

672+
if (strncmp(hdev->name, "Keychron", 8) == 0) {
673+
hid_info(hdev, "Keychron keyboard detected; function keys will default to fnmode=2 behavior\n");
674+
asc->quirks |= APPLE_IS_KEYCHRON;
675+
}
676+
663677
return 0;
664678
}
665679

0 commit comments

Comments
 (0)