Keyboard layout unable to recognize pipe

Jason’s remarks prompted me to dig into this a bit more even though that was a rabbit hole I didn’t care to venture into.

Using setkeycodes is about as low level as it can get, I’m afraid. Everything I’ve seen seems to say that yes indeed, the scan codes are a function of the keyboard hardware and associated controller. Back in the bad old days there was actually an intel 8042 microcontroller at ports x60 and x64. Even today, the Linux AT keyboard driver talks through those ports to something that behaves like the legacy controller.

Effectively, the controller scans the key switch matrix and provides a stream of scan codes as key presses occur, and those scan codes are more or less standardized based on the keyboard vendor’s model and layout. That being given, it is up to either the BIOS or the OS keyboard driver to map the scan codes to the key numbers which are used by all the higher layers of abstraction from the Linux virtual console up through X apps.

When you’re using a GRUB2 console, the scan code to key number translation must be done by SeaBIOS which Purism has bundled with Coreboot. They will have taken care to make sure the resulting key number matches the legend on the key. This explains why it works “right” for GRUB2.

John Savard has an excellent exposition of how keyboard evolution brought us to the layouts and scan code sets we have today at Based on his description of the standard 101-key keyboard and the international variants, it seems like the '13v2 keyboard is a compact version of the international UK keyboard. Search on his page for “International Keys” and pay particular attention to his description of the Int 1 and Int 2 keys. See also the layout diagrams below that comparing the US and UK variants and the scan codes assigned to each key location.

So we have an International UK keyboard here, but space constraints don’t allow for the Int 1 key near the left shift, which would be the \| key in the UK market. The Int 2 key is normally located where we expect to find \| and does produce scan code x2B, but in the UK market is normally <>. So it seems the vendor took the Int 1 key (UK \|) from its location near left shift and put is where we (US) expect to see that key. The Int 1 key they dispensed with altogether. So there is no physical key present on this keyboard which produces scan code x2B, and consequently no standard keyboard layout file is going to give us \|.

That’s why we have to accept the one and only scan code the key does produce (x56) and use setkeycode to assign it the desired key number. This tells the kernel to modify its scan-to-keyboard-number translation table. But Jason is right, this doesn’t help in early boot where only the initramfs is mounted. If you have \ or | in your LUKS disk passphrase you’re out of luck. If you boot into single user mode, rc.local is not run and you’re out of luck–at least you can run setkeycodes manually at that point.

It would be possible to modify the keyboard layout files used in the initramfs and later so that key number 86 yields \|. But if you have a use case where you sometimes need to switch layouts you’ll have mutliple files to maintain, and you might be doing manual edits every time they’re updated.

Better would be to somehow work the setkeycodes run into the initramfs somehow. I’m looking into the Fedora case–there it’s probably just a matter of adding a new dracut module. But I’m not familiar enough with how Debian derived distros build their initramfs to comment on that case.

More later when/if I get something working.


I have not been successful making this permanent on PureOS.

I can’t login as root on a virtual console, so I logged as myself and did “sudo -s” to get a root shell.

The “setkeycodes 56 43” command works and carries over to the GUI login on the F2 virtual console.

The “systemctl status rc-local” command produces similar output, but the last line is:

Active: inactive (dead)

Is an additional command needed to activate the rc-local service? (Clueless about the “systemctl” command and think it isn’t a good idea to experiment with it!)

I decided to experiment anyway… :slight_smile:

I tried “systemctl start rc-local” but that didn’t work.

A search for “rc.local example debian” found a post that said I need “#!/bin/sh -e” as the first line in rc.local, so I added it. Rebooted, and now the backslash / pipe key works correctly.

1 Like

Sorry if I wasn’t entirely clear the first time around–the systemctl status command was just a way to make sure the necessary systemd unit is in fact installed. That little piece of systemd is what runs the commands in rc.local at boot time, so as you discovered, all you need to do is create the rc.local file with the right commands in it.

You’re right about needing #!/bin/bash at the top too. I forgot about that because on my Fedora system the file already existed for other reasons.

Hi Dennis - thank you so much for doing the research on this before I could. I may look in to fixing this in the Debian initramfs. I have done some other things with initramfs in Debian, but I have never needed to change keymappings.

To others who might read this in the future:
If someone does happen to have \ or | in their LUKS passphrase, I suggest adding a LUKS passphrase that replaces \ with < and | with > so you will be able to unlock the device conveniently with a device that handles this key more normally. The other alternative would be to remove this key from your passphrase.

