EmbeddedController icon indicating copy to clipboard operation
EmbeddedController copied to clipboard

Report fn key and lock states via HID

Open Jules-Bertholet opened this issue 1 year ago • 2 comments

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.

Jules-Bertholet avatar Nov 30 '24 19:11 Jules-Bertholet

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.

DHowett avatar Nov 30 '24 19:11 DHowett

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)

Jules-Bertholet avatar Nov 30 '24 22:11 Jules-Bertholet