Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
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 <[email protected]>
  • Loading branch information
Jules-Bertholet committed Nov 30, 2024
commit 7ef0e39ebf80b77453404f3c534215114844e955
79 changes: 58 additions & 21 deletions board/hx20/i2c_hid_mediakeys.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

#define REPORT_ID_RADIO 0x01
#define REPORT_ID_CONSUMER 0x02
#define REPORT_ID_DISPLAY 0x04
#define REPORT_ID_SYSTEM 0x04

/*
* See hid usage tables for consumer page
Expand All @@ -50,25 +50,28 @@ struct consumer_button_report {
uint16_t button_id;
} __packed;

struct display_report {
struct system_report {
uint8_t state;
} __packed;

enum system_buttons: uint8_t {
SYSTEM_KEY_FN = BIT(0),
SYSTEM_KEY_FN_LOCK = BIT(1),
SYSTEM_FN_LOCK_INDICATOR = BIT(2),
SYSTEM_KEY_DISPLAY_TOGGLE = BIT(3),
};

static struct radio_report radio_button;
static struct consumer_button_report consumer_button;
static struct display_report display_button;
static struct system_report system_buttons;


int update_hid_key(enum media_key key, bool pressed)
{
if (key >= HID_KEY_MAX) {
return EC_ERROR_INVAL;
}
if (key == HID_KEY_AIRPLANE_MODE || key == HID_KEY_DISPLAY_TOGGLE) {
key_states[key] = pressed;
if (pressed)
task_set_event(TASK_ID_HID, 1 << key, 0);
} else if (key_states[key] != pressed) {
if (key_states[key] != pressed) {
key_states[key] = pressed;
task_set_event(TASK_ID_HID, 1 << key, 0);
}
Expand Down Expand Up @@ -127,18 +130,24 @@ static const uint8_t report_desc[] = {
0x81, 0x00, /* Input (Data,Arr,Abs) */
0xC0, /* END_COLLECTION */

/* Display Toggle Collection */
/* System Control Collection */
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
0x09, 0x80, /* USAGE (System Control) */
0xA1, 0x01, /* COLLECTION (Application) */
0x85, REPORT_ID_DISPLAY, /* Report ID (Display) */
0x85, REPORT_ID_SYSTEM, /* Report ID (System) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
0x09, 0xB5, /* USAGE (System Display Toggle Int/Ext Mode) */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x09, 0x97, /* USAGE (System Function Shift) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
0x09, 0x98, /* USAGE (System Function Shift Lock) */
0x81, 0x06, /* INPUT (Data,Var,Rel) */
0x09, 0x99, /* USAGE (System Function Shift Lock Indicator) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
0x09, 0xB5, /* USAGE (System Display Toggle Int/Ext Mode) */
0x81, 0x06, /* INPUT (Data,Var,Rel) */
0x75, 0x07, /* REPORT_SIZE (7) */
0x75, 0x04, /* REPORT_SIZE (4) */
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
0xC0, /* END_COLLECTION */
};
Expand Down Expand Up @@ -240,11 +249,11 @@ static int i2c_hid_touchpad_command_process(size_t len, uint8_t *buffer)
&consumer_button,
sizeof(struct consumer_button_report));
break;
case REPORT_ID_DISPLAY:
case REPORT_ID_SYSTEM:
response_len =
fill_report(buffer, report_id,
&display_button,
sizeof(struct display_report));
&system_buttons,
sizeof(struct system_report));
break;
default:
response_len = 2;
Expand Down Expand Up @@ -328,11 +337,11 @@ int i2c_hid_process(unsigned int len, uint8_t *buffer)
fill_report(buffer, REPORT_ID_CONSUMER,
&consumer_button,
sizeof(struct consumer_button_report));
} else if (input_mode == REPORT_ID_DISPLAY) {
} else if (input_mode == REPORT_ID_SYSTEM) {
response_len =
fill_report(buffer, REPORT_ID_DISPLAY,
&display_button,
sizeof(struct display_report));
fill_report(buffer, REPORT_ID_SYSTEM,
&system_buttons,
sizeof(struct system_report));
}
break;
case I2C_HID_COMMAND_REGISTER:
Expand Down Expand Up @@ -430,9 +439,37 @@ void hid_handler_task(void *p)
input_mode = REPORT_ID_RADIO;
radio_button.state = key_states[i] ? 1 : 0;
break;
case HID_KEY_FN:
input_mode = REPORT_ID_SYSTEM;
if (key_states[i]) {
system_buttons.state |= SYSTEM_KEY_FN;
} else {
system_buttons.state &= ~SYSTEM_KEY_FN;
}
break;
case HID_KEY_FN_LOCK:
input_mode = REPORT_ID_SYSTEM;
if (key_states[i]) {
system_buttons.state |= SYSTEM_KEY_FN_LOCK;
} else {
system_buttons.state &= ~SYSTEM_KEY_FN_LOCK;
}
break;
case HID_FN_LOCK_INDICATOR:
input_mode = REPORT_ID_SYSTEM;
if (key_states[i]) {
system_buttons.state |= SYSTEM_FN_LOCK_INDICATOR;
} else {
system_buttons.state &= ~SYSTEM_FN_LOCK_INDICATOR;
}
break;
case HID_KEY_DISPLAY_TOGGLE:
input_mode = REPORT_ID_DISPLAY;
display_button.state = key_states[i] ? 1 : 0;
input_mode = REPORT_ID_SYSTEM;
if (key_states[i]) {
system_buttons.state |= SYSTEM_KEY_DISPLAY_TOGGLE;
} else {
system_buttons.state &= ~SYSTEM_KEY_DISPLAY_TOGGLE;
}
break;
}
hid_irq_to_host();
Expand Down
3 changes: 3 additions & 0 deletions board/hx20/i2c_hid_mediakeys.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ enum media_key {
HID_KEY_DISPLAY_BRIGHTNESS_UP,
HID_KEY_DISPLAY_BRIGHTNESS_DN,
HID_KEY_AIRPLANE_MODE,
HID_KEY_FN,
HID_KEY_FN_LOCK,
HID_FN_LOCK_INDICATOR,
HID_KEY_DISPLAY_TOGGLE,
HID_KEY_MAX
};
Expand Down
23 changes: 15 additions & 8 deletions board/hx20/keyboard_customization.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ void fnkey_startup(void) {
Fn_key |= FN_LOCKED;
}
}

