Skip to content

Commit 7ef0e39

Browse files
fwk: 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 is reported 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. Signed-off-by: Jules Bertholet <julesbertholet@quoi.xyz>
1 parent 8059110 commit 7ef0e39

File tree

6 files changed

+152
-57
lines changed

6 files changed

+152
-57
lines changed

board/hx20/i2c_hid_mediakeys.c

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
#define REPORT_ID_RADIO 0x01
2525
#define REPORT_ID_CONSUMER 0x02
26-
#define REPORT_ID_DISPLAY 0x04
26+
#define REPORT_ID_SYSTEM 0x04
2727

2828
/*
2929
* See hid usage tables for consumer page
@@ -50,25 +50,28 @@ struct consumer_button_report {
5050
uint16_t button_id;
5151
} __packed;
5252

53-
struct display_report {
53+
struct system_report {
5454
uint8_t state;
5555
} __packed;
5656

57+
enum system_buttons: uint8_t {
58+
SYSTEM_KEY_FN = BIT(0),
59+
SYSTEM_KEY_FN_LOCK = BIT(1),
60+
SYSTEM_FN_LOCK_INDICATOR = BIT(2),
61+
SYSTEM_KEY_DISPLAY_TOGGLE = BIT(3),
62+
};
63+
5764
static struct radio_report radio_button;
5865
static struct consumer_button_report consumer_button;
59-
static struct display_report display_button;
66+
static struct system_report system_buttons;
6067

6168

6269
int update_hid_key(enum media_key key, bool pressed)
6370
{
6471
if (key >= HID_KEY_MAX) {
6572
return EC_ERROR_INVAL;
6673
}
67-
if (key == HID_KEY_AIRPLANE_MODE || key == HID_KEY_DISPLAY_TOGGLE) {
68-
key_states[key] = pressed;
69-
if (pressed)
70-
task_set_event(TASK_ID_HID, 1 << key, 0);
71-
} else if (key_states[key] != pressed) {
74+
if (key_states[key] != pressed) {
7275
key_states[key] = pressed;
7376
task_set_event(TASK_ID_HID, 1 << key, 0);
7477
}
@@ -127,18 +130,24 @@ static const uint8_t report_desc[] = {
127130
0x81, 0x00, /* Input (Data,Arr,Abs) */
128131
0xC0, /* END_COLLECTION */
129132

