Report fn key and lock states via HID
Fn key state is reported as "System Function Shift", FnLock key (Fn+Esc) state as "System Function Shift Lock", and Fn lock state as "System Function Shift Lock Indicator". This allows the OS to detect when the Fn key is pressed, enabling the user to configure custom keybinds involving it; it also allows the OS to report the state of the Fn lock feature to the user.
This PR, by enabling users to configure custom Fn key shortcuts, is a potential alternative to #50, #54, and especially #51.
If this PR is accepted, I plan to follow it with a patch to the Linux kernel to emit the proper input events.
Uses the same HID collection as #49; uses its branch as a base for this reason.
Ah, thanks for doing this. I worked on this exact thing back in 2022, but I gave up when I realized the kernel would need patching.
Kernel patch:
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 541d682af15a..8bdf5016b50c 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -3349,6 +3349,7 @@ static const char *keys[KEY_MAX + 1] = {
[KEY_FN_F7] = "Fn+F7", [KEY_FN_F8] = "Fn+F8",
[KEY_FN_F9] = "Fn+F9", [KEY_FN_F10] = "Fn+F10",
[KEY_FN_F11] = "Fn+F11", [KEY_FN_F12] = "Fn+F12",
+ [KEY_FNLOCK] = "FnLock",
[KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle",
[KEY_KBDILLUMDOWN] = "KbdIlluminationDown",
[KEY_KBDILLUMUP] = "KbdIlluminationUp",
@@ -3541,7 +3542,7 @@ static const char *leds[LED_MAX + 1] = {
[LED_KANA] = "Kana", [LED_SLEEP] = "Sleep",
[LED_SUSPEND] = "Suspend", [LED_MUTE] = "Mute",
[LED_MISC] = "Misc", [LED_MAIL] = "Mail",
- [LED_CHARGING] = "Charging",
+ [LED_CHARGING] = "Charging", [LED_FNL] = "FnLock",
};
static const char *repeats[REP_MAX + 1] = {
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index fda9dce3da99..65d1a9b89984 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -812,6 +812,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
if ((usage->hid & 0xf0) == 0x90) { /* SystemControl*/
switch (usage->hid & 0xf) {
+ case 0x7: map_key_clear(KEY_FN); break;
+ case 0x8: map_key_clear(KEY_FNLOCK); break;
+ case 0x9: map_led(LED_FNL); break;
case 0xb: map_key_clear(KEY_DO_NOT_DISTURB); break;
default: goto ignore;
}
diff --git a/drivers/input/input-leds.c b/drivers/input/input-leds.c
index 6bbf3806ea37..58bc7d581250 100644
--- a/drivers/input/input-leds.c
+++ b/drivers/input/input-leds.c
@@ -39,6 +39,7 @@ static const struct {
[LED_MISC] = { "misc" },
[LED_MAIL] = { "mail" },
[LED_CHARGING] = { "charging" },
+ [LED_FNL] = { "fnlock" },
};
struct input_led {
diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
index a4206723f503..ef86fde10baf 100644
--- a/include/uapi/linux/input-event-codes.h
+++ b/include/uapi/linux/input-event-codes.h
@@ -547,6 +547,7 @@
#define KEY_FN_S 0x1e3
#define KEY_FN_B 0x1e4
#define KEY_FN_RIGHT_SHIFT 0x1e5
+#define KEY_FNLOCK 0x1e6
#define KEY_BRL_DOT1 0x1f1
#define KEY_BRL_DOT2 0x1f2
@@ -955,6 +956,7 @@
#define LED_MISC 0x08
#define LED_MAIL 0x09
#define LED_CHARGING 0x0a
+#define LED_FNL 0x0b
#define LED_MAX 0x0f
#define LED_CNT (LED_MAX+1)