Using the EC to change the keyboard layout on the Framework Laptop

Ever since Dustin Howett released his docs and tools for working with the framework laptop embedded controller, I've wanted to change the keyboard to my preferred layout, colemak. Today was the day! First I made sure I could remove a keyboard key without breaking it. Turns out it's really easy, and I didn't break a single one. It's basically just use the back of the provided screwdriver to pry up the top corners of the key until it pops off.

Then I wrote a script that changes each key one by one into the corresponding colemak key. Here's that script:

#!/bin/bash
# Framework en-us qwerty >>> colemak (caps lock unchanged) 

sudo fw-ectool raw 0x3E0C d1,d1,b3,b2,w0d # Tab > Tab
sudo fw-ectool raw 0x3E0C d1,d1,b0,b2,w15 # q > q
sudo fw-ectool raw 0x3E0C d1,d1,b6,b5,w1d # w > w
sudo fw-ectool raw 0x3E0C d1,d1,b2,b4,w2b # e > f
sudo fw-ectool raw 0x3E0C d1,d1,b6,b6,w4d # r > p
sudo fw-ectool raw 0x3E0C d1,d1,b3,b6,w34 # t > g
sudo fw-ectool raw 0x3E0C d1,d1,b3,b7,w3b # y > j
sudo fw-ectool raw 0x3E0C d1,d1,b6,b7,w4b # u > l
sudo fw-ectool raw 0x3E0C d1,d1,b6,ba,w3c # i > u
sudo fw-ectool raw 0x3E0C d1,d1,b3,b8,w35 # o > y
sudo fw-ectool raw 0x3E0C d1,d1,b5,bd,w4c # p > ;
sudo fw-ectool raw 0x3E0C d1,d1,b6,bd,w54 # [ > [
sudo fw-ectool raw 0x3E0C d1,d1,b6,be,w5b # ] > ]
sudo fw-ectool raw 0x3E0C d1,d1,b2,b8,w5d # \ > \

sudo fw-ectool raw 0x3E0C d1,d1,b4,b4,w58 # Caps > Caps (w66 for Bkspc)
sudo fw-ectool raw 0x3E0C d1,d1,b7,b2,w1c # a > a
sudo fw-ectool raw 0x3E0C d1,d1,b4,b5,w2d # s > r
sudo fw-ectool raw 0x3E0C d1,d1,b7,be,w1b # d > s
sudo fw-ectool raw 0x3E0C d1,d1,b7,b6,w2c # f > t
sudo fw-ectool raw 0x3E0C d1,d1,b2,b6,w23 # g > d
sudo fw-ectool raw 0x3E0C d1,d1,b2,b7,w33 # h > h
sudo fw-ectool raw 0x3E0C d1,d1,b7,b7,w31 # j > n
sudo fw-ectool raw 0x3E0C d1,d1,b7,ba,w24 # k > e
sudo fw-ectool raw 0x3E0C d1,d1,b7,b8,w43 # l > i
sudo fw-ectool raw 0x3E0C d1,d1,b7,bd,w44 # ; > o
sudo fw-ectool raw 0x3E0C d1,d1,b0,be,w52 # ' > '

sudo fw-ectool raw 0x3E0C d1,d1,b1,b5,w1a # z > z
sudo fw-ectool raw 0x3E0C d1,d1,b0,b5,w22 # x > x
sudo fw-ectool raw 0x3E0C d1,d1,b0,b0,w21 # c > c
sudo fw-ectool raw 0x3E0C d1,d1,b0,b6,w2a # v > v
sudo fw-ectool raw 0x3E0C d1,d1,b1,b6,w32 # b > b
sudo fw-ectool raw 0x3E0C d1,d1,b1,b7,w42 # n > k
sudo fw-ectool raw 0x3E0C d1,d1,b0,b7,w3a # m > m
sudo fw-ectool raw 0x3E0C d1,d1,b0,ba,w41 # , > ,
sudo fw-ectool raw 0x3E0C d1,d1,b0,b8,w49 # . > .
sudo fw-ectool raw 0x3E0C d1,d1,b0,bd,w4a # / > /

I kept caps lock the same because I use it as a modifier with sway.

to change it back to QWERTY:

#!/bin/bash
# Framework en-us qwerty defaults

