Xorg and special keys: one solution for keycode>255
An historic
I've buy an IR receiver, and an universal controller to control my multimedia computer, my TV, my ADSL box and my 2.1 Home cinema.
I've been pleased to see that my universal controller do now more control than the remote that was sold with my IR receiver. But a lot of those control didn't work with Xorg, so I had to find someway to use them.
At first, my logs where spamed with line like:
imon 4-4:1.0: imon_incoming_packet: unknown keypress, code 0x100000e
(imon is the real builder of the IR receiver).
I looked for this on the internet and found
- the problem was known
- the fix was in the Linus kernel git repository
- but not in any released kernel
So I waited, and Linux 3.10 was released, and the Debian Kernel Team did include it in debian sid, so I could easily use it.
But some command was still unrecognized as key by Xorg, so I had to find how to let X know them.
Reading documentation on internet, and trying some command lead nowhere: the kernel did in fact understood very well the command, but X did ignore them. After two day of trying to understood XKB, I found this bug: those key was unavailable to X and XKB because their keycode was bigger than 255.
The first solution to this problem is this patch, but I prefer to use standard tool. I finally found that udev can remap key, hence my solution:
The Solution
To use key that have keycode bigger than 255, you need to have keycode smaller than 255. keycode are determined by a map in the kernel, that udev can set when the receiver is plugged.
You need a keymap. input-kbd
from the input-utils
package will
list the available scancode, and their current keycode (to know the
number of your input device, use lsinput
):
% sudo input-kbd 6
0x100007f = 106 # KEY_RIGHT
0x1000080 = 105 # KEY_LEFT
0x1007f00 = 108 # KEY_DOWN
0x1008000 = 103 # KEY_UP
0x1010000 = 272 # BTN_LEFT
0x1010080 = 272 # BTN_LEFT
0x1020000 = 273 # BTN_RIGHT
0x1020080 = 273 # BTN_RIGHT
0x200001e = 513 # KEY_NUMERIC_1
0x200001f = 514 # KEY_NUMERIC_2
(There is more, I just cut it there).
Putting this in some file (say keymap
), editing it, and running
sudo input-kbd -f keymap 6
should change the kernel
mapping. But it don't.
It's not a problem, because the best solution is to use udev.
Wrote a keyboard mapping in say /etc/udev/imon
:
0x200001e KP1
0x200001f KP2
0x2000020 KP3
0x2000021 KP4
0x2000022 KP5
0x2000023 KP6
0x2000024 KP7
0x2000025 KP8
0x2000026 KP9
0x2000027 KP0
0x2800000 MENU
0x288795b7 PAGEDOWN
0x289395b7 PAGEUP
- You don't need to put there the scancode and keycode you don't divert,
- the interesting scancode are found by
input-kbd
- you can also use
input-events
to find which scancode correspond to one key - the interesting keycode are in
/usr/include/linux/input.h
, note that this is not the same thing than X keycode...
You then need to tell udev to load this mapping, with
/etc/udev/rules.d/96-local-keymap.rules
:
ACTION=="remove", GOTO="mykeyboard_end"
KERNEL!="event*", GOTO="mykeyboard_end"
ENV{ID_INPUT_KEY}=="", GOTO="mykeyboard_end"
SUBSYSTEMS=="bluetooth", GOTO="mykeyboard_end"
SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
ENV{ID_VENDOR}=="15c2", ENV{ID_MODEL_ID}=="0042", RUN+="keymap $name /etc/udev/imon"
LABEL="mykeyboard_end"
You will need to adapt 15c2
and 0042
to you own remote. I've found
those using lsusb
Bus 004 Device 014: ID 15c2:0042 SoundGraph Inc.
I could now use xkb to further refine the way those key are used by xorg...