130-
/* Display Toggle Collection */
133+
/* System Control Collection */
131134
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
132135
0x09, 0x80, /* USAGE (System Control) */
133136
0xA1, 0x01, /* COLLECTION (Application) */
134-
0x85, REPORT_ID_DISPLAY, /* Report ID (Display) */
137+
0x85, REPORT_ID_SYSTEM, /* Report ID (System) */
135138
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
136139
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
137-
0x09, 0xB5, /* USAGE (System Display Toggle Int/Ext Mode) */
138140
0x95, 0x01, /* REPORT_COUNT (1) */
139141
0x75, 0x01, /* REPORT_SIZE (1) */
142+
0x09, 0x97, /* USAGE (System Function Shift) */
143+
0x81, 0x02, /* INPUT (Data,Var,Abs) */
144+
0x09, 0x98, /* USAGE (System Function Shift Lock) */
145+
0x81, 0x06, /* INPUT (Data,Var,Rel) */
146+
0x09, 0x99, /* USAGE (System Function Shift Lock Indicator) */
147+
0x81, 0x02, /* INPUT (Data,Var,Abs) */
148+
0x09, 0xB5, /* USAGE (System Display Toggle Int/Ext Mode) */
140149
0x81, 0x06, /* INPUT (Data,Var,Rel) */
141-
0x75, 0x07, /* REPORT_SIZE (7) */
150+
0x75, 0x04, /* REPORT_SIZE (4) */
142151
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
143152
0xC0, /* END_COLLECTION */
144153
};
@@ -240,11 +249,11 @@ static int i2c_hid_touchpad_command_process(size_t len, uint8_t *buffer)
240249
&consumer_button,
241250
sizeof(struct consumer_button_report));
242251
break;
243-
case REPORT_ID_DISPLAY:
252+
case REPORT_ID_SYSTEM:
244253
response_len =
245254
fill_report(buffer, report_id,
246-
&display_button,
247-
sizeof(struct display_report));
255+
&system_buttons,
256+
sizeof(struct system_report));
248257
break;
249258
default:
250259
response_len = 2;
@@ -328,11 +337,11 @@ int i2c_hid_process(unsigned int len, uint8_t *buffer)
328337
fill_report(buffer, REPORT_ID_CONSUMER,
329338
&consumer_button,
330339
sizeof(struct consumer_button_report));
331-
} else if (input_mode == REPORT_ID_DISPLAY) {
340+
} else if (input_mode == REPORT_ID_SYSTEM) {
332341
response_len =
333-
fill_report(buffer, REPORT_ID_DISPLAY,
334-
&display_button,
335-
sizeof(struct display_report));
342+
fill_report(buffer, REPORT_ID_SYSTEM,
343+
&system_buttons,
344+
sizeof(struct system_report));
336345
}
337346
break;
338347
case I2C_HID_COMMAND_REGISTER:
@@ -430,9 +439,37 @@ void hid_handler_task(void *p)
430439
input_mode = REPORT_ID_RADIO;
431440
radio_button.state = key_states[i] ? 1 : 0;
432441
break;
442+
case HID_KEY_FN:
443+
input_mode = REPORT_ID_SYSTEM;
444+
if (key_states[i]) {
445+
system_buttons.state |= SYSTEM_KEY_FN;
446+
} else {
447+
system_buttons.state &= ~SYSTEM_KEY_FN;
448+
}
449+
break;
450+
case HID_KEY_FN_LOCK:
451+
input_mode = REPORT_ID_SYSTEM;
452+
if (key_states[i]) {
453+
system_buttons.state |= SYSTEM_KEY_FN_LOCK;
454+
} else {
455+
system_buttons.state &= ~SYSTEM_KEY_FN_LOCK;
456+
}
457+
break;
458+
case HID_FN_LOCK_INDICATOR:
459+
input_mode = REPORT_ID_SYSTEM;
460+
if (key_states[i]) {
461+
system_buttons.state |= SYSTEM_FN_LOCK_INDICATOR;
462+
} else {
463+
system_buttons.state &= ~SYSTEM_FN_LOCK_INDICATOR;
464+
}
465+
break;
433466
case HID_KEY_DISPLAY_TOGGLE:
434-
input_mode = REPORT_ID_DISPLAY;
435-
display_button.state = key_states[i] ? 1 : 0;
467+
input_mode = REPORT_ID_SYSTEM;
468+
if (key_states[i]) {
469+
system_buttons.state |= SYSTEM_KEY_DISPLAY_TOGGLE;
470+
} else {
471+
system_buttons.state &= ~SYSTEM_KEY_DISPLAY_TOGGLE;
472+
}
436473
break;
437474
}
438475
hid_irq_to_host();

board/hx20/i2c_hid_mediakeys.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ enum media_key {
2828
HID_KEY_DISPLAY_BRIGHTNESS_UP,
2929
HID_KEY_DISPLAY_BRIGHTNESS_DN,
3030
HID_KEY_AIRPLANE_MODE,
31+
HID_KEY_FN,
32+
HID_KEY_FN_LOCK,
33+
HID_FN_LOCK_INDICATOR,
3134
HID_KEY_DISPLAY_TOGGLE,
3235
HID_KEY_MAX
3336
};

board/hx20/keyboard_customization.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,8 @@ void fnkey_startup(void) {
281281
Fn_key |= FN_LOCKED;
282282
}
283283
}
284+
285+
update_hid_key(HID_FN_LOCK_INDICATOR, (Fn_key & FN_LOCKED) != 0);
284286
}
285287
DECLARE_HOOK(HOOK_CHIPSET_STARTUP, fnkey_startup, HOOK_PRIO_DEFAULT);
286288

