Framework and the EC
Framework — for those unaware — is the coolest laptop manufacturer ever. Their whole shtick is producing laptops that give the user the ability to easily and effortlessly disassemble, repair, and modify their hardware. I highly suggest checking them out if you’re interested in computer hardware at all. The laptops even have hotswappable I/O!
Anyways getting back on topic, Framework has also been giving power to the user on the software-side of things too! A good while ago they open-sourced the code for the embedded controller of their laptops, which offers all sorts of possibilities for customization of the keyboard, LED lights, and more.
LED Fun!
This is an area of the EC which I have not really looked at or touched much. I do want to play around with this a lot more in the coming future though! So far just for shits-and-giggles, I’ve patched the EC to make the power-button LED green instead of the normal boring white:
As you can see, it’s all fairly simple. I just had to change our
EC_LED_COLOR_WHITE
for
EC_LED_COLOR_GREEN
. The codebase defines a few
colors, but they’re defined as RGB
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:
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!
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:
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()
:
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.