Kernel Input – Capturing and Mapping Key Input from Events Device

driverseventsinputkernel

I have a Lenovo IdeaPad Yoga 13 with Ubuntu 13.10 Installed. The device has a "Toggle TouchPad" button on the keyboard (F5). The keyboard's F* buttons are reversed (so to get F5, I need to press Fn + F5, and F5 is actually the toggle key).

I've found out that the button is actually read by the keyboard (rather than the TouchPad like certain devices), which is at /dev/input/event3. So using sudo input-events 3 I was able to figure out that the button sends the scan code 190:

Output of sudo lsinput:

/dev/input/event3
   bustype : BUS_I8042
   vendor  : 0x1
   product : 0x1
   version : 43907
   name    : "AT Translated Set 2 keyboard"
   phys    : "isa0060/serio0/input0"
   bits ev : EV_SYN EV_KEY EV_MSC EV_LED EV_REP

Output of sudo input-events 3:

23:13:03.849392: EV_MSC MSC_SCAN 190
23:13:03.849392: EV_SYN code=0 value=0
23:13:03.855413: EV_MSC MSC_SCAN 190
23:13:03.855413: EV_SYN code=0 value=0

No other programs (such as xev) seem to be able to read it except for input-events. Is there any way to map this button to make it toggle the TouchPad on my laptop? If so, how can I do so?

Best Answer

As it turns out the kernel did pick it up, but kept complaining that it's not recognised.

For anyone else having this issue, or wants to map a key that's not read by the OS, read on.

Open a terminal and run dmesg | grep -A 1 -i setkeycodes. This will give you multiple entries like this:

[    9.307463] atkbd serio0: Unknown key pressed (translated set 2, code 0xbe on isa0060/serio0).
[    9.307476] atkbd serio0: Use 'setkeycodes e03e <keycode>' to make it known.

What we are interested is the hexadecimal value after "setkeycodes", in this case this is e03e. If you have multiple of these, you can run tail -f /var/log/kern.log. Once you've done so, you can tap the button you're looking for, and this will give you a the same line as above, and again, we only need the hexadecimal value. Make a note of this.

Now run xmodmap -pke | less and find the appropriate mapping. In my case, I needed to map this to toggle my touch pad, which means I was interested in the following line:

keycode 199 = XF86TouchpadToggle NoSymbol XF86TouchpadToggle

If you can't find whatever you're interested in, read @Gilles answer too, as you can define custom mappings too, then read on (if the kernel reads it, you won't need to add it to xorg.conf.d)

Now I ran the following command: sudo setkeycodes [hexadecimal] [keycode], so in my case that became: setkeycodes e03e 199.

Now you can use the following line to test if it worked and/or you have the correct mapping:

xev | grep -A2 --line-buffered '^KeyRelease' | sed -n '/keycode /s/^.*keycode \([0-9]*\).* (.*, \(.*\)).*$/\1 \2/p'

When you run this command, you need to focus on the newly opened window (xev) and check the console output. In my case it read as following:

207 NoSymbol

This was obviously wrong, as I requested keycode 199, so it's mapped to XF86TouchpadToggle. I checked xmodmap -pke again, and noticed that keycode 207 is actually mapped to NoSymbol, and I noticed that there was an offset difference of 8, so I tried the setkeycodes command again, but the key is mapped to keycode 191.

sudo setkeycodes e03e 191

This worked perfectly.

EDIT -- the solution I provided to have to working on start up does not. I will figure this out tomorrow and update this answer. For now I suppose you can run this on start up manually.