PDA

View Full Version : Fix special keys and/or remap your keyboard



Skull One
7th February 2013, 12:45 PM
[Deprecated since FC20] See https://wiki.archlinux.org/index.php/Map_scancodes_to_keycodes

About this guide
The story starts with a friend buying a new laptop (a samsung).
He was happy that Fedora runs very well, but very disapointed by the behavior of the special keys (fn+fXX):
some of them did nothing, some put a mess (volume keys), and some others were missing. He (gently) asked me 'you said that linux can do everything, but what about that?'. Outch! After some investigations, I was able to fix the problem. So, I am writting this guide, as a memo, and to share the solution.

This guide will help you to get a fully functional keyboard.

A. Get all the keys to work

Unfortunately, some special keys don't return the 'release event'.
Once you have pressed them, the system acts like they are pressed permanently, which is very annoying.

1. Identify the faulty keys

Open a terminal, and type (in root mode):


showkey

Press a working key (a letter for instance): you will see two events, the 'pressed event' and the 'released event'.
Now, check all the special keys: if one does not report a 'release event', write it on a paper. You can exit the program using <ctrl>+C.

2. Get the code of the faulty keys

First, get the path of your keyboard. In a terminal, run the command:


/lib/udev/findkeyboards

On my system it reports 'AT keyboard: input/event3'; adapt the next command to what you have (in root mode):


/lib/udev/keymap -i input/event3

On my system, the output defiles permanently. It is annoying, but I can still see the relevant information. You can stop the program using <Esc>, and <Ctrl>+C.
Edit: run the command in a terminal session to have a 'static' output.
When you press a key, it produces something like:


scan code: 0xB3 key code: wlan

We only need the scan code (0xB3 in this example).
For all the faulty keys, write the corresponding scan code on a paper.

3. Force the release of the faulty keys
This is the easy part.
Create a file '/usr/lib/udev/keymaps/force-release/my_laptop', and write the scan codes of the faulty keys inside, one by line.
Look at the other files in the same directory if you are not sure.

Apply the changes with the command (adapt to your system):


/usr/lib/udev/keyboard-force-release.sh input/event3 my_laptop

Edit: the path here is not good here. Find the correct one (adapt the input):


# find /sys -type f -name event3
/sys/devices/platform/i8042/serio0/input/input3/event3

So, the correct command is (adapt to your system):


/usr/lib/udev/keyboard-force-release.sh devices/platform/i8042/serio0 my_laptop


It is done! The keys will now report a 'release event'.
To activate this at boot time, you can write an udev rule (see below) or add the command to the file /etc/rc.d/rc.local


B. Remap the keys to their correct key code

It is possible that some special keys are mapped to some funny key codes, or not mapped at all.
In the precedent section, we have seen how to get the scan code of a key.
For one of my special keys, I got the output:


scan code: 0xCE key code: kpplusminus

As you can see, the key code is here 'kpplusminus'. Very funny since the key is labelled with a configuration icon.

To fix this, open the file /usr/include/linux/input.h (it is provided by the package kernel-headers), and search for a key with an appropriate name. I have chosen 'KEY_CONFIG'.
To obtain the corresponding key code, suppress the prefix 'KEY_' and use lowercase: it is 'config' in this example.

Create a file '/usr/lib/udev/keymaps/my_laptop', and write the combination scancode keycode inside. In this example it is a line '0xCE config'.
Look at the other files in the same directory if you are not sure.

Apply the changes with the command (adapt to your system):


/usr/lib/udev/keymap input/event3 my_laptop


It is done! The key is now a 'config' key.
To activate this at boot time, you can write an udev rule (see below) or add the command to the file /etc/rc.d/rc.local


C. Remap keys for convenience

All your special keys are now working, but maybe you really miss some of them.
For instance, there is no 'sleep' key on this laptop, and the 'config' key is not really useful. So, we can remap it to become the indispensable 'sleep' key.
We just have to write '0xCE sleep' in the keymap file and rerun the keymap command.

Moreover, the 'sleep' key emits an acpi event when pressed. To see it, run in a terminal:


acpi_listen

and press the key. On my system, the output is
button/sleep SBTN 00000080 00000000
To handle this event (if it is not yet handled), create a file '/etc/acpi/events/sleepconf', and write inside (adapt to your output):


event=button/sleep SBTN 00000080
action=/usr/sbin/pm-suspend

Then, restart the acpi daemon:


systemctl restart acpid


It is done! You can now easily put you laptop into sleep.
As you have seen, it is really easy to remap your keyboard to what you want.


D. The keyboard is now fully functional, is there something else to do?

Contribute!
Read first /usr/share/doc/udev-*/README.keymap.txt, and send the required informations (see section 6 of the README).

E. udev rules

If you want your modifications enabled after reboot, you have to write udev rules or to update /etc/rc.d/rc.local.
First, get informations:


cat /sys/class/dmi/id/sys_vendor
cat /sys/class/dmi/id/product_name

On my system, the output is:
SAMSUNG ELECTRONICS CO., LTD.
and
350V5C/350V5X/350V4C/350V4X/351V5C/351V5X/351V4C/351V4X/3540VC/3540VX/3440VC/3440VX
First, look at the existing rules: '/usr/lib/udev/rules.d/95-keyboard-force-release.rules' and '/usr/lib/udev/rules.d/95-keymap.rules'

Then create a file: '/usr/lib/udev/rules.d/96-keyboard-force-release-addons.rules' and write inside (adapt the VENDOR and product_name to your system):


ACTION=="remove", GOTO="force_release_end"
SUBSYSTEM!="serio", GOTO="force_release_end"
KERNEL!="serio*", GOTO="force_release_end"
DRIVER!="atkbd", GOTO="force_release_end"

ENV{DMI_VENDOR}="$attr{[dmi/id]sys_vendor}"

ENV{DMI_VENDOR}=="SAMSUNG*", ATTR{[dmi/id]product_name}=="*350V5C*", RUN+="keyboard-force-release.sh $devpath my_laptop"

LABEL="force_release_end"


Then create a file: '/usr/lib/udev/rules.d/95-keymap-addons.rules' and write inside (adapt the VENDOR and product_name to your system):


ACTION=="remove", GOTO="keyboard_end"
KERNEL!="event*", GOTO="keyboard_end"
ENV{ID_INPUT_KEY}=="", GOTO="keyboard_end"
SUBSYSTEMS=="bluetooth", GOTO="keyboard_end"
SUBSYSTEMS=="usb", GOTO="keyboard_end"

ENV{DMI_VENDOR}="$attr{[dmi/id]sys_vendor}"
ENV{DMI_VENDOR}=="", GOTO="keyboard_end"

ENV{DMI_VENDOR}=="SAMSUNG*", ATTR{[dmi/id]product_name}=="*350V5C*", RUN+="keymap $name my_laptop"

LABEL="keyboard_end"


It is done!

JONOR
14th February 2013, 01:30 PM
Impressive looking guide Skull One !
It is something i want to be prepared for should remapping ever be needed.

For this part :


[root@lj ~]# /lib/udev/findkeyboards
USB keyboard: input/event5
USB keyboard: input/event2
USB keyboard: input/event3
USB keyboard: input/event16

The different event numbers were tried in the next step /lib/udev/keymap -i input/event ...
until the keyboard scan codes became apparent.

fedorabawks
11th April 2013, 11:22 PM
Do you know how to do it without a scancode? I have loads of keycodes but no scancodes.

Skull One
12th April 2013, 07:53 AM
You must have scancodes, since it is what the kernel get from the keyboard. See žA.2 to get them.
By the way, it is easier to read them using a terminal session (and not a terminal in a graphical session), since the output does not defile.

fedorabawks
12th April 2013, 11:00 AM
Thanks for your reply.

If I run /lib/udev/keymap -i input/eventX I get:



(no scan code received) key code: 136
(no scan code received) key code: 137
(no scan code received) key code: 139


What I'm trying to do is remap keycodes to others which X will read.

