Pinebook Pro Keyboard Shenanigans
I'm not the fastest typer, and I don't really use 10 fingers- I'm closer to 7 or 8, but I try to minimize the amount of keypresses that I make. This means that I use shortcuts a lot, and if there's a key for it, I use it. One example of this (that involves the delete key) is how I press delete instead of right arrow and backspace.
And ever since I got my Pinebook Pro, I felt the distinct lack of a delete key.
What's worse was the fact that in place of a delete key was a power key, one that, once tapped, depending on the DE either showed a power menu, or shut off the PBP:
One of the first things after I installed Manjaro ARM was disabling the power button's system shutdown effects in
/etc/systemd/logind.conf, by setting
HandlePowerKey=ignore (and restarting
systemd-logind, which fyi kills X session)
Later on, to actually get it to work as a delete key I used something I did long ago, and just got the keycode from xev and set it with xmodmap to delete.
This wasn't perfect by any means, it had some delay, and some software like gimp just ignored it (which made image editing a lot more painful).
Then the project working on improving the keyboard and touchpad ended up releasing an update, one that allowed people to make their own keymappings.
I saw this while at work, put a note for myself:
I've been meaning to put aside some time to try and implement this behavior in the firmware itself, but I just couldn't find the time or the energy.
I don't have much of a story to tell tbh. I cloned the repo, downloaded the requirements, compiled the tools.
I compiled and installed
firmware/src/keymaps/default_iso.h (by following instructions on
firmware/src/README.md) just to see if it works or not, it did, so I continued on.
After setting up this new firmware, I did notice that some functionality worked differently though, such as:
- numlock didn't turn ha3f 6f the 2eyb6ard 5nt6 a n40-ad (numlock didn't turn half of the keyboard into a numpad), but simply allowed the numpad area on the keyboard to be used with fn keys, which is a much better way of doing things.
- Fn+F3 no longer pressed p. p.
- Keyboard/Touchpad name changed from the actual part name to “Pine64 Pinebook Pro”, breaking my
xinput set-propsettings. Simply renaming the device on the commands fixed this.
- Sleep button combination (Fn+Esc) did not work (I don't use this combination, but the fact that it had the image on the keyboard and worked prior to the flashing bothered me).
I copied the file
ave_iso.h, trying to figure out how it's structured. I tried to find the power button, and I couldn't find it.
There was this vague keyboard shaped array with key mappings, and I did get how one half of them worked, but I couldn't understand how the other half did:
Well, I dug in the codebase for a couple hours, trying to figure out everything, and it finally made sense.
FR, FS and FK are just arrays that are mapped to
fns_keypad arrays in the same file respectively. This is all explained on the
The number (such as 6 on
FR(6)) given as argument is the index from said array.
An example entry of
REG_FN(KC_Z, KC_NUBS) means that default action is
KC_Z, while action when Fn is held down is
KC means keycode, and they're mapped in
firmware/src/include/keycodes.h. Do note that not all descriptions are correct in practice though, one example is that
0xA5 is actually used for brightness up (I explain why this is the case later).
R() function used on rest of the keyboard are “Regular” keys, ones that have no actions with Fn. They're directly passed on to their
If you hate yourself, you can also supply regular integers in place of any of the aforementioned functions and anywhere where you see a
KC_, and this did help when I was trying to understand how things work.
FK is only able to be used with Fn keys when numlock is open. I'm not exactly sure what the difference of FR and FS are outside of semantics. (Looking at my own PR, I regret using FR instead of FS as I'm not fitting the semantics properly. Functionality seems the same though.)
I ended up implementing the sleep button combination, and I learned a lot about keyboards while trying to figure out how I could even emulate the power button. I have some links that I used during my adventure at the bottom of this article. I sent a PR with that patch and it got merged.
After asking around on the Pine64 #pinebook channel, I was told by a helpful person that the power button is wired to the SoC directly, and that SoC sends the power key input itself (or rather, that this input was handled by the device tree in the linux kernel and turned into an actual emulated keypress).
Most importantly however, they said that it could be remapped with udev. Now, I had only used udev rules to date,and it got me rather confused as I had no idea how one would remap anything with that. That got me to research how to do that, and I learned about a tool that I never used before:
And sure enough, I found it:
gpio-key-power and hitting the key, I immediately saw the keypress (this image was taken after the change, so it says
KEY_DELETE, before the change it used to say
Upon more research, I learned how to write
hwdb entries in udev, not
rules. Similarly, I found an already existing hwdb file in
/etc/udev/hwdb.d/10-usb-kbd.hwdb, which explained why the
KC_SYSTEM_POWER key was mapped to brightness up: Because the hwdb was set up this way. For reference, here's what it looks like:
evdev:input:b0003v258Ap001E* KEYBOARD_KEY_700a5=brightnessdown KEYBOARD_KEY_700a6=brightnessup KEYBOARD_KEY_70066=sleep
This also explained to me why
KC_POWER caused a sleep action and not a power key action when done through the builtin keyboard (but not through the dedicated power button).
I quickly wrote a hwdb file myself on
And upon recreating the hwdb file with
# systemd-hwdb update and triggering the hwdb with
# udevadm trigger /dev/input/event2, the power button started working as a proper delete key.
evtest saw it as
KEY_DELETE, the delay when tapping it rapidly vanished, and stuff like gimp started to acknowledge it. Now I just need to avoid holding it down.
- Detailed definitions for the keycodes: https://github.com/qmk/qmk_firmware/blob/master/docs/keycodes.md
- Explanation of the difference between KCPOWER and KCSYSTEMPOWER (aka KCPWR) (was helpful as I was confused as to why they were different): https://github.com/qmk/qmk_firmware/issues/1994
- More keycode definitions: http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc
- A question from askubuntu that made me realize that udev hwdbs exist: https://askubuntu.com/questions/877404/how-to-remap-xf86sleep-key-to-space-xmodmap-xkbcomp-udev-fail
- A blog post that was essential to me figuring out how to use hwdbs: http://who-t.blogspot.com/2019/02/adding-entries-to-udev-hwdb.html