From 4d6857993ea9f39ff4113809fd7b2272ff83647f Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Sun, 30 Jul 2023 16:08:45 +0200 Subject: Finish the Framework EC page --- src/srp/fw-ec/1172.png | Bin 0 -> 17531 bytes src/srp/fw-ec/fn-lock-1.diff.html | 12 +++ src/srp/fw-ec/fn-lock-2.diff.html | 36 +++++++++ src/srp/fw-ec/hybrid.diff.html | 88 ++++++++++++++++++++++ src/srp/fw-ec/index.html | 155 ++++++++++++++++++++++++++++++++++++++ src/srp/fw-ec/kbd-sc-cb.c.html | 7 ++ src/style.css | 23 ++++-- 7 files changed, 315 insertions(+), 6 deletions(-) create mode 100644 src/srp/fw-ec/1172.png create mode 100644 src/srp/fw-ec/fn-lock-1.diff.html create mode 100644 src/srp/fw-ec/fn-lock-2.diff.html create mode 100644 src/srp/fw-ec/hybrid.diff.html create mode 100644 src/srp/fw-ec/kbd-sc-cb.c.html diff --git a/src/srp/fw-ec/1172.png b/src/srp/fw-ec/1172.png new file mode 100644 index 0000000..14b3be1 Binary files /dev/null and b/src/srp/fw-ec/1172.png differ diff --git a/src/srp/fw-ec/fn-lock-1.diff.html b/src/srp/fw-ec/fn-lock-1.diff.html new file mode 100644 index 0000000..fb48204 --- /dev/null +++ b/src/srp/fw-ec/fn-lock-1.diff.html @@ -0,0 +1,12 @@ +diff --git a/board/hx20/board.h b/board/hx20/board.h +index 7b4ea288a..cfc6a61a2 100644 +--- a/board/hx20/board.h ++++ b/board/hx20/board.h +@@ -218,7 +218,6 @@ + #define CONFIG_CMD_LEDTEST + #define CONFIG_LED_PWM_COUNT 3 + #define CONFIG_LED_PWM_TASK_DISABLED +-#define CONFIG_CAPSLED_SUPPORT + + #ifdef CONFIG_ACCEL_KX022 + #define CONFIG_LID_ANGLE diff --git a/src/srp/fw-ec/fn-lock-2.diff.html b/src/srp/fw-ec/fn-lock-2.diff.html new file mode 100644 index 0000000..b3880e0 --- /dev/null +++ b/src/srp/fw-ec/fn-lock-2.diff.html @@ -0,0 +1,36 @@ +diff --git a/board/hx20/keyboard_customization.c b/board/hx20/keyboard_customization.c +index 2b91f2e0c..9a5050a0f 100644 +--- a/board/hx20/keyboard_customization.c ++++ b/board/hx20/keyboard_customization.c +@@ -249,6 +249,23 @@ int fn_table_set(int8_t pressed, uint32_t fn_bit) + return false; + } + ++static void hx20_update_fnkey_led(void) { ++ /* Turn the capslock light into a fn-lock light */ ++ gpio_set_level(GPIO_CAP_LED_L, (Fn_key & FN_LOCKED) ? 1 : 0); ++} ++ ++/* Set the fn-lock light to the correct setting when the system resumes */ ++void hx20_fnkey_resume(void) { ++ hx20_update_fnkey_led(); ++} ++DECLARE_HOOK(HOOK_CHIPSET_RESUME, hx20_fnkey_resume, HOOK_PRIO_DEFAULT); ++ ++/* Disable the fn-lock light on suspend */ ++void hx20_fnkey_suspend(void) { ++ gpio_set_level(GPIO_CAP_LED_L, 0); ++} ++DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, hx20_fnkey_suspend, HOOK_PRIO_DEFAULT); ++ + void fnkey_shutdown(void) { + uint8_t current_kb = 0; + +@@ -420,6 +437,7 @@ int functional_hotkey(uint16_t *key_code, int8_t pressed) + Fn_key &= ~FN_LOCKED; + else + Fn_key |= FN_LOCKED; ++ hx20_update_fnkey_led(); + } + return EC_ERROR_UNIMPLEMENTED; + } diff --git a/src/srp/fw-ec/hybrid.diff.html b/src/srp/fw-ec/hybrid.diff.html new file mode 100644 index 0000000..a37d3b5 --- /dev/null +++ b/src/srp/fw-ec/hybrid.diff.html @@ -0,0 +1,88 @@ +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; diff --git a/src/srp/fw-ec/index.html b/src/srp/fw-ec/index.html index d8a48ba..cdfc8b5 100644 --- a/src/srp/fw-ec/index.html +++ b/src/srp/fw-ec/index.html @@ -87,6 +87,161 @@ tuples which is awesome, because it opens the door to custom RGB effects in the future!

+ +

There’s More Than One LED!?

+ +

+ That’s right! The Framework laptop I own (13″; the 16″ releases + soon though!) has 3 more LED lights. + One on the left of the chassis, one on right of the chassis, and + one on the capslock key. The capslock + LED acts as an indicator of whether or + not you’ve got capslock enabled. This is useless to me though, + because my custom keyboard layout doesn’t even support capslock + (see the next section) — so I patched it to be a function-lock + indicator instead! +

+ +

+ Here’s the diff — but do take care if you want to apply similar + patches to your laptop! The files I’m editing are under + board/hx20 since I’m on an 11th Gen Intel + CPU. If you have a different + CPU, you will probably need to fuck with + different code: +

+ +
+
+ ~/board/hx20/board.h +
+
m4_include(fn-lock-1.diff.html)
+
+ +
+
+ ~/board/hx20/keyboard-customization.c +
+
m4_include(fn-lock-2.diff.html)
+
+ +

