{"id":4376,"date":"2021-08-23T10:00:00","date_gmt":"2021-08-23T15:00:00","guid":{"rendered":"https:\/\/www.foell.org\/justin\/?p=4376"},"modified":"2023-04-17T10:08:48","modified_gmt":"2023-04-17T15:08:48","slug":"remapping-keyboard-keys-in-ubuntu-with-udev-evdev","status":"publish","type":"post","link":"https:\/\/www.foell.org\/justin\/remapping-keyboard-keys-in-ubuntu-with-udev-evdev\/","title":{"rendered":"Remapping Keyboard Keys in Ubuntu with udev \/ evdev"},"content":{"rendered":"\n<p>A coworker gave a lunch and learn about mechanical keyboards. I should have known it would be an entrance to a black hole&#8230; it all started 25 years ago with my beloved <a href=\"https:\/\/deskthority.net\/wiki\/NTC_KB-6251\">Zeos Keyboard with Alps keygates<\/a> &#8211; which I consequently wrecked after spilling a beer into it \ud83c\udf7a Then onto my <a href=\"https:\/\/deskthority.net\/wiki\/HHKB_Lite\">HHKB Lite2<\/a> which I still have but need a host of adapters to connect its <a href=\"https:\/\/en.wikipedia.org\/wiki\/PS\/2_port\">PS\/2 connector<\/a>. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" data-attachment-id=\"4386\" data-permalink=\"https:\/\/www.foell.org\/justin\/remapping-keyboard-keys-in-ubuntu-with-udev-evdev\/img_0346\/\" data-orig-file=\"https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0346-scaled.jpg\" data-orig-size=\"2560,1920\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;1.8&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;iPhone SE (2nd generation)&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;1629477169&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;3.99&quot;,&quot;iso&quot;:&quot;400&quot;,&quot;shutter_speed&quot;:&quot;0.033333333333333&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}\" data-image-title=\"img_0346\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0346-300x225.jpg\" data-large-file=\"https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0346-1024x768.jpg\" src=\"https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0346-1024x768.jpg\" alt=\"\" class=\"wp-image-4386\" srcset=\"https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0346-1024x768.jpg 1024w, https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0346-300x225.jpg 300w, https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0346-768x576.jpg 768w, https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0346-1536x1152.jpg 1536w, https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0346-2048x1536.jpg 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Now I&#8217;m entering the modern mechanical era with a <a href=\"https:\/\/www.keychron.com\/products\/keychron-k6-wireless-mechanical-keyboard\">Keychron K6<\/a> &#8211; a 65% keyboard that closely resembles my HHKB layout. It has Gateron Blue (light and clicky) switches that remind me of my famed Zeos board. Here&#8217;s the original layout:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"611\" data-attachment-id=\"4387\" data-permalink=\"https:\/\/www.foell.org\/justin\/remapping-keyboard-keys-in-ubuntu-with-udev-evdev\/img_0260\/\" data-orig-file=\"https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0260-scaled.jpg\" data-orig-size=\"2560,1528\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;1.8&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;iPhone SE (2nd generation)&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;1627404773&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;3.99&quot;,&quot;iso&quot;:&quot;400&quot;,&quot;shutter_speed&quot;:&quot;0.033333333333333&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}\" data-image-title=\"img_0260\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0260-300x179.jpg\" data-large-file=\"https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0260-1024x611.jpg\" src=\"https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0260-1024x611.jpg\" alt=\"\" class=\"wp-image-4387\" srcset=\"https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0260-1024x611.jpg 1024w, https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0260-300x179.jpg 300w, https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0260-768x458.jpg 768w, https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0260-1536x917.jpg 1536w, https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0260-2048x1222.jpg 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>My first issue is I have a bit of OCD when it comes to pairing. I expect insert\/del, home\/end, and page up\/down to be at least near each other, if not next to each other. So I changed the keycaps in the far right row, around the corner to the FN1\/2 keys. I used <a href=\"https:\/\/www.keycaps.info\/\">low(ish) profile DSA keys<\/a> on this edge to mimic the lower arrow keys from the HHKB. Also I got <a href=\"https:\/\/pimpmykeyboard.com\/dsa-individual-keys\/\">custom colored beige\/blue FN1\/FN2 keys<\/a> to quickly remind me that FN1 is for the gold functions and FN2 is for blue.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" data-attachment-id=\"4388\" data-permalink=\"https:\/\/www.foell.org\/justin\/remapping-keyboard-keys-in-ubuntu-with-udev-evdev\/img_0343\/\" data-orig-file=\"https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0343.jpg\" data-orig-size=\"2100,1575\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;1.8&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;iPhone SE (2nd generation)&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;1629409074&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;3.99&quot;,&quot;iso&quot;:&quot;640&quot;,&quot;shutter_speed&quot;:&quot;0.033333333333333&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;1&quot;}\" data-image-title=\"img_0343\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0343-300x225.jpg\" data-large-file=\"https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0343-1024x768.jpg\" src=\"https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0343-1024x768.jpg\" alt=\"\" class=\"wp-image-4388\" srcset=\"https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0343-1024x768.jpg 1024w, https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0343-300x225.jpg 300w, https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0343-768x576.jpg 768w, https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0343-1536x1152.jpg 1536w, https:\/\/www.foell.org\/justin\/files\/2021\/08\/img_0343-2048x1536.jpg 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Now I needed to change what the swapped keys did when I pressed them&#8230;<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>When it comes to <span class=\"emoji\">customizing<\/span> keyboards in Linux, there are at least 10 ways to skin this cat \ud83d\ude3c but for a one-to-one replacement, evdev is the answer. Why? Because <a href=\"https:\/\/brokkr.net\/2019\/01\/11\/customize-your-keyboard-layout-and-have-it-work-under-wayland\/\">it&#8217;s low-level enough to work with everything, whether you use Xorg or Wayland. It even works in the console<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Getting information about your keyboard<\/h2>\n\n\n\n<p>For our research you&#8217;ll probably need to install a couple of things:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt install evtest evemu-tools<\/code><\/pre>\n\n\n\n<p>You can use <code>evemu-describe<\/code> to get information about your keyboard. If you run <code>evemu-describe<\/code> without any arguments, you&#8217;ll be prompted to select the input device. I&#8217;ve highlighted my input in <strong>bold<\/strong>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>sudo evemu-describe<\/strong>\nAvailable devices:\n\/dev\/input\/event0:\tLid Switch\n...\n\/dev\/input\/event19:\tGeneric USB Audio\n\/dev\/input\/event20:\tKeychron K6 Keyboard\n\/dev\/input\/event21:\tKeychron K6 Consumer Control\n\/dev\/input\/event22:\tKeychron K6 System Control\n\/dev\/input\/event23:\tBluetoothMouse3600 Mouse\n\/dev\/input\/event24:\tBluetoothMouse3600 Consumer Control\nSelect the device event number &#91;0-24]: <strong>20<\/strong>\n# EVEMU 1.3\n# Kernel: 5.11.0-27-generic\n# DMI: dmi:bvnDellInc.:bvr1.7.0:bd10\/22\/2020:br1.7:svnDellInc.:pnXPS137390:pvr:rvnDellInc.:rn0G2D0W:rvrA00:cvnDellInc.:ct10:cvr:\n# Input device name: \"Keychron K6 Keyboard\"\n# Input device ID: bus 0x05 vendor 0x5ac product 0x24f version 0x11b\n# Supported events:\n#   Event type 0 (EV_SYN)\n#     Event code 0 (SYN_REPORT)\n...\n#     Event code 15 (SYN_MAX)\n#   Event type 1 (EV_KEY)\n#     Event code 1 (KEY_ESC)\n...\n# Properties:\nN: Keychron K6 Keyboard\nI: 0005 05ac 024f 011b\n...<\/code><\/pre>\n\n\n\n<p>Take note of the properties line towards the bottom:<br><code>I: 0005 05ac 024f 011b<\/code><br>It is the Bus\/Product\/Vendor\/Version identifier that we&#8217;ll use that to identify the keyboard in our hardware DB file.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Gather Keycode &amp; Scancode Information<\/h2>\n\n\n\n<p>Along with the Bus\/Product\/Vendor\/Version identifier, you&#8217;ll need scancodes and keycodes for our configuration file.<\/p>\n\n\n\n<p>The keys I wanted to replace on the far right are:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Home -&gt; Grave\/Tilde<\/li><li>Page Up -&gt; Insert<\/li><li>Page Down -&gt; Delete<\/li><\/ul>\n\n\n\n<p>To get scancodes, run <code>sudo evtest<\/code> and select the input device you want to test (same as above), and then press the keys you want to switch out.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>sudo evtest<\/strong>\nNo device specified, trying to scan all of \/dev\/input\/event*\nAvailable devices:\n\/dev\/input\/event0:\tLid Switch\n...\n\/dev\/input\/event19:\tGeneric USB Audio\n\/dev\/input\/event20:\tKeychron K6 Keyboard\n\/dev\/input\/event21:\tKeychron K6 Consumer Control\n\/dev\/input\/event22:\tKeychron K6 System Control\n\/dev\/input\/event23:\tBluetoothMouse3600 Mouse\n\/dev\/input\/event24:\tBluetoothMouse3600 Consumer Control\nSelect the device event number &#91;0-24]: <strong>20<\/strong>\nInput driver version is 1.0.1\nInput device ID: bus 0x5 vendor 0x5ac product 0x24f version 0x11b\nInput device name: \"Keychron K6 Keyboard\"\nSupported events:\n  Event type 0 (EV_SYN)\n  Event type 1 (EV_KEY)\n    Event code 1 (KEY_ESC)\n...\nTesting ... (interrupt to exit)\nEvent: time 1629497486.881450, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70028\nEvent: time 1629497486.881450, type 1 (EV_KEY), code 28 (KEY_ENTER), value 0\nEvent: time 1629497486.881450, -------------- SYN_REPORT ------------\nEvent: time 1629497489.406440, type 4 (EV_MSC), code 4 (MSC_SCAN), value 7004a\nEvent: time 1629497489.406440, type 1 (EV_KEY), code 102 (KEY_HOME), value 1\nEvent: time 1629497489.406440, -------------- SYN_REPORT ------------<\/code><\/pre>\n\n\n\n<p>For example, the scancode for the HOME key is <meta http-equiv=\"content-type\" content=\"text\/html; charset=utf-8\">7004a. The keycodes are printed in all caps, such as KEY_HOME. You can also look up keycodes <a href=\"https:\/\/hal.freedesktop.org\/quirk\/quirk-keymap-list.txt\">here<\/a>, or if you&#8217;re trying to add a new key that isn&#8217;t on your keyboard, you can find all keycodes in <code>\/usr\/include\/linux\/input-event-codes.h<\/code><\/p>\n\n\n\n<p>We&#8217;re going to put this all into a hardware DB file. The filename is arbitrary, as long as it has a <code>.hwdb<\/code> extension. I put a number at the beginning because config files like this are loaded in filename order. If something should load before or after, it can use a lower\/higher number (respectively).<\/p>\n\n\n\n<p><code>sudo vi \/etc\/udev\/hwdb.d\/50-k6keyboard-bt.hwdb<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Input device ID: bus 0x5 vendor 0x5ac product 0x24f version 0x11b\n# evdev:input:b&lt;bus_id&gt;v&lt;vendor_id&gt;p&lt;product_id&gt;e&lt;version_id&gt;-&lt;modalias&gt;\nevdev:input:b0005v05ACp024F*\n KEYBOARD_KEY_7004a=grave\n KEYBOARD_KEY_7004b=delete\n KEYBOARD_KEY_7004e=insert<\/code><\/pre>\n\n\n\n<p>It took several attempts to get this right. I didn&#8217;t realize that the format is very particular and it should look something like: <code>b0000v0000p0000e0000*<\/code>. Don&#8217;t include the hex prefix of <code>0x<\/code>. Also <a href=\"https:\/\/catswhisker.xyz\/log\/2018\/8\/27\/use_vecinfinity_usb_foot_pedal_as_a_keyboard_under_linux\/\">hex values must be capitalized in udev version 220 and above<\/a>. Lastly, <a href=\"https:\/\/unix.stackexchange.com\/questions\/639345\/remapping-keys-of-bluetooth-keyboard#comment1198349_639345\">put a * at the end to capture all the versions<\/a>. You can verify your version of udev by running:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ udevadm --version\n245<\/code><\/pre>\n\n\n\n<p>The keycode remapping lines must look like this:<br><code>KEYBOARD_KEY_&lt;scancode&gt;=&lt;keycode&gt;<\/code><br>The <a href=\"https:\/\/wiki.archlinux.org\/title\/map_scancodes_to_keycodes\">keycodes must be lowercase<\/a> on the right side of the .hwdb file.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Build &amp; Test<\/h2>\n\n\n\n<p>Once your hardware DB file is saved, you can test out the setup, by running these commands:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ <strong>sudo systemd-hwdb update<\/strong>\n$ <strong>sudo udevadm trigger<\/strong>\n$ <strong>udevadm info \/dev\/input\/event20<\/strong>\nP: \/devices\/pci0000:00\/0000:00:14.0\/usb1\/1-7\/1-7:1.0\/bluetooth\/hci0\/hci0:256\/0005:05AC:024F.0007\/input\/input41\/event20\nN: input\/event20\nL: 0\nE: DEVPATH=\/devices\/pci0000:00\/0000:00:14.0\/usb1\/1-7\/1-7:1.0\/bluetooth\/hci0\/hci0:256\/0005:05AC:024F.0007\/input\/input41\/event20\nE: DEVNAME=\/dev\/input\/event20\nE: MAJOR=13\nE: MINOR=84\nE: SUBSYSTEM=input\nE: USEC_INITIALIZED=4366743414\nE: KEYBOARD_KEY_7004a=grave\nE: KEYBOARD_KEY_7004b=delete\nE: KEYBOARD_KEY_7004e=insert\nE: ID_INPUT=1\nE: ID_INPUT_KEY=1\nE: ID_INPUT_KEYBOARD=1\nE: ID_BUS=bluetooth\nE: XKBMODEL=pc105\nE: XKBLAYOUT=us\nE: BACKSPACE=guess\nE: LIBINPUT_DEVICE_GROUP=5\/5ac\/24f:90:78:41:ca:1e:02\nE: TAGS=:power-switch:<\/code><\/pre>\n\n\n\n<p>The first command (<code>systemd-hwdb update<\/code>) reads the hwdb files and rebuilds the binary hardware database from the text files. The second (<code>udevadm trigger<\/code>) tells udev to (re)scan hardware for matches. The last (<code>udevadm info<\/code>) helps verify that the configuration &#8211; remember to replace event20 with your device ID.<\/p>\n\n\n\n<p>You can see in the output that my KEYBOARD_KEY entries are there and they do indeed work \ud83d\udcaa It will also be there after you reboot.<\/p>\n\n\n\n<p>My next step will be adding home\/end and page up\/down modifiers to my arrow keys&#8230;<\/p>\n<div class='kindleWidget kindleLight' ><img decoding=\"async\" src=\"https:\/\/www.foell.org\/justin\/wp-content\/plugins\/send-to-kindle\/media\/white-15.png\" \/><span>Send to Kindle<\/span><\/div>","protected":false},"excerpt":{"rendered":"<p>A coworker gave a lunch and learn about mechanical keyboards. I should have known it would be an entrance to a black hole&#8230; it all started 25 years ago with my beloved Zeos Keyboard with Alps keygates &#8211; which I consequently wrecked after spilling a beer into it \ud83c\udf7a Then onto my HHKB Lite2 which&hellip; <a href=\"https:\/\/www.foell.org\/justin\/remapping-keyboard-keys-in-ubuntu-with-udev-evdev\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"Remapping Keyboard Keys in Ubuntu with udev and loving the click! \ud83d\udd0a","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[1,8],"tags":[169,186,166],"class_list":["post-4376","post","type-post","status-publish","format-standard","hentry","category-business","category-ubuntu","tag-bluetooth","tag-keyboard","tag-linux"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/posts\/4376","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/comments?post=4376"}],"version-history":[{"count":18,"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/posts\/4376\/revisions"}],"predecessor-version":[{"id":4400,"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/posts\/4376\/revisions\/4400"}],"wp:attachment":[{"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/media?parent=4376"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/categories?post=4376"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/tags?post=4376"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}