@@ -422,11 +424,15 @@ int functional_hotkey(uint16_t *key_code, int8_t pressed)
422424
switch (prss_key) {
423425
case SCANCODE_ESC: /* TODO: FUNCTION_LOCK */
424426
if (fn_table_set(pressed, KB_FN_ESC)) {
427+
update_hid_key(HID_KEY_FN_LOCK, pressed);
425428
if (pressed) {
426-
if (Fn_key & FN_LOCKED)
429+
if (Fn_key & FN_LOCKED) {
427430
Fn_key &= ~FN_LOCKED;
428-
else
431+
update_hid_key(HID_FN_LOCK_INDICATOR, 0);
432+
} else {
429433
Fn_key |= FN_LOCKED;
434+
update_hid_key(HID_FN_LOCK_INDICATOR, 1);
435+
}
430436
}
431437
return EC_ERROR_UNIMPLEMENTED;
432438
}
@@ -495,12 +501,13 @@ enum ec_error_list keyboard_scancode_callback(uint16_t *make_code,
495501
if (factory_status())
496502
return EC_SUCCESS;
497503

498-
if (pressed_key == SCANCODE_FN && pressed) {
499-
Fn_key |= FN_PRESSED;
500-
return EC_ERROR_UNIMPLEMENTED;
501-
} else if (pressed_key == SCANCODE_FN && !pressed) {
502-
Fn_key &= ~FN_PRESSED;
503-
return EC_ERROR_UNIMPLEMENTED;
504+
if (pressed_key == SCANCODE_FN) {
505+
if (pressed) {
506+
Fn_key |= FN_PRESSED;
507+
} else {
508+
Fn_key &= ~FN_PRESSED;
509+
}
510+
update_hid_key(HID_KEY_FN, pressed);
504511
}
505512

506513
/*

board/hx30/i2c_hid_mediakeys.c

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
#define REPORT_ID_RADIO 0x01
2626
#define REPORT_ID_CONSUMER 0x02
2727
#define REPORT_ID_SENSOR 0x03
28-
#define REPORT_ID_DISPLAY 0x04
28+
#define REPORT_ID_SYSTEM 0x04
2929

3030
#define ALS_REPORT_STOP 0x00
3131
#define ALS_REPORT_POLLING 0x01
@@ -75,26 +75,29 @@ struct als_feature_report {
7575
uint16_t minimum;
7676
} __packed;
7777

78-
struct display_report {
78+
struct system_report {
7979
uint8_t state;
8080
} __packed;
8181

82+
enum system_buttons: uint8_t {
83+
SYSTEM_KEY_FN = BIT(0),
84+
SYSTEM_KEY_FN_LOCK = BIT(1),
85+
SYSTEM_FN_LOCK_INDICATOR = BIT(2),
86+
SYSTEM_KEY_DISPLAY_TOGGLE = BIT(3),
87+
};
88+
8289
static struct radio_report radio_button;
8390
static struct consumer_button_report consumer_button;
8491
static struct als_input_report als_sensor;
8592
static struct als_feature_report als_feature;
86-
static struct display_report display_button;
93+
static struct system_report system_buttons;
8794

8895
int update_hid_key(enum media_key key, bool pressed)
8996
{
9097
if (key >= HID_KEY_MAX) {
9198
return EC_ERROR_INVAL;
9299
}
93-
if (key == HID_KEY_AIRPLANE_MODE || key == HID_KEY_DISPLAY_TOGGLE) {
94-
key_states[key] = pressed;
95-
if (pressed)
96-
task_set_event(TASK_ID_HID, 1 << key, 0);
97-
} else if (key_states[key] != pressed) {
100+
if (key_states[key] != pressed) {
98101
key_states[key] = pressed;
99102
task_set_event(TASK_ID_HID, 1 << key, 0);
100103
}
@@ -291,18 +294,24 @@ static const uint8_t report_desc[] = {
291294
0x81, 0x02, /* Input (Data,Arr,Abs) */
292295
0xC0, /* END_COLLECTION */
293296

294-
/* Display Toggle Collection */
297+
/* System Control Collection */
295298
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
296299
0x09, 0x80, /* USAGE (System Control) */
297300
0xA1, 0x01, /* COLLECTION (Application) */
298-
0x85, REPORT_ID_DISPLAY, /* Report ID (Display) */
301+
0x85, REPORT_ID_SYSTEM, /* Report ID (System) */
299302
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
300303
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
301-
0x09, 0xB5, /* USAGE (System Display Toggle Int/Ext Mode) */
302304
0x95, 0x01, /* REPORT_COUNT (1) */
303305
0x75, 0x01, /* REPORT_SIZE (1) */
306+
0x09, 0x97, /* USAGE (System Function Shift) */
307+
0x81, 0x02, /* INPUT (Data,Var,Abs) */
308+
0x09, 0x98, /* USAGE (System Function Shift Lock) */
304309
0x81, 0x06, /* INPUT (Data,Var,Rel) */
305-
0x75, 0x07, /* REPORT_SIZE (7) */
310+
0x09, 0x99, /* USAGE (System Function Shift Lock Indicator) */
311+
0x81, 0x02, /* INPUT (Data,Var,Abs) */
312+
0x09, 0xB5, /* USAGE (System Display Toggle Int/Ext Mode) */
313+
0x81, 0x06, /* INPUT (Data,Var,Rel) */
314+
0x75, 0x04, /* REPORT_SIZE (4) */
306315
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
307316
0xC0, /* END_COLLECTION */
308317
};
@@ -498,11 +507,11 @@ static int i2c_hid_touchpad_command_process(size_t len, uint8_t *buffer)
498507
sizeof(struct als_feature_report));
499508
}
500509
break;
501-
case REPORT_ID_DISPLAY:
510+
case REPORT_ID_SYSTEM:
502511
response_len =
503512
fill_report(buffer, report_id,
504-
&display_button,
505-
sizeof(struct display_report));
513+
&system_buttons,
514+
sizeof(struct system_report));
506515
break;
507516
default:
508517
response_len = 2;
@@ -590,11 +599,11 @@ int i2c_hid_process(unsigned int len, uint8_t *buffer)
590599
fill_report(buffer, REPORT_ID_SENSOR,
591600
&als_sensor,
592601
sizeof(struct als_input_report));
593-
} else if (input_mode == REPORT_ID_DISPLAY) {
602+
} else if (input_mode == REPORT_ID_SYSTEM) {
594603
response_len =
595-
fill_report(buffer, REPORT_ID_DISPLAY,
596-
&display_button,
597-
sizeof(struct display_report));
604+
fill_report(buffer, REPORT_ID_SYSTEM,
605+
&system_buttons,
606+
sizeof(struct system_report));
598607
}
599608
break;
600609
case I2C_HID_COMMAND_REGISTER:
@@ -704,9 +713,37 @@ void hid_handler_task(void *p)
704713
input_mode = REPORT_ID_RADIO;
705714
radio_button.state = key_states[i] ? 1 : 0;
706715
break;
716+
case HID_KEY_FN:
717+
input_mode = REPORT_ID_SYSTEM;
718+
if (key_states[i]) {
719+
system_buttons.state |= SYSTEM_KEY_FN;
720+
} else {
721+
system_buttons.state &= ~SYSTEM_KEY_FN;
722+
}
723+
break;
724+
case HID_KEY_FN_LOCK:
725+
input_mode = REPORT_ID_SYSTEM;
726+
if (key_states[i]) {
727+
system_buttons.state |= SYSTEM_KEY_FN_LOCK;
728+
} else {
729+
system_buttons.state &= ~SYSTEM_KEY_FN_LOCK;
730+
}
731+
break;
732+
case HID_FN_LOCK_INDICATOR:
733+
input_mode = REPORT_ID_SYSTEM;
734+
if (key_states[i]) {
735+
system_buttons.state |= SYSTEM_FN_LOCK_INDICATOR;
736+
} else {
737+
system_buttons.state &= ~SYSTEM_FN_LOCK_INDICATOR;
738+
}
739+
break;
707740
case HID_KEY_DISPLAY_TOGGLE:
708-
input_mode = REPORT_ID_DISPLAY;
709-
display_button.state = key_states[i] ? 1 : 0;
741+
input_mode = REPORT_ID_SYSTEM;
742+
if (key_states[i]) {
743+
system_buttons.state |= SYSTEM_KEY_DISPLAY_TOGGLE;
744+
} else {
745+
system_buttons.state &= ~SYSTEM_KEY_DISPLAY_TOGGLE;
746+
}
710747
break;
711748
case HID_ALS_REPORT_LUX:
712749

board/hx30/i2c_hid_mediakeys.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ enum media_key {
8181
HID_KEY_DISPLAY_BRIGHTNESS_UP,
8282
HID_KEY_DISPLAY_BRIGHTNESS_DN,
8383
HID_KEY_AIRPLANE_MODE,
84+
HID_KEY_FN,
85+
HID_KEY_FN_LOCK,
86+
HID_FN_LOCK_INDICATOR,
8487
HID_KEY_DISPLAY_TOGGLE,
8588
HID_ALS_REPORT_LUX,
8689
HID_KEY_MAX

0 commit comments

Comments
 (0)