25

I am trying to find a way to remap keyboard keys forcefully.
I tried using xmodmap and setxkbmap, but they do not work for one specific application. Such commands work for other normal windowed/applications on X tho.

I think the application may be reading the keyboard raw data and ignoring X input?

So, how to remap keys without using xmodmap and setxkbmap? if it is ever possible to be done using some software.

I also tried xkeycaps, xkbcomp, but did not try loadkeys, as it is running on X.

I found here that I could try setkeycodes, "because after assigning kernel keycode the button should work in xorg", but I also found that "you can't use 'setkeycodes' on USB keyboards", that's my case (I am interested in case someone make it work on ps2 as I think I could use an adapter).

This seemed promising "Map scancodes to keycodes", but after a few tests nothing changed, here are they:
I found keycode "36" ("j" key) at vt1 with showkey
I found scancode "7e" (keypad ".") at vt1 with showkey --scancodes

$cat >/etc/udev/hwdb.d/90-custom-keyboard.hwdb
keyboard:usb:v*p*
keyboard:dmi:bvn*:bvr*:bd*:svn*:pn*:pvr*
 KEYBOARD_KEY_7e=36
$udevadm hwdb --update #updates file: /lib/udev/hwdb.bin
$udevadm trigger #should apply the changes but nothing happened
$cat /lib/udev/hwdb.bin |egrep "KEYBOARD_KEY_7e.{10}" -ao
KEYBOARD_KEY_7eleftmeta
$#that cat on hwdb.bin did not change after the commands..

Obs.: did not work either with: KEYBOARD_KEY_7e=j