If I run evtest on the input device here are some of the buttons/keys I wish to reassign to some standard keys on a qwerty keyboard.



Event code 256 (BTN_0)
Event code 310 (BTN_TL)
Event code 311 (BTN_TR)
Event code 312 (BTN_TL2)
Event code 313 (BTN_TR2)
Event code 315 (BTN_START)
Event code 317 (BTN_THUMBL)
Event code 318 (BTN_THUMBR)

Skull One
12th April 2013, 11:40 AM
It means that the keys are not recognised by the kernel. Sadly, you prabably cannot do anything about it, it is a driver problem.
Does evtest report something when you press the keys?
Just to know, what is the keyboard model?

fedorabawks
12th April 2013, 11:45 AM
Why not? This is the output from evtest:



If I run evtest on the input device here are some of the buttons/keys I wish to reassign to some standard keys on a qwerty keyboard.



Event code 256 (BTN_0)
Event code 310 (BTN_TL)
Event code 311 (BTN_TR)
Event code 312 (BTN_TL2)
Event code 313 (BTN_TR2)
Event code 315 (BTN_START)
Event code 317 (BTN_THUMBL)
Event code 318 (BTN_THUMBR)

Skull One
12th April 2013, 12:13 PM
I do not have a similar device to make some tests, but if the kernel does not recognise the keys, it is done...
You have not answered the question: Does evtest report something when you press the keys? Normally, each time you press a key, it prints something.
But it looks weird for me to see a keycode without a scancode. Maybe you could try to play with xev and xmodmap?

fedorabawks
12th April 2013, 12:25 PM
Pardon for third time this is the output I get after running:

# sudo evtest /dev/input/event12



...
Event code 256 (BTN_0)
Event code 310 (BTN_TL)
Event code 311 (BTN_TR)
Event code 312 (BTN_TL2)
Event code 313 (BTN_TR2)
Event code 315 (BTN_START)
Event code 317 (BTN_THUMBL)
Event code 318 (BTN_THUMBR)
...


As does:

# showkey -k

generates the above keycodes when pressing buttons.

---------- Post added at 12:25 PM ---------- Previous post was at 12:19 PM ----------

The kernel is picking all keys as they are detected by showkeys -k.

xev and xmodmap will only deal with keys in Xorg's range. I can reassign these keys later. First I want to reassign those keys which are outside range to < 255.

Should be pretty elementary task.

Skull One
12th April 2013, 12:39 PM
Sorry, I was not clear: I did not asked for what evtest prints immediatly, but for what it prints after, when you press a key. Here a sample (after pressing shift)


Event: time 1365766118.348513, -------------- SYN_REPORT ------------
Event: time 1365766118.460408, type 4 (EV_MSC), code 4 (MSC_SCAN), value 2a
Event: time 1365766118.460408, type 1 (EV_KEY), code 42 (KEY_LEFTSHIFT), value 0
Event: time 1365766118.460408, -------------- SYN_REPORT ------------


Maybe the keycodes are outside range _because_ the kernel does not recognise the keys. In my understanding, it is a driver problem.
I do not have more clues. Please, post the keyboard model, in case someone has more information about it.

fedorabawks
12th April 2013, 12:46 PM
If we consider two of the above keys BTN_TL and BTN_TR, this is output:



Event: time 1365766863.282348, -------------- SYN_REPORT ------------
Event: time 1365766863.514358, type 1 (EV_KEY), code 310 (BTN_TL), value 0
Event: time 1365766863.514358, -------------- SYN_REPORT ------------
Event: time 1365766871.556217, type 1 (EV_KEY), code 311 (BTN_TR), value 1


I was mentioning keycodes are outside range of Xorg not kernel. Kernel obviously is recognising these keys. Kernel 3.8 and the device has no special driver for it other than uinput.

Skull One
12th April 2013, 01:20 PM
This is beyond my comprehension :(.
But you can make it works with a little hacking, see:
http://thisshouldnothappen.blogspot.fr/2010/05/getting-your-multimedia-keysremote.html
http://www.win.tue.nl/~aeb/linux/kbd/scancodes.html