Keychron K3 Function Keys With Udev Trigger

I wrote previously about how to configure the Keychron K2 / K3 mechanical keyboards) so their function keys work in function key mode (and not the default multimedia mode).

The previous technique uses a one-shot systemd unit to run a command that sets a bit in the keyboard’s /sys device. It works generally well, but my experience has shown that it assumes the keyboard is always present at boot time (when the multi-user systemd target runs). this is not always the case for me because I use the keyboard primarily over Bluetooth; sometimes I turn it off when I’m going to be away for a while / overnight, and the keyboard itself disconnects and sleeps after 10 minutes of inactivity.

Annoyed at having to run the sys command manually every time the keyboard disconnects, I wrote a udev rule to handle this when the keyboard connect or disconnects. This is similar to my old Logitech K380 which uses this to toggle function key settings and uses a udev rule from here.

I first had to determine which parameters to use to write a rule that fires when the device is added. I followed this guide on how to write udev rules, and first obtained the input device for the Keychron keyboard by grepping, with the keyboard connected:

$ grep -ri 'keychron' /sys/bus/hid/devices/*/input/* 2>/dev/null
/sys/bus/hid/devices/0005:05AC:024F.004B/input/input89/uevent:NAME="Keychron K3"
/sys/bus/hid/devices/0005:05AC:024F.004B/input/input89/name:Keychron K3

Next, I checked the attributes for the associated input device thingy:

$ udevadm info -a -p /sys/bus/hid/devices/0005:05AC:024F.004B/input/input89

  looking at device '/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.0/bluetooth/hci0/hci0:256/0005:05AC:024F.004B/input/input89':
    ATTR{name}=="Keychron K3"

  looking at parent device '/devices/pci0000:00/0000:00:14.0/usb3/3-10/3-10:1.0/bluetooth/hci0/hci0:256/0005:05AC:024F.004B':

The device itself and its parent provide enough information to write a rule using the “name” attribute and the “DRIVERS” from the hid device. I could have used another parent higher up the tree, but this seemed fine, because apparently the next parent up is either a bluetooth or a USB thing, and I wanted the rule to work whether I connect via either method; so using the hid subsystem’s apple driver which is commeon to both, and the final input device which is unequivocally the Keychron keyboard, works with both.

Assuming one were to want different configurations for multiple connected Keychrons of the same model/name, one could scope the rule by ATTR{phys}.

The resulting udevadm rule can be written to disk like so:

cat <<EOF | sudo tee /etc/udev/rules.d/80-keychron-k3.rules
# Drivers comes from the parent device (hid bluetooth)
# ATTR{name} is from the input subsystem device
ACTION=="add", DRIVERS=="apple", ATTR{name}=="Keychron K3", RUN+="/usr/local/bin/keychron-k3-fnkeys"

And then the actual script is very simple/unrefined, since it doesn’t depend on any variables that change each time the device is connected (which we might be able to get via udev variables somehow):

# Place this in /usr/local/bin/keychron-k3-fnkeys
# Runs as root so no sudo is needed
echo 0 > /sys/module/hid_apple/parameters/fnmode

remember to make the script executable sudo chmod 755 /usr/local/bin/keychron-k3-fnkeys and it should run from the udev rule upon connecting the Keychron keyboard.

Selecting Canned Responses With Fzf and Xclip

If you do any kind of support or deal with customers in any way, it’s likely that 80% of incoming requests can be served by sending a canned reply about one of a handful of common issues.

I keep my canned replies in a specific directory, copy them to the clipboard using xclip and then paste them in whichever web-based ticketing system the request comes from.

For this I used to rely on CTRL-R completion using fzf, but that’s becoming kind of unwieldy; so instead, I crafted an fzf-powered oneliner that gives me a responses command. I run that and I get a list of all the canned responses in the directory with auto-completion as per fzf, and also a nice preview window so I can ensure the text contains what I need to send. On pressing ENTER, this is put in the clipboard courtesy of xclip ready to be pasted.

function responses(){
    xclip -selection c $(find ~/Documents/w/responses -type f | fzf --preview-window='up:40%' --preview 'cat {}')

The above goes in ~/.bashrc.

Signing Documents With SSH Key

It turns out you can use openssh keys to sign and verify files and documents.

The sender needs to do this:

  • Create a file /tmp/whatever with the text to verify, then sign it with:
openssl dgst -sha512 -sign ~/.ssh/id_rsa /tmp/whatever > /tmp/whatever.sig
  • Then base64-encode the sig and the whatever file:
base64 /tmp/whatever >/tmp/whatever.b64
base64 /tmp/whatever.sig >/tmp/whatever.sig.b64

generate checksums: sha512sum whatever* > checksums

And send the whatever.b64, whatever.sig.b64, and checksums files.

The checksum files allow verification that the content didn’t get mangled, because it’s easy for it to get borked in transit and this technique doesn’t provide a lot of integrity validation like e.g. GPG would.

Then the verifier does:

  • Obtain the ssh key in question. I use this technique with Launchpad public keys, so this works:
curl | grep "" > /tmp/
  • Convert the key to an openssl-compatible key:
ssh-keygen -e -f /tmp/ -m pkcs8 > /tmp/
  • Finally verify the documents (which you previously integrity-checked using sha512sum and the checksums file you received):
openssl dgst -sha512 -verify /tmp/ -signature /tmp/whatever.sig

A single script to demo the technique against my public Launchpad key:

KEY_IDENTIFIER="name of the key"

mkdir ssh-attestation
pushd ssh-attestation

# Signing procedure
echo "This is me" > attest
openssl dgst -sha512 -sign $KEY_ON_DISK attest > attest.sig
base64 attest > attest.b64
base64 attest.sig > attest.sig.b64
sha512sum attest* > shasums

# Verification procedure
echo "Verifying"
sha512sum -c shasums
# Brittle - maybe select by line number instead?
curl "$LAUNCHPAD_USER/+sshkeys" | grep "$KEY_IDENTIFIER" | grep -v "$KEY_EXCLUDER" >
ssh-keygen -e -f -m pkcs8 >
openssl dgst -sha512 -verify -signature attest.sig attest

Ubuntu 20.04 Deep Sleep

How else to get this

Suspend - the best way to get this kind of uptime

In an email thread with some colleagues, one of them mentioned that they had to force their laptop to use “deep” sleep instead of “s2idle”. This got me thinking - I’ve had the impression that my XPS13 sometimes doesn’t really suspend, and/or wakes up in the middle of the night, because the battery capacity sometimes is lower than it should be after being suspended overnight (going to sleep with 100% battery and having about 70% the morning afeter).

So I quickly looked up “s2idle” and landed here.

From here it looks like indeed s2idle is not really suspend-suspend and the system can wake up of its own accord according to unclear rules (or maybe they are clear, but I don’t care, I want the system to go to full sleep and only wake up when I open the lid or something similar). And it seems the way to get it to real deep-sleep is to write “deep” into /sys/power/mem_sleep. It further mentions that indeed s2idle is the default (which I confirmed by checking the above file), but it can be overridden by setting mem_sleep_default in the kernel command line.

It’s been a while since I last had to muck with GRUB configuration…

Just for kicks I also looked up mem_sleep_default and lo and behold, came upon a thread for the XPS 13 9310 (exactly the one I have).

Revamping Note Taking With Vimwiki

Inspired by some article on the Internet, I set out to modernize the way I take daily notes. Up until now I had simply been dumping date-named files in a single directory. This allows me to use standard tools such as grep for finding stuff in my notes, also referencing them by date when appropriate, preparing notes in advance by creating the file for a date in the future, and have comfortable aliases/commands to do things.

For example, mn (make note) creates or opens the notes file for the current day, while wmatrix creates or opens a weekly file with progress updates from the team, which I use to keep track of daily standup items and follow up if necessary.

The random article in question talks about Obsidian and how it provides nice rendered Markdown notes with collapsible GUI controls, a ton of keyboard shortcuts, a modern and friendly graphical display, and it can render link relations in the notes to display a “knowledge graph”. It does all this on top of a local folder containing .md files, so it’s quite future-proof and portable, and provides mobile apps and some synchronization (which I haven’t explored) to keep notes updated.

I tried it and it felt quite heavyweight for a glorified note taker. I found the controls distracting, the general application not providing a ton of value over a single directory of files, and most importantly, the extensive keyboard navigability requires me learning another set of keybindings which at this point I’d really rather avoid.

Obsidian in action

The same random article, however, also pointed me in the direction of vimwiki. In essence, Obsidian’s knowledge base is a local wiki, and this is exactly what vimwiki provides - indeed, in the article they are identified as complementary to each other, with vimwiki providing editability and access via the command line, and Obsidian allowing remote access and a graphical view, when needed.

I configured vimwiki to use Markdown and store files next to my old notes folder:

let g:vimwiki_list = [{'path': '~/Documents/w/vimwiki',
                      \ 'syntax': 'markdown', 'ext': '.md'}]

The experience from vim is fantastic; \ww opens a wiki index, and from there any single word can become a link by hitting ENTER in command mode on top of it. Vimwiki automatically creates the target and you can start writing Markdown in it, which is nicely syntax-colored. Vimwiki automatically handles indenting and formatting of lists, tables and markdown headings, and nicely collapses and linkifies URLs. It can even manage to-do lists in brackets [ ] and indent/dedent hierarchical table entries.

Vimwiki also has the concept of “diary” entries which are automatically created under the current date’s name, as well as useful shortcuts for “yesterday” and “tomorrow” pages, and can auto-generate an index for all diary/dated entries.

Vimwiki has wiki-wide search functionality via :VWS, though of course one can still shell out and use grep in a directory of raw .md files for ultimate portability.

I updated my mn and wmatrix aliases to integrate with vimwiki and have been happily using it for the past few days. The experience is pretty close to what I had with my old raw notes folder with some niceties added on top; I’ll probably start leveraging them more as I get more familiar with the setup.

Run Command on File Update

This is a poor man’s “watch a file for changes and when it does, run a command”.

while true; do inotifywait --event modify a-document.tex ; pdflatex a-document.tex ; done

Keychron K3 Function Keys

The Keychron K2 and K3 have dual-purpose media/function keys. The accompanying card says to use fn+x+l to change modes, but I tried it and it didn’t work. I need my function keys, I’m already used to pressing fn when I do need to access multimedia functionality.

I found this repo which explains how to set up a systemd service to configure the keys by writing a value to a driver configuration file. This works, but I was also able to get this changed immediately (though not persistently) by doing:

# Set the keys to operate in Fx mode
echo 0 | sudo tee /sys/module/hid_apple/parameters/fnmode

# Set the keys to operate in multimedia mode

echo 1 | sudo tee /sys/module/hid_apple/parameters/fnmode


Esta es una historia de fantasmas. Los nombres han sido cambiados para proteger identidades.

Hola que tal mi nombre es L. B. C. vivo en el estado de mexico ( municipio de chimalhuacan ) en mi casa abitan no se si talvez sean niños pero el asunto es de que hay alguien mas en nuestra casa en ocaciones mis hermanos pequeños ven un niño de color oscuro en mi cuarto y disen que se pone a brincar en mi cama.

Una ocacion mi hermana estaba en el baño y dejo la puerta abierta y entonses le empeso a gritar a mi mama pero no le hiso caso entonses mi hermana empeso a llorar talves de temor por que como enfrente del baño esta su cuerto de mi hermana, dise que vio a un niño que se asomo y se metio rapido a su cuarto entonses ya cuando llego mi mama a ver por que estaba llorando estaba bien espantada.

Antes de que esto susediera a nadien de nosostros nos abian espantado al unico que le pasaba era a mi hermano el tambien beia niños en el baña y en la sala, eso lla tiene tienpo y desde aquel entonses ya no habiamos hescuchado ni bisto nada, hasta que una noche llo me dormi un poca tarde, y entonses desde el momento que me fui a costar senti miedo y en eso que bolteo a la puerta pribnsipal de los dos cuartos y bi una sirueta que esta en la puerta el tamaño era de una persona adulta, pero como a mi me dio mucho miedo me tape toda la cara, pero enseguida de que me tape la cara senti que algo le levantaba todo el coberto y la colcha que tenia con eso senti en miedo increible.

En este tiempo que mis hermanos an estado biendo los niños a mi me esta pasando que lla cuando me voy a dormir siento como una presensia o alguien que se hacerca a mi asta siento como se me va hacercando cada vez mas pero volteo y no veo nada.

Bueno talvez no se si estar seguro de saber de lo que esta pasando hay pero quisiera que me ayudaran mi telefono es el 5XXXXXXX mi domisilio es ( Calle XXXXXX Manzana 2 Lote 11 San Ajustin Chimalhuacan )

Una cosa mas disen que antes de que nosotros construlleramos la casa hase como 8 años era un kinder y una guarderia.

Bueno es todo lo que les puedo mensionar les agradeseria si me informaran de algo ADIOS.

Itunes on Ubuntu

I’m cheating because this uses virtualbox.

This is ubuntu 20.04.

install these debs:


Download this Win10 evaluation/development VM

or a suitable one from here

Unzip the file, then on virtualbox, import the VM from the ova file.

Update settings for the VM and enable USB controller, with xHCI so it doesn’t take ages to transfer files.

Boot the VM, log in.

Download itunes from apple inside the vm (maybe with edge):

(I couldn’t install from the ms app store because reasons)

Start itunes by keeping SHIFT pressed while opening itunes:

Choose the path where the itunes library is.