Making all the Special Keys Work

(The first attempt)


Escape, Mute, Vol Down, Vol Up, Toggle Touchpad, Mic Mute, Webcam Toggle



MSI User[?], Keys Backlight, Dim Display, Brighter Display, Multi-Displays, Rotate Screen, Print Screen

Out of the box, when I installed Manjaro and made no changes, many but not all of these keys worked.  Escape, Volume control, Brightness all worked fine.  PRTSC brings up a screen capture utility.  The Multi-Displays key brings up a menu to control attached displays.  But the rest of the keys were a problem. 

The Short Answer

Let's jump straight to making them work.  Create the file /etc/udev/hwdb.d/60-keyboard.hwdb:

evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*Delta*:*
 KEYBOARD_KEY_76=f21
 KEYBOARD_KEY_8e=kbdillumtoggle
 KEYBOARD_KEY_f2=rotate_display
 KEYBOARD_KEY_f1=micmute
 KEYBOARD_KEY_91=screenlock
Note that the single space at the beginning of each "KEYBOARD_..." line is critical.

Now run "systemd-hwdb update" (may require a "sudo", my notes don't say).

And then run "udevadm trigger" (again, use sudo if this leads to an error).  Alternatively, just reboot.

At this point, all the keys should now be generating SOMETHING that can be recognized by higher-level interfaces and let you bind actions to them.  Some of these actions are picked up by default, i.e. I don't think I had to do anything at all to make the "MSI User Profile" key lock the display besides set that code.  I assigned it to "screenlock" and X11 recognizes "screenlock" as the appropriate X11 event, or KDE recognizes the lower level system event.  Other things will have to be manually bound, e.g. by the "Shortcuts" in the KDE Settings application.

The touchpad toggle key in particular (the one assigned "F21" above) is a strange key on this laptop that seems to generate control and alt modifiers no matter what you do.  So I went into the KDE Settings window, to the Shortcuts, then to Touchpad, and just added a binding and pressed that key.  It shows "Meta+Ctrl+Touchpad Toggle" as the shortcut I created, though all I did was press the single key.  I'm not going to sweat the details though since it does exactly what I want.

I haven't fixed the unfortunate default behavior of the webcam key.  It worked "out of the box" after a Manjaro install, but it seemed to work by unloading and reloading the kernel module that drives the webcam, and this is not a behavior that seems to play well with camera apps (like Zoom, for example).  It also works with no notification of whether you're toggling the camera off or on, which makes it somewhat useless.  But now... it's stopped working.  It was generating keycodes AND X11 events, but now it's doing neither and I'm not sure why.  And now I'm getting kernel errors in dmesg about it I wasn't getting before.

Also, the MicMute key is now generating keycodes but I can't get it to bind to anything. 

I'll describe the script I bound to the keyboard backlight button in a later posting (I have bindings to toggle it on and off, loop through a group of default settings, and raise and lower the brightness).

Likewise a script can be written to flip the display image upside down, and bind it to the rotate screen key.  That's just one possible usage.  But since the MSI Delta 15 display can lay flat, it may be useful to some when showing your display to people sitting across from you.

The Long Answer

For background read "Map scancodes to keycodes" and perhaps "Keyboard Input" on the Arch Wiki.  The nutshell is that hardware generates scancodes that the Linux kernel turns into keycodes.  And then X11 has its own keyboard map where it takes Linux keycodes, converts them to X11 keycodes (not the same), and in turn converts those to X11 keyboard events.

So some of these keyboards were generating scancodes, but Linux was not turning them into keycodes.  The file we create above fixes this problem.  I first got the codes from dmesg (run with sudo), which tells me things like this:

[500227.300561] atkbd serio0: Unknown key pressed (translated set 2, code 0xee on isa0060/serio0).
[500227.300572] atkbd serio0: Use 'setkeycodes e06e <keycode>' to make it known.
[500227.365051] atkbd serio0: Unknown key released (translated set 2, code 0xee on isa0060/serio0).
(That's actually the output for the webcam key now that it has disappeared from view.)

You can indeed use "setkeycodes" with the e0xx numbers to turn a scancode into a keycode without rebooting.  But it also doesn't survive a reboot.  For that the proper method is the udev file I created above.  Although initially, I tried to use these same e0xx values in udev and it didn't work.

Thanks to Manjaro Forums for helping me work through that issue.

So it turns out that even though setkeycodes understands those codes they need to be changed for udev.  Bascially the "e0" as reported on this system corresponds to the hi (8th) bit being set in the actual scancodes that udev looks at.  So "e00e" actually corresponds to "8e" in the udev code.  But rather than learning this obscure rule of thumb (which may vary in different systems), I'd suggest you just install evtest ("pacman -S evtest"), which generates proper missing scancodes live, and you can use those directly.

In a perfect world, if you pick the right Linux keycodes (which are defined in /usr/include/linux/input-event-codes.h) then X11 will notice them (only at startup, so if you've changed the keycodes, log out and log in again, at least) and assign them useful X11 events.  I think this happened when I assigned "screenlock" to that key, and it just started working in KDE.

Note that when using the keycode names from input-event-codes.h in the udev file (as I did above), drop the "KEY_" and make the rest lower case.

But you may have to make changes with xmodmap to get the events to come out the way you want them to.  I'm not doing that currently, and xmodmap is not the right way (I haven't actually figured out the "right" way yet, but I may not need to if everything can be assigned proper Linux keycodes).  I did fiddle with that in my initial testing.  I don't _think_ the X11 keycodes and Linux keycodes are necessarily the same but I think they tend to be.  So in one case I assigned an unused keycode to a key with setkeycodes, and then assigned that same keycode with xmodmap -pk to an X11 event, and it seemed to work.

If you do need to do this, you can get the X11 keysym names form /usr/include/X11/XF86keysym.h, though you'll need to drop the "XK" from the names.  So you'd have something like "xmodmap -e 'keycode 248 = XF86_AudioMicMute'".  But again, I'm hoping all of that can be avoided if we assign Linux keycodes in an intelligent way in udev.

As for the webcam key working, then not working, it may be a kernel update that I installed along the way, or it may be that the changes I made somehow broke it.  It may also be that when the webcam key was working, I had already made some changes which I failed to put in my notes and don't currently recall.

Ideally (once everything really is set properly) these udev changes can be added to the official linux kernel udev files and no such update will be needed (but I need to figure out how to submit changes first).

 

Comments

Popular posts from this blog

Why this laptop? Why this distro?

Welcome to the Center of the Universe for Linux on the MSI Delta 15