Keyboard layout unable to recognize pipe

The US keyboard layout in my librem 13v2 is unable to recognize the pipe symbol. It instead outputs ‘<’ . I managed to change the keyboard layout to English(US) with deadkeys where the pipe symbol worked, but this in turn caused the necessity to double press tilda key (~) and double quotes (") for them to be recognized.
I also tried dpkg-reconfigure keyboard-configuration as mentioned here - with no luck.

Could someone please tell me what is the correct layout to use/or the correct keyboard type to use in dpkg keyboard config.



Having the same problem (using Fedora 27), and xmodmap doesn’t seem to work to fix the mapping. I have got it fixed in the console with a loadkeys command, but that does not seem to carry over to the graphical environment

# in a console (e.g. Ctl+Alt+F3)
$ cat bar_fix.kmap 
keymaps 0-127
keycode 86 = backslash
shift keycode 86 = bar
$ sudo loadkeys bar_fix.kmap

But in a terminal window the following

$ xmodmap -e "keycode 86 = backslash bar"

theoretically should work, but seems to have no effect.

This is happening because the '13v2 keyboard produces a scancode of 0x56 for that particular key. Every other keyboard on the planet since the dawn of the pc/at at least (well, the 3 I’ve
looked at anyway ;)) produces a scancode of 0x2B.

On Fedora 26 with English (US) keyboard configured this is mapped to key number 86, and yields the < and > characters.

The scancode is, so far as I know, a property of the keyboard design and is fixed. So you need to change the key number that scancode 0x56 maps to.

From a virtual console (not the gui!) login as root and type the command:
setkeycodes 56 43

You should now find that the key produces pipe and backslash as it should, both in virtual console and in xorg/MATE/whatever and in wayland/gnome in the case of PureOS.

To make this change permanent, type:
systemctl status rc-local

You should see something like this, which is from Fedora:
rc-local.service - /etc/rc.d/rc.local Compatibility
Loaded: loaded (/usr/lib/systemd/system/rc-local.service; enabled-runtime; vendor preset: disabled)

Don’t try to enable/disable it; in both Fedora and PureOS it’s already correctly set up.

All you need is to create either /etc/rc.local (in PureOS) or /etc/rc.d/rc.local (for Fedora). The file should be owned by root and have perms 750:
-rwxr-x—. 1 root root 386 Dec 6 17:13 rc.local

Put the set keycodes command above in file with an exit code, so the content is:
setkeycodes 56 43
exit 0

Now when you reboot the key is fixed automagically and you don’t need to worry about it any more until you reinstall your system from scratch.


First of all - Dennis’s advice is great. I just opened up a Librem 13v2 and I was able to sort this strange / new issue to me out much faster thanks. This is a pretty good workaround.

I am wondering if there might be some way to fix this quirk on a lower level. Is it possible to change the scan code coming from the keyboard in coreboot? Or perhaps update the keyboard firmware if that is possible.

I made a couple observations while digging in to this issue.

  1. This issue occurs in Debian Stretch and PureOS (in addition to Fedora 26 and 27 as other users reported).
  2. GRUB2 detects the key as a normal \ | key

Is it possible that the keyboard on my laptop has a UK firmware or something strange going on in it?
I’d like to actually correct the scancode if possible, because this will help fixing the keyboard on other operating systems and in cryptsetup or busybox before a full boot.
I might figure out how to get the setkeycodes command to run as part of initrd but I’m curious if anybody has ideas on what is possible (or might be odd) on a lower level.


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?