You can add a passphrase to a LUKS volume with the cryptsetup luksAddKey command. There are other places to find more details. Be careful if the data on your LUKS volume is important.

After reading an article on the Arch wiki, I came up with a more permanent fix

This uses udev and the systemd hdwb hooks provided by most upstream distros
This will work fine on the latest Ubuntu, Fedora, Arch etc

Create /etc/udev/hwdb.d/90-purism-pipe-symbol-fix.hwdb with these contents:


Then execute
sudo systemd-hwdb update
sudo udevadm trigger

Now the | \ key below backspace (backslash) should work as expected permanently


Created a pull request for the hwdb defaults systemd provides

Please leave a comment on the pull request if you also experience this issue or have suggestions. Thumb up emojis also count :slight_smile:


This appears to work. Thanks!

1 Like

Note, the file can’t have a trailing newline, and there is a single space before KEYBOARD_KEY - once I fixed those and ran the two commands again, I got pipes and backslashes immediately - thanks!

If you’re running qubes, do this in the dom0 terminal. All other vms will be affected immediately.

1 Like

You need to add an extra hash-bang for the shell. So the whole file becomes:

setkeycodes 56 43
exit 0

And you can test this with sysctl status rc-local; sysctl status rc-local.


Just bumping - This is still broken on laptops being shipped out right now. I got my laptop today and it still requires this ridiculous setkeycode command to fix every time I boot a livecd, and is unfixable in luks. Haven’t seen any response from support or a developer and it’s been, what, 4 months now? This is ridiculous.


From what I can tell, it’s a problem with the keyboard supplier more so than a problem of Purism. You could ask Purism to change keyboard suppliers, but then Librem production gets shut down for a while.

1 Like

it’s a problem with the keyboard supplier more so than a problem of Purism

Lmao what? They sell a product. They are responsible for what goes out. If they’re having supplier issues then they need to inform their buyers that what they’re buying is defective. They don’t get to just throw up their hands and go “oh it’s a supply side thing” and pretend the keyboards they’re selling to people are still working.


Have you tried the solution posted in this thread by @ewout on January 8?

I’ll grant you that Purism should try to include this fix by default, but they are a fairly small company tackling very large issues. They sell a Laptop with features that no other company offers. This laptop currently has a software-fixable keyboard glitch that can be run by the user. Hardly a critical issue.
Should they post a notice on the order page or something? Probably. But that’s also why these forums exist - so users can communicate with other users about issues and their solutions.
Should Purism suspend laptop production (and thus effectively revenue)? I’d say no.


I have to agree that Purism’s handling of this is less than stellar. While it appears to be a minor issue, I know it threw me for a loop when I tried to install PureOS on my new laptop right out of the box. At a minimum, make a note of this and the steps to perform and place it in the manual. This should not be a surprise that you have to try to search for when buying new high end hardware.


This confuses me a lot. I got my Librem 13 on Tuesday. Pipe worked.
I installed 700 PureOS updates (and I think I rebooted). Pipe worked.
Today, I got 500 new packages incoming, (which also broke KDE Plasma, but that’s a different story). Pipe broken.
I tried @ewout’s solution, but no luck. With or without it, showkey gives me 43, which is proper if I understand right.

Actually, that latest update pulled ewout’s fix in from upstream, possibly breaking it for the German layout I have.
So I tried to be clever and commented the lines in /lib/udev/hwdb.d/60-keyboard.hwdb, but still no effect (yes, I ran the two commands).
Any ideas, anybody?

I have the same issue with Librem 13 and PureOS. I got the keycode 43 for Pipe and Pound Sign on a german keyboard. Udev rules or setting the keycode doesn’t work.

Thank you!

In my case in addition to leaving the space before KEYBOARD_KEY it also helps if I get the commands typed correctly :slight_smile:

It’s completely ridiculous that this has not been resolved on a hardware or firmware level yet. It’s dissapointing that there has yet to even be a public announcment, or note in the “getting started guide” that one of the most common keys for developers doesn’t work by default. This is a huge problem for me because I regularly use iPXE to boot liveCD’s on my Librem.

I have a buspirate and have remapped keyscancodes on a ThinkPad T430S using tools by Hamish Coleman and would be interested to see if I could do it again if Librem would provide any details on the Embedded Controllers interaction with the keyboard.

@cmorche: Do you use it as a coreboot payload with the integrated wifi card?
Do you know, if that would work with USB 3.0 ethernet adapter well?