sudo fw-ectool raw 0x3E0C d1,d1,b3,b2,w0d # Tab > Tab
sudo fw-ectool raw 0x3E0C d1,d1,b0,b2,w15 # q > q
sudo fw-ectool raw 0x3E0C d1,d1,b6,b5,w1d # w > w
sudo fw-ectool raw 0x3E0C d1,d1,b2,b4,w24 # e > e
sudo fw-ectool raw 0x3E0C d1,d1,b6,b6,w2d # r > r
sudo fw-ectool raw 0x3E0C d1,d1,b3,b6,w2c # t > t
sudo fw-ectool raw 0x3E0C d1,d1,b3,b7,w35 # y > y
sudo fw-ectool raw 0x3E0C d1,d1,b6,b7,w3c # u > u
sudo fw-ectool raw 0x3E0C d1,d1,b6,ba,w43 # i > i
sudo fw-ectool raw 0x3E0C d1,d1,b3,b8,w44 # o > o
sudo fw-ectool raw 0x3E0C d1,d1,b5,bd,w4d # p > p
sudo fw-ectool raw 0x3E0C d1,d1,b6,bd,w54 # [ > [
sudo fw-ectool raw 0x3E0C d1,d1,b6,be,w5b # ] > ]
sudo fw-ectool raw 0x3E0C d1,d1,b2,b8,w5d # \ > \

sudo fw-ectool raw 0x3E0C d1,d1,b4,b4,w58 # Caps > Caps
sudo fw-ectool raw 0x3E0C d1,d1,b7,b2,w1c # a > a
sudo fw-ectool raw 0x3E0C d1,d1,b4,b5,w1b # s > s
sudo fw-ectool raw 0x3E0C d1,d1,b7,be,w23 # d > d
sudo fw-ectool raw 0x3E0C d1,d1,b7,b6,w2b # f > f
sudo fw-ectool raw 0x3E0C d1,d1,b2,b6,w34 # g > g
sudo fw-ectool raw 0x3E0C d1,d1,b2,b7,w33 # h > h
sudo fw-ectool raw 0x3E0C d1,d1,b7,b7,w3b # j > j
sudo fw-ectool raw 0x3E0C d1,d1,b7,ba,w42 # k > k
sudo fw-ectool raw 0x3E0C d1,d1,b7,b8,w4b # l > l
sudo fw-ectool raw 0x3E0C d1,d1,b7,bd,w4c # ; > ;
sudo fw-ectool raw 0x3E0C d1,d1,b0,be,w52 # ' > '

sudo fw-ectool raw 0x3E0C d1,d1,b1,b5,w1a # z > z
sudo fw-ectool raw 0x3E0C d1,d1,b0,b5,w22 # x > x
sudo fw-ectool raw 0x3E0C d1,d1,b0,b0,w21 # c > c
sudo fw-ectool raw 0x3E0C d1,d1,b0,b6,w2a # v > v
sudo fw-ectool raw 0x3E0C d1,d1,b1,b6,w32 # b > b
sudo fw-ectool raw 0x3E0C d1,d1,b1,b7,w31 # n > n
sudo fw-ectool raw 0x3E0C d1,d1,b0,b7,w3a # m > m
sudo fw-ectool raw 0x3E0C d1,d1,b0,ba,w41 # , > ,
sudo fw-ectool raw 0x3E0C d1,d1,b0,b8,w49 # . > .
sudo fw-ectool raw 0x3E0C d1,d1,b0,bd,w4a # / > /

fw-ectool is an alias to ectool --interface=fwk that comes with my AUR package fw-ectool-git for Howett's ectool.

Don't run this if you don't know what those commands do! make sure you have an extra USB keyboard on hand in case you mess up - while I didn't need it, if I had accidentally overwrote some of the more critical letter keys or like enter I wouldn't be able to set it back.

The basis of this is from https://www.howett.net/posts/2021-12-framework-ec/#3e0c---keyboard-mapping

ideally I would like to do this in a more automated/cleaner way, so that the commands above are actually readable without multiple tables on screen. but to create the layout I had to first get the layout location for each key, then get the PC/AT keycodes for each target key from pdf page 52 (labeled 1-33) of this document. I would be willing to help with anyone wanting to do e.g. dvorak as well.

Benefits of doing it this way over setting layout in the OS include that it works anywhere the keyboard works, so bios, windows, linux, or whatever I install will be immediately correct with the OS set to the default en-us layout. It survives reboots, however if the device is shut down for more than 30 sec the EC resets and wipes the config, so I have a systemd unit to restore the layout when resuming from hibernation and fresh boots.

/usr/local/bin/fw-ec-setup is just a script that runs my remap script as well as a little light sequence (because the EC can be told how to light up the 3 onboard multicolor LEDs) to let me know it worked.

$ cat /etc/systemd/system/fw-ec.service 
[Unit]
Description=Setup EC for keyboard layout, lights, etc.
After=hibernate.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/fw-ec-setup
RemainAfterExit=false
StandardOutput=journal

[Install]
WantedBy=multi-user.target hibernate.target

As Dustin suggested I could even write an EFI driver to apply it before boot, but I use linux so much more than windows that making sure I reboot into windows and not a cold boot is not a big deal.

Dustin has also informed me that I could shrink down the above code into one or two single EC commands, each sequence can take 32 commands at once, however that will hurt the already terrible readability, so I decided against it. With the current setup it only takes 1.05 sec to run everything, and it happens long before I get to a login prompt, so I don't really care about speed either.

My original post on the framework forum

Leave a Reply

Your email address will not be published.