+ As you can see, toggling the capslock + LED is as simple as + invoking gpio_set_level(). Not only that, but + disabling its functionality with the capslock key is as easy as + undefining the CONFIG_CAPSLOCK_SUPPORT macro. + Figuring out if the function key is locked is also really easy. + The Fn_key global variable is a bit-field containing + information pertaining to the function key, and we also + conveniently already have the FN_LOCKED constant + defined that we can bitwise-AND with Fn_key to check + the locked state! +

+ +

+ We also setup some hooks with the DECLARE_HOOK() + macro. These just ensure that we are behaving properly on system + resume and -suspend. +

+ +

The Hybrid Key

+ +

+ Wouldn’t it be cool if a physical key could represent two keys at + the same time? I thought so too. Like all Emacs users, I suffer + from a distinct lack of easily-accessible modifier keys. I need + escape because I use Vim bindings; I need left-control because + all the Emacs bindings use it; I need super for my + window-managers’ bindings; I need left-alt so I can type + characters that don’t come on a standard American keyboard (such + as ß, , and é), and now I have a + problem. All my modifiers are taken, but Emacs still needs a + meta key to work! +

+
+
+ Workflow by Randall Munroe +
+ XKCD Comic 1172 +
+ +

+ What will I ever do!? Well thanks to Framework making + the EC open-source, and conveniently + giving me a file called keyboard_customization.c, + I’m going to take two keys and stick them in one! The basic + premise is this: the capslock key is arguably the easiest + modifier key to hit, and it’s currently bound to the escape key + on my system. This is inefficient though, because nobody makes + key-bindings that chord the escape-key with another key; chords + are always done with a modifier like control, and Emacs is no + different. So my plan was to make it so that the capslock key + when used on its own mimics an escape-key, while instead + mimicking the left-control-key when used in a chord with another + key. +

+ +

+ It took me a little longer this time to figure out how to + implement what I wanted since the code isn’t as clear, but it was + still a surprisingly easy feature to patch into the + EC! I basically just updated the + scancode table, swapping out the capslock scancode for my own + random one that I called SCANCODE_CTRL_ESC. I then + created a new function called try_ctrl_esc() which + is called in the on-keyup and -down callback function. The + try_ctrl_esc() function handles all of the logic as + you can see in the following diff; it’s basically just a state + machine: +

+ + + +
+
~/board/hx20/keyboard_customization.c
+
m4_include(hybrid.diff.html)
+
+ +

+ One thing that’s good to take note of is what I return from + try_ctrl_esc(). The general pattern for handling a + keyup or -down event is to stick the following code into + keyboard_scancode_callback(): +

+ +
+
+ keyboard_scancode_callback() in + ~/board/hx20/keyboard_customization.c +
+
m4_include(kbd-sc-cb.c.html)
+
+ +

+ In my_handler_function() (or whatever you decide to + name it), you attempt to handle the event. If you don’t want to + handle a particular event and instead want to pass it on to the + next handler, you need to return EC_SUCCESS. If you + managed to successfully handle the event though, then you need to + return an error such as EC_ERROR_UNIMPLEMENTED. + It’s pretty stupid and makes very little sense from a naming + perspective, but oh well… +

+ +

What’s Next?

+ +

+ RGB + LEDs + maybe. +


diff --git a/src/srp/fw-ec/kbd-sc-cb.c.html b/src/srp/fw-ec/kbd-sc-cb.c.html new file mode 100644 index 0000000..6fffdc5 --- /dev/null +++ b/src/srp/fw-ec/kbd-sc-cb.c.html @@ -0,0 +1,7 @@ +/* “make_code” is the scancode. “pressed” is a boolean that is true if this is a + * keydown event, and false if it’s a keyup. + */ + +r = my_handler_function(make_code, pressed); +if (r != EC_SUCCESS) + return r; diff --git a/src/style.css b/src/style.css index 2b67620..45ac7df 100644 --- a/src/style.css +++ b/src/style.css @@ -7,6 +7,7 @@ --accent: #DE935F; --lesser: #969896; --green: #B5BD68; + --blue: #81A2BE; --red: #C66; } @@ -83,7 +84,6 @@ aside { font-style: italic; color: var(--lesser); position: relative; - margin-block: 1.5rem; } aside > p::before, @@ -123,16 +123,12 @@ abbr::before { pointer-events: none; } +abbr.cpu::before { content: 'Central Processing Unit'; } abbr.ec::before { content: 'Embedded Controller'; } abbr.html::before { content: 'Hypertext Markup Language'; } abbr.led::before { content: 'Light-Emitting Diode'; } abbr.rgb::before { content: 'Red Green Blue'; } -.diff-ins { color: var(--green); } -.diff-del { color: var(--red); } -.diff-loc { color: var(--lesser); } -.diff-meta { font-weight: bold; } - figure > pre { margin-left: 4ch; overflow-x: scroll; } figure > pre > code { counter-increment: line; } figure > pre > code::before { @@ -149,6 +145,12 @@ figure > pre > code::before { background-color: var(--bg); } +figure > img { + display: block; + margin: 16px auto; + width: 50%; +} + header > div { display: flex; justify-content: space-between; @@ -160,3 +162,12 @@ header > div menu { gap: 2ch; } header > div li { list-style: none; } + +.c-cmt { color: var(--lesser); } +.c-fn { color: var(--accent); } +.c-kw { color: var(--green); } +.c-pp { color: var(--blue); } +.diff-ins { color: var(--green); } +.diff-del { color: var(--red); } +.diff-loc { color: var(--lesser); } +.diff-meta { font-weight: bold; } -- cgit v1.2.3