diff --git a/board/hx20/keyboard_customization.c b/board/hx20/keyboard_customization.c
index 9a5050a0f..2756f17ce 100644
--- a/board/hx20/keyboard_customization.c
+++ b/board/hx20/keyboard_customization.c
@@ -22,12 +22,15 @@
#define CPRINTS(format, args...) cprints(CC_KEYBOARD, format, ## args)
#define CPRINTF(format, args...) cprintf(CC_KEYBOARD, format, ## args)
+/* The scancode for the caps-lock key, which is now a hybrid key */
+#define SCANCODE_CTRL_ESC 0x0101
+
uint16_t scancode_set2[KEYBOARD_COLS_MAX][KEYBOARD_ROWS] = {
{0x0021, 0x007B, 0x0079, 0x0072, 0x007A, 0x0071, 0x0069, 0xe04A},
{0xe071, 0xe070, 0x007D, 0xe01f, 0x006c, 0xe06c, 0xe07d, 0x0077},
{0x0015, 0x0070, 0x00ff, 0x000D, 0x000E, 0x0016, 0x0067, 0x001c},
{0xe011, 0x0011, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
- {0xe05a, 0x0029, 0x0024, 0x000c, 0x0058, 0x0026, 0x0004, 0xe07a},
+ {0xe05a, 0x0029, 0x0024, 0x000c, 0x0101, 0x0026, 0x0004, 0xe07a},
{0x0022, 0x001a, 0x0006, 0x0005, 0x001b, 0x001e, 0x001d, 0x0076},
{0x002A, 0x0032, 0x0034, 0x002c, 0x002e, 0x0025, 0x002d, 0x002b},
{0x003a, 0x0031, 0x0033, 0x0035, 0x0036, 0x003d, 0x003c, 0x003b},
@@ -497,6 +500,55 @@ int functional_hotkey(uint16_t *key_code, int8_t pressed)
return EC_SUCCESS;
}
+int try_ctrl_esc(uint16_t *key_code, int8_t pressed) {
+ static enum {
+ NONE,
+ HELD,
+ CTRL
+ } ctrl_esc_state;
+
+ if (*key_code == SCANCODE_CTRL_ESC) {
+ /* If we pressed the caps key, enter the HELD state. Otherwise,
+ * we are either releasing from the HELD state or the CTRL
+ * state. In both cases we should reset the state to NONE, but
+ * when releasing from the HELD state we want to send an ESC and
+ * when releasing from the CTRL state we want to end the CTRL.
+ *
+ * Also important to note is that even before we know if we’re
+ * going to be acting as ESC or CTRL, we need to send a press-
+ * event of the CTRL key because you can chord CTRL with mouse-
+ * clicks too, not just other keys.
+ */
+ if (pressed) {
+ ctrl_esc_state = HELD;
+ simulate_keyboard(SCANCODE_LEFT_CTRL, 1);
+ } else if (ctrl_esc_state == HELD) {
+ ctrl_esc_state = NONE;
+ simulate_keyboard(SCANCODE_LEFT_CTRL, 0);
+ simulate_keyboard(SCANCODE_ESC, 1);
+ simulate_keyboard(SCANCODE_ESC, 0);
+ } else if (ctrl_esc_state == CTRL) {
+ ctrl_esc_state = NONE;
+ simulate_keyboard(SCANCODE_LEFT_CTRL, 0);
+ }
+
+ return EC_ERROR_UNIMPLEMENTED;
+ }
+
+ /* If we get here then we are dealing with a key that isn’t the caps
+ * key. In that case we need to handle all 3 states. If the state is
+ * NONE then we can just exit from this function. If it’s HELD and we
+ * are pressing a key, then that’s a key-chord and we need to start a
+ * CTRL. Finally, if we are in the CTRL state, there is nothing to do.
+ */
+ if (ctrl_esc_state == HELD && pressed) {
+ ctrl_esc_state = CTRL;
+ simulate_keyboard(SCANCODE_LEFT_CTRL, 1);
+ }
+
+ return EC_SUCCESS;
+}
+
enum ec_error_list keyboard_scancode_callback(uint16_t *make_code,
int8_t pressed)
{
@@ -521,6 +573,10 @@ enum ec_error_list keyboard_scancode_callback(uint16_t *make_code,
if (!pos_get_state())
return EC_SUCCESS;
+ r = try_ctrl_esc(make_code, pressed);
+ if (r != EC_SUCCESS)
+ return r;
+
r = hotkey_F1_F12(make_code, Fn_key, pressed);
if (r != EC_SUCCESS)
return r;