update_hid_key(HID_FN_LOCK_INDICATOR, (Fn_key & FN_LOCKED) != 0);
}
DECLARE_HOOK(HOOK_CHIPSET_STARTUP, fnkey_startup, HOOK_PRIO_DEFAULT);

Expand Down Expand Up @@ -422,11 +424,15 @@ int functional_hotkey(uint16_t *key_code, int8_t pressed)
switch (prss_key) {
case SCANCODE_ESC: /* TODO: FUNCTION_LOCK */
if (fn_table_set(pressed, KB_FN_ESC)) {
update_hid_key(HID_KEY_FN_LOCK, pressed);
if (pressed) {
if (Fn_key & FN_LOCKED)
if (Fn_key & FN_LOCKED) {
Fn_key &= ~FN_LOCKED;
else
update_hid_key(HID_FN_LOCK_INDICATOR, 0);
} else {
Fn_key |= FN_LOCKED;
update_hid_key(HID_FN_LOCK_INDICATOR, 1);
}
}
return EC_ERROR_UNIMPLEMENTED;
}
Expand Down Expand Up @@ -495,12 +501,13 @@ enum ec_error_list keyboard_scancode_callback(uint16_t *make_code,
if (factory_status())
return EC_SUCCESS;

if (pressed_key == SCANCODE_FN && pressed) {
Fn_key |= FN_PRESSED;
return EC_ERROR_UNIMPLEMENTED;
} else if (pressed_key == SCANCODE_FN && !pressed) {
Fn_key &= ~FN_PRESSED;
return EC_ERROR_UNIMPLEMENTED;
if (pressed_key == SCANCODE_FN) {
if (pressed) {
Fn_key |= FN_PRESSED;
} else {
Fn_key &= ~FN_PRESSED;
}
update_hid_key(HID_KEY_FN, pressed);
}

/*
Expand Down
79 changes: 58 additions & 21 deletions board/hx30/i2c_hid_mediakeys.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#define REPORT_ID_RADIO 0x01
#define REPORT_ID_CONSUMER 0x02
#define REPORT_ID_SENSOR 0x03
#define REPORT_ID_DISPLAY 0x04
#define REPORT_ID_SYSTEM 0x04

#define ALS_REPORT_STOP 0x00
#define ALS_REPORT_POLLING 0x01
Expand Down Expand Up @@ -75,26 +75,29 @@ struct als_feature_report {
uint16_t minimum;
} __packed;

struct display_report {
struct system_report {
uint8_t state;
} __packed;

enum system_buttons: uint8_t {
SYSTEM_KEY_FN = BIT(0),
SYSTEM_KEY_FN_LOCK = BIT(1),
SYSTEM_FN_LOCK_INDICATOR = BIT(2),
SYSTEM_KEY_DISPLAY_TOGGLE = BIT(3),
};

static struct radio_report radio_button;
static struct consumer_button_report consumer_button;
static struct als_input_report als_sensor;
static struct als_feature_report als_feature;
static struct display_report display_button;
static struct system_report system_buttons;

int update_hid_key(enum media_key key, bool pressed)
{
if (key >= HID_KEY_MAX) {
return EC_ERROR_INVAL;
}
if (key == HID_KEY_AIRPLANE_MODE || key == HID_KEY_DISPLAY_TOGGLE) {
key_states[key] = pressed;
if (pressed)
task_set_event(TASK_ID_HID, 1 << key, 0);
} else if (key_states[key] != pressed) {
if (key_states[key] != pressed) {
key_states[key] = pressed;
task_set_event(TASK_ID_HID, 1 << key, 0);
}
Expand Down Expand Up @@ -291,18 +294,24 @@ static const uint8_t report_desc[] = {
0x81, 0x02, /* Input (Data,Arr,Abs) */
0xC0, /* END_COLLECTION */

/* Display Toggle Collection */
/* System Control Collection */
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
0x09, 0x80, /* USAGE (System Control) */
0xA1, 0x01, /* COLLECTION (Application) */
0x85, REPORT_ID_DISPLAY, /* Report ID (Display) */
0x85, REPORT_ID_SYSTEM, /* Report ID (System) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
0x09, 0xB5, /* USAGE (System Display Toggle Int/Ext Mode) */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x09, 0x97, /* USAGE (System Function Shift) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
0x09, 0x98, /* USAGE (System Function Shift Lock) */
0x81, 0x06, /* INPUT (Data,Var,Rel) */
0x75, 0x07, /* REPORT_SIZE (7) */
0x09, 0x99, /* USAGE (System Function Shift Lock Indicator) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
0x09, 0xB5, /* USAGE (System Display Toggle Int/Ext Mode) */
0x81, 0x06, /* INPUT (Data,Var,Rel) */
0x75, 0x04, /* REPORT_SIZE (4) */
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
0xC0, /* END_COLLECTION */
};
Expand Down Expand Up @@ -498,11 +507,11 @@ static int i2c_hid_touchpad_command_process(size_t len, uint8_t *buffer)
sizeof(struct als_feature_report));
}
break;
case REPORT_ID_DISPLAY:
case REPORT_ID_SYSTEM:
response_len =
fill_report(buffer, report_id,
&display_button,
sizeof(struct display_report));
&system_buttons,
sizeof(struct system_report));
break;
default:
response_len = 2;
Expand Down Expand Up @@ -590,11 +599,11 @@ int i2c_hid_process(unsigned int len, uint8_t *buffer)
fill_report(buffer, REPORT_ID_SENSOR,
&als_sensor,
sizeof(struct als_input_report));
} else if (input_mode == REPORT_ID_DISPLAY) {
} else if (input_mode == REPORT_ID_SYSTEM) {
response_len =
fill_report(buffer, REPORT_ID_DISPLAY,
&display_button,
sizeof(struct display_report));
fill_report(buffer, REPORT_ID_SYSTEM,
&system_buttons,
sizeof(struct system_report));
}
break;
case I2C_HID_COMMAND_REGISTER:
Expand Down Expand Up @@ -704,9 +713,37 @@ void hid_handler_task(void *p)
input_mode = REPORT_ID_RADIO;
radio_button.state = key_states[i] ? 1 : 0;
break;
case HID_KEY_FN:
input_mode = REPORT_ID_SYSTEM;
if (key_states[i]) {
system_buttons.state |= SYSTEM_KEY_FN;
} else {
system_buttons.state &= ~SYSTEM_KEY_FN;
}
break;
case HID_KEY_FN_LOCK:
input_mode = REPORT_ID_SYSTEM;
if (key_states[i]) {
system_buttons.state |= SYSTEM_KEY_FN_LOCK;
} else {
system_buttons.state &= ~SYSTEM_KEY_FN_LOCK;
}
break;
case HID_FN_LOCK_INDICATOR:
input_mode = REPORT_ID_SYSTEM;
if (key_states[i]) {
system_buttons.state |= SYSTEM_FN_LOCK_INDICATOR;
} else {
system_buttons.state &= ~SYSTEM_FN_LOCK_INDICATOR;
}
break;
case HID_KEY_DISPLAY_TOGGLE:
input_mode = REPORT_ID_DISPLAY;
display_button.state = key_states[i] ? 1 : 0;
input_mode = REPORT_ID_SYSTEM;
if (key_states[i]) {
system_buttons.state |= SYSTEM_KEY_DISPLAY_TOGGLE;
} else {
system_buttons.state &= ~SYSTEM_KEY_DISPLAY_TOGGLE;
}
break;
case HID_ALS_REPORT_LUX:

Expand Down
3 changes: 3 additions & 0 deletions board/hx30/i2c_hid_mediakeys.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ enum media_key {
HID_KEY_DISPLAY_BRIGHTNESS_UP,
HID_KEY_DISPLAY_BRIGHTNESS_DN,
HID_KEY_AIRPLANE_MODE,
HID_KEY_FN,
HID_KEY_FN_LOCK,
HID_FN_LOCK_INDICATOR,
HID_KEY_DISPLAY_TOGGLE,
HID_ALS_REPORT_LUX,
HID_KEY_MAX
Expand Down
Loading