Some more alternative ways (by @vinc17) to find the keys:
evtest /dev/input/by-id/... or
input-kbd 3 (put the id index found at ls -l /dev/input/by-id/* from ex. event3)

PS.: *If you are interested on testing yourself, the related thread for the application is this: http://forums.thedarkmod.com/topic/14266-keyboard-issue-in-new-version-108/ The issues I have are the same: some keys (KP_Decimal, DownArrow, UpArrow, RightArrow) are ignored and considered all with the same value there "0x00"

  • The updated file should be /etc/udev/hwdb.bin, not /lib/udev/hwdb.bin. But though this file is updated correctly, this doesn't work for me either, even after a reboot. Perhaps something missing in the documentation. About this: https://bugs.freedesktop.org/show_bug.cgi?id=82311 – vinc17 Nov 21 '14 at 16:02
  • @vinc17 that is really interesting, as soon I can I will try again, I think we have to find that settings file and try to imitate it, thx! – Aquarius Power Nov 22 '14 at 16:28
  • 1
    My problem was due to the fact that the KEYBOARD_KEY_ lines started with 2 spaces instead of a single one (this wasn't documented and I got no error messages!). I don't know for you, but with my USB keyboard, showkey --scancodes doesn't give the scancodes udev expects (the values are different); the input-kbd utility gives the correct scancodes. – vinc17 Nov 26 '14 at 14:17
  • 1
    The evtest utility should also give you the correct scancodes: after typing a key, you should get 2 lines and the first one should end with something of the form code 4 (MSC_SCAN), value xxx, where xxx is the scancode. But the driver for my keyboard is buggy, and I don't get this MSC_SCAN line for some keys I wanted to remap. That's why I used input-kbd, which lists all the scancodes for the selected device. – vinc17 Nov 26 '14 at 14:28
  • interesting, I had none of these applications hehe! so it did work for you right? mind pasting the code? btw, at evtest the value for my keypad "." shows as 70085. I tried with this: KEYBOARD_KEY_70085=36, KEYBOARD_KEY_70085=7002c (7002c is the code of space bar btw); I tried with 1 space, 2 spaces and a TAB before that line at configuration file, none worked, may be I am still missing the right way to configure/type it? it show no error messages either.. – Aquarius Power Nov 27 '14 at 16:30
  • 1
    I've posted detailed info in an answer. Now, I'm not sure that 36 or 7002c works as a value. I think that you need the key code identifier. See my answer. – vinc17 Nov 28 '14 at 00:33

1 Answers1

27

First find the scancode of the key that needs to be remapped, e.g. with the evtest utility. A line like the following one (with MSC_SCAN in it) should be output:

Event: time 1417131619.686259, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70068

followed by a second one giving the current key code. If no MSC_SCAN line is output, this is due to a kernel driver bug, but the scancode can still be found with the input-kbd utility; evtest should have given the key code, so that it should be easy to find the corresponding line in the input-kbd output (e.g. by using grep).

Once the scancodes of the keys to be remapped have been determined, create a file such as /etc/udev/hwdb.d/98-custom-keyboard.hwdb containing the remappings. The beginning of the file /lib/udev/hwdb.d/60-keyboard.hwdb gives some information. In my case (which works), I have:

evdev:input:b0003v05ACp0221*
 KEYBOARD_KEY_70035=102nd       # Left to z: backslash bar
 KEYBOARD_KEY_70064=grave       # Left to 1: grave notsign
 KEYBOARD_KEY_70068=insert      # F13: Insert

(Before udev 220, I had to use keyboard:usb:v05ACp0221* for the first line.)

The evdev: string must be at the beginning of the line. Note that the letters in the vendor and product id should be capital letters. Each KEYBOARD_KEY_ settings should have exactly one space before (note: a line with no spaces will give an error message, and a line with two spaces were silently ignored with old udev versions). KEYBOARD_KEY_ is followed by the scancode in hexadecimal (like what both evtest and input-kbd give). Valid values could be obtained from either the evtest output or the input-kbd output, or even from the /usr/include/linux/input.h file: for instance, KEY_102ND would give 102nd (by removing KEY_ and converting to lower case), which I used above.

After the file is saved, type:

udevadm hwdb --update

to (re)build the database /etc/udev/hwdb.bin (you can check its timestamp). Then,

udevadm trigger --sysname-match="event*"

will take the new settings into account. You can check with evtest.

In 2014, the released udev had incomplete/buggy information in /lib/udev/hwdb.d/60-keyboard.hwdb, but you can look at the latest development version of the file and/or my bug report and discussion concerning the documentation and spacing issues.

If this doesn't work, the problem might be found after temporarily increasing the log level of udevd with udevadm control (see the udevadm(8) man page for details).

For old udev versions such as 204, this method should still work.

vinc17
  • 12,174
  • When I run the udevadm commands, the file that gets updated is /lib/udev/hwdb.bin, I looked with bless and the KEYBOARD_KEY_70085 appears at its end. I think ubuntu 14.04 is configured (protected?) this way. I tried udevadm control --log-priority=debug. based on lsusb (045e:0750) my keyboard gets like keyboard:usb:v045ep0750*, but I tried with keyboard:usb:v*p* too. My guess is this /etc/udev/hwdb.bin should be updated but doesnt even exist. – Aquarius Power Nov 29 '14 at 23:06
  • As I read here it could be like I was using this command udevadm hwdb --usr --update, despite I was not. – Aquarius Power Nov 29 '14 at 23:07
  • After udevadm hwdb --update I copied /lib/udev/hwdb.bin to /etc/udev/hwdb.bin and ran strace udevadm trigger --sysname-match="event*" and the file hwdb.bin seems have not been read by it (if it is like this works). – Aquarius Power Nov 29 '14 at 23:16
  • as it works for you, my guess is my system is bugged (as this functionality seems somewhat bugged), as soon I can, I will see if I can upgrade my packages and may be this can work! my udevadm --version is 204 btw. – Aquarius Power Nov 29 '14 at 23:17
  • 1
    @AquariusPower Yes, there may be an Ubuntu specific bug (I'm using Debian/unstable). To see whether the database is read when doing udevadm trigger ..., see my test here. Note that before running udevadm trigger ..., you need to make sure that the modification time of the file has been updated, otherwise the access time will not be updated when the file is read. – vinc17 Nov 29 '14 at 23:23
  • will check the test (btw I would like to link this question) – Aquarius Power Nov 29 '14 at 23:26
  • oh, while I was testing, I checked if the hwdb.bin was being updated with bless hexeditor; I saw at its end the KEYBOARD_KEY_70085 that I was trying to remap had been written there. And that file had its timestamp updated! :). it really looks like a bug or a limitation here. What is your udevadm --version? – Aquarius Power Nov 29 '14 at 23:31
  • btw, I did not reboot as I need this to be changeable without rebooting, on the fly. May be this is intended to only work with a reboot? – Aquarius Power Nov 29 '14 at 23:36
  • 1
    @AquariusPower udevadm --version: 215 (and udev package version: 215-7). Thanks to udevadm trigger ..., you shouldn't need to reboot (unless you want to remove settings, AFAIK). But you may want to try a reboot to see if there is any effect. – vinc17 Nov 29 '14 at 23:44
  • I think that is it, on my system the highest version possible to install thru package manager is 204! here I found that 215 is the latest udev and is on the ubuntu vivid that unfortunately is not LTS. I have to think on this, may be a version between 204 and 215 may work and is installable without too much trouble here. May be also a fix may be provided for this 204 old version too! Thx! – Aquarius Power Nov 30 '14 at 19:54
  • @AquariusPower I've added an alternate method at the end of my answer for old udev versions. – vinc17 Nov 30 '14 at 20:15
  • cool, I created this file /etc/udev/keymaps/mykeymaps.cfg with 0x70085 grave, and this file /etc/udev/rules.d/98-my-custom-keyboard.rules with ACTION!="remove", SUBSYSTEMS=="usb", ENV{ID_VENDOR_ID}=="045e", ENV{ID_MODEL_ID}=="0750", RUN+="keymap $name /etc/udev/keymaps/mykeymaps.cfg"; I saw on the README that udev should monitor and apply such rules but nothing happened yet, any idea? any way to force/check if it is being read/applied? – Aquarius Power Dec 01 '14 at 19:50
  • @AquariusPower I don't know why it doesn't work for you. Still nothing after reboot? This method worked very well for me under Debian up to udev 204, and when I upgraded to udev 215, I had to use the new hwdb method. Check in dmesg output that there's a "New USB device found" line corresponding to your idVendor/idProduct. If not, this may be a kernel/driver bug. Otherwise you should see with a udev developer. – vinc17 Dec 01 '14 at 21:17
  • yes, I found it on dmesg and with lsusb, I think my kernel or driver is buggy or there is something else that ubuntu does to protect the system from being easily tweaked like that :/. As soon I can I will try a boot with a liveCD that has udev 215+ and see what happens :D. – Aquarius Power Dec 01 '14 at 23:29
  • oh btw, I would like to add that after reboot, the udev 204 says that /etc/udev/keymaps/mykeymaps.cfg was not found! that seems a serious bug or may be it should be configured in some other undocumented way... Anyway, I think messing too much with a buggy app is not good idea unless on critical situations; better is try to update it as soon I can... – Aquarius Power Dec 04 '14 at 18:24
  • Note that is is necessary to use the format evdev:input:b*v*p* since v220. https://unix.stackexchange.com/a/216811/168688 – Michael Yoo Jul 30 '17 at 10:26
  • Question: What's the difference between KEYBOARD_KEY_70039 from MSC_SCAN, value 70039 and KEYBOARD_KEY_58 from code 58 (KEY_CAPSLOCK)? They seem to achieve the same effects? – Michael Yoo Jul 30 '17 at 10:28
  • Note that when using evtest to get the scancodes, the value of the EV_MSC,MSC_SCAN line is the scancode, and the value of the EV_KEY line (the next/second line) is the keycode, and the hwdb rule maps scancodes (former) to keycodes (latter). I got confused because my USB keyboard gave scancodes in the form of "70032", while my laptop gave me scancodes of the form "1d". I must have tested wrong, and KEYBOARD_KEY_58 shouldn't have worked. – Michael Yoo Jul 30 '17 at 11:12
  • @MichaelYoo Thanks for the reminder about the change in udev 220; I've now updated my answer (I forgot to do this when I updated my config). 70039 is here the scancode, and 58 (event code) is the keycode; for instance, you can use "58" instead of "capslock" (in the past, I had to use "86" instead of "102nd" due to this bug). Note that the scancodes depend on the keyboard. – vinc17 Jul 31 '17 at 13:53
  • I used evdev:input:b*v*p* directly so I did not need to figure out the specific values to fill in to identify my keyboard. – vossad01 Nov 28 '17 at 00:24
  • 2
    For the evdev:input:bZZZZvYYYYpXXXX, ZZZZ, YYYY and XXXX and are the 4-digit hex uppercase bus, vendor and product ID (they are explained in /lib/udev/hwdb.d/60-keyboard.hwdb). To obtain these values of your keyboard, first use evtest to identify the event number eventX of it, then check files under /sys/class/input/eventX/device/id/. – zsrkmyn Dec 06 '19 at 05:57
  • finally, I retried this on ubuntu 20.04 and worked great, thx!! I created this example if it can help: https://gist.github.com/AquariusPower/83748456a59ea743ae034ed78b14f646 – Aquarius Power Sep 11 '20 at 05:49