RM518 RF MCE remote control on Ubuntu Precise
#1
I have an RM518 RF MCE remote control, which is part of a combination with an RF wireless keyboard. They share the same receiver. I want to use this remote with XBMC.

The remote appears as 2 devices in /proc/bus/input/devices with the same name and differing physical addresses. The first delivers all the regular keyboard events from both keyboard and remote control, e.g., arrow buttons and backspace. The second delivers what I will call the media center key events and the trackball events. Media center keys are the yellow, green, etc, buttons, the TV, VCR etc buttons and the home key. I suspect these correspond with the eHome events I've read about in Windows.

I can view the events from both devices using evtest. Perfectly rational events are being delivered from both devices. such as KEY_YELLOW and KEY_HOME on the media center side and KEY_LEFT on the keyboard side.

The problem is that XBMC only sees the keyboard side events so half the buttons on the remote do nothing. Nothing appears in the XBMC log file when they are pressed and the X event viewer xev also shows nothing.

How can I get XBMC to see these buttons? I expect there is some way via keyboard.xml but despite hours of reading the remote control documentation I've been unable to find it. I suspect maybe adding a <remote device="" name=""> section to keyboard.xml might do it but the instructions on how to specify @Name or @device attributes are extremely scant: "cat /proc/bus/input/devices". But I have 2 with the same name. Here's the output:

I: Bus=0003 Vendor=1241 Product=f767 Version=0110
N: Name="HOLTEK Wireless 2.4GHz Trackball Keyboard"
P: Phys=usb-0000:00:1d.2-1/input0
S: Sysfs=/devices/pci0000:00/0000:00:1d.2/usb4/4-1/4-1:1.0/input/input3
U: Uniq=
H: Handlers=sysrq kbd event3
B: PROP=0
B: EV=120013
B: KEY=1000000000007 ff9f207ac14057ff febeffdfffefffff fffffffffffffffe
B: MSC=10
B: LED=7

I: Bus=0003 Vendor=1241 Product=f767 Version=0110
N: Name="HOLTEK Wireless 2.4GHz Trackball Keyboard"
P: Phys=usb-0000:00:1d.2-1/input1
S: Sysfs=/devices/pci0000:00/0000:00:1d.2/usb4/4-1/4-1:1.1/input/input4
U: Uniq=
H: Handlers=kbd mouse0 event4
B: PROP=0
B: EV=1f
B: KEY=4837fff072ff32d bf54444600000000 70001 20f908b17c000 677bfad941dfed 9ed6c000004400 10000002
B: REL=143
B: ABS=100000000
B: MSC=10

The second one, the one with kbd, mouse0 and event4 handlers is the one that delivers the media center events.

The remote control documentation is lacking a comprehensive overview that describes the event path from device to XBMC, all the mappings that are done and where they happen, or at least one that I could find. I am referring to mapping of scancodes to KEY_ codes then KEY_ codes to the key event names used by XBMC and then the event names to actions. Only the final mapping is shown in the most of the examples. A good overview would help put all of the other information into perspective.
Reply
#2
Took me a while to find it but this thread http://forum.xbmc.org/showthread.php?pid...#pid828171 may be useful.

Ps the names may be the same but other attributes like Phys are different.
If I have helped you or increased your knowledge, click the 'thumbs up' button to give thanks :) (People with less than 20 posts won't see the "thumbs up" button.)
Reply
#3
(2013-03-23, 23:48)nickr Wrote: Took me a while to find it but this thread http://forum.xbmc.org/showthread.php?pid...#pid828171 may be useful.

Thanks but I don't see how it helps. The bulk of it is talking about lirc and setting up the kernel to get events from the remote. The final part of it is about mapping XBMC event names to actions which is already fairly well documented elsewhere. My remote is (a) not IR and (b) evtest shows that the remote's scancodes are being converted to the correct KEY_ events so the kernel parts are already set up correctly. The above page says nothing about how KEY_ events are mapped to the XBMC event names (key1, etc.) nor how you get XBMC to open a new input device and map those KEY_ names to its own event names.

Quote:Ps the names may be the same but other attributes like Phys are different.
I can see that. A <remote> section within keymap.xml or another .xml file in userdata seems to be the place where KEY_ event names are mapped to XBMC event names. What is lacking is any documentation about the format of the @device or @Name attributes of said <remote> section so I do not now how to set it to make XBMC open the desired physical device. Since no events appear in the XBMC log, it is clearly not opening the device at present.

I think what is needed is to tell XBMC to open the middle one of the following items which appear in /dev/input/by-id. It already must have the 1st and 3rd open at it gets keyboard events and mouse (actually trackball) events from both the keyboard and the remote.

usb-HOLTEK_Wireless_2.4GHz_Trackball_Keyboard-event-kbd
usb-HOLTEK_Wireless_2.4GHz_Trackball_Keyboard-if01-event-mouse
usb-HOLTEK_Wireless_2.4GHz_Trackball_Keyboard-if01-mouse
Reply
#4
I finally figured out how to do this after much searching on the web and browsing source code. One of the issues that caused this to take so much time is the quantity of out-of-date documentation on the web. With that in mind, I can only guarantee that what follows is accurate for XBMC 12.2 (Frodo) running on Ubuntu Precise Pangolin (12.04 LTS). The part that seems to change most frequently is udev (see below).

The RF wireless RM518 is paired with a wireless keyboard and share a single RF USB dongle. Both have trackballs. They appear as 2 devices in /dev/input. One device receives all the keystrokes common to both keyboard and remote, such as arrow keys and keypad number keys. The other receives keystrokes that are unique to the remote and the move and mouse click events from both trackballs. Because of this it is not possible to use LIRC with this device. Giving LIRC the exclusive access to the 'file' in /dev/input that it needs would render the trackball useless for operating the system.

To help explain the issues in handling the keystrokes that are unique to the remote, it is necessary to understand all the layers involved in processing keystrokes between the device and XBMC. There are five. A complete description of all these layers is given in the last part of this article.

+------------------+
| kernel |
+------------------+
|
v
+------------------+
| udev |
+------------------+
|
v
+------------------+
| evdev / X Server |
+------------------+
|
v
+------------------+
| SDL |
+------------------+
|
v
+------------------+
| XBMC |
+------------------+

The primary issue with getting the unique RM518 buttons' keystrokes to XBMC and mapping them to commands is that udev generates key codes > 255 and the X server will not forward any codes > 255. The primary issue can be fixed by setting up a keymap file for udev that maps the scancodes to keycodes < 255. You then bump into a secondary issue, XBMC's mapping operates on key symbols, not codes, and neither SDL nor XBMC recognize the key symbols generated by the X server for most of the reasonable choices of key codes < 255. The way I fixed this issue is to select keycodes corresponding to known symbols either unused in the default mapping (only 'y') , already mapped to the commands I want or mapped to commands I don't need.

Place the following as the file holtek-keymap.rules in /etc/udev/rules.d to cause udev to load a custom mapping for the RM518.

Code:
# Load keymap for Holtek RM518 remote keycodes.
#
# Key map overrides can be specified by either giving scancode/keyname
# pairs directly as keymap arguments (if there are just one or two to change),
# or as a file name (in /lib/udev/keymaps).

ACTION=="remove", GOTO="holtek_end"
KERNEL!="event*", GOTO="holtek_end"
# The device with the keys we need to re-map has both KEY and MOUSE set.
# The device handling the standard keyboard keys has only KEY set.
ENV{ID_INPUT_KEY}=="", GOTO="holtek_end"
ENV{ID_INPUT_MOUSE}=="", GOTO="holtek_end"
SUBSYSTEM!="input", GOTO="holtek_end"

ENV{ID_VENDOR}=="HOLTEK", RUN+="keymap $name /etc/udev/keymaps/holtek_rm518_remote"

LABEL="holtek_end"

Place the following custom mapping in /etc/udev/keymaps/holtek_rm518_remote

Code:
# Remap RM518 remote control keys whose default keycodes have
# values > 255 and are, therefore, dropped by the X server's
# evdev driver and so are unseen by XBMC.
# h, k, e are standard XBMC keyboard mappings for the tv, vcr & program guide functions.
0xFFBC0046 y          # yellow 400
0xFFBC0047 apostrophe # green  399
0xFFBC0049 grave      # blue   401
0xFFBC004A equal      # red    398
0xFFBC0025 h          # tv     377
0xFFBC0048 k          # vcr    379
0x000C008D e          # program 362
#0xFFBC0024 menu      # menu 139 so ok

Here is the keyboard.xml I added to my XBMC profile. (~/.xbmc/userdata/keymaps/keyboard.xml).

Code:
<keymap>
  <!-- Key ids are the internal XBMC codes corresponding to the symbolic names of the
       keys so they aren't very useful. It would be much more useful for local command
       mapping if XBMC did not throw away an incoming key's "scancode" and instead
       allowed it to be used in command mapping with something like <key code="0xFOO"></key>.
  -->
  <global>
    <keyboard>
      <!-- Remap because it is a prominent button on the remote but the default mapping just makes XBMC
            select the first item on the currently displayed screen.  A bit useless. -->
      <home>XBMC.ActivateWindow(Home)</home>  <!-- MCE Home -->
      <!-- This code is sent by the close button (marked with x in a square). Unfortunately the Gnome desktop
             seems to sometimes use alf-F4 to open is find window. -->
      <f4 mod="alt">Close</f4>
      <quote>ActivateWindow(music)</quote>    <!-- MCE My music -->
      <leftquote>ActivateWindow(pictures)</leftquote><!-- MCE My picture -->
      <equals>ActivateWindow(video)</equals>    <!-- MCE My video -->
      <y>ActivateWindow(MyPVR)</y>    <!-- MCE My TV -->
    </keyboard>
  </global>
</keymap>

I'll add another post with the gory details.
Reply
#5
Here, as promised, are the gory details of keystroke handling and key mapping from kernel to XBMC

This is only known to be accurate for XBMC 12.2 (Frodo) on Ubuntu 12.04 LTS (Precise Pangolin). The part that has changed most frequently between releases is udev.

There are five levels where keystrokes are handled.

Code:
+------------------+
         |      kernel      |
         +------------------+
                  |
                  v
         +------------------+
         |       udev       |
         +------------------+
                  |
                  v
         +------------------+
         | evdev / X Server |
         +------------------+
                  |
                  v
         +------------------+
         |       SDL        |
         +------------------+
                  |
                  v
         +------------------+
         |       XBMC       |
         +------------------+

1. Keyboard scan codes to udev key codes
----------------------------------------

The kernel passes information about the device (in the case I was investigating, an RM518 wireless RF remote control) to udev from which udev sets up a node in /dev/input from which it then reads key events.

udev or the kernel has a database of known keyboards - apparently compiled in - which it uses to map scan codes to key codes. It produces perfectly reasonable codes for all the keys on the remote.

udev keycodes (KEY_FOO) are defined in /usr/include/linux/input.h

The easiest way to view scan and key codes is
Code:
sudo /lib/udev/keymap -i /dev/input/<device>
where <device> can be either "eventX" or "by-id/<name>". In the first case, replace X with the number of the device of interest. "evtest", see below, will show you a list of devices by name and number. For the RM518, pick the second "Holtek" device. Note that the numbers are likely to change across reboots. In the second case, for the RM518 remote <name> is
"usb-HOLTEK_Wireless_2.4GHz_Trackball_Keyboard-if01-event-mouse". This will not change across reboots. Scan codes and key codes are shown in the form needed in udev keymaps. I.e, keycodes are shown in symbolic form.

Key and scan codes can be also be viewed with "sudo evtest". For the RM518, pick the second Holtek device from the list. The scan code is displayed as the "value" entry in the MSC_SCAN (miscellaneous scan) event that is reported just before the key code of interest. The key code is shown using the KEY_FOO name from input.h and numerically. The value field of the key code event shows whether the key was pressed (1) or released (0).

The second "Holtek" device receives mouse events from both trackballs (keyboard and remote) and key events for the remote-only keys. These are the keys of interest.

The key mapping can be modified by:
  • a rule in /etc/udev/rules.d (the place for local rules like this, the main rules are in /lib/udev/rules.d). The rule can contain maps for a small number of keys or it can point to a keymap file. If the keymap file is not in /lib/udev/keymaps, (e.g. it is in /etc/udev/keymaps then the rule needs the full path of keymap file.

Note that in the udev keymaps KEY_FOO becomes "foo" so each line will be something like "0x02" foo

To test the keymap file
Code:
sudo /lib/udev/keymap input/event4 /etc/udev/keymaps/holtek_rm518_remote
It will make the specified mappings. Note the missing /dev. Have not tested to see if it will work with /dev.

To view the information needed to write a udev rule do
Code:
udevadm info --query=all --name=/dev/input/event4
Using the symlink in /dev/input/by-id does not work...

To test parsing of the udev rules
Code:
udevadm test /sys/devices/pci0000:00/0000:00:1d.2/usb4/4-1/4-1:1.1/input/input4/event4
This takes no action, just reports what it would do. The final parameter is the DEVPATH reported by the info command above, preceded by "/sys".


2. udev key codes to X evdev driver key codes
---------------------------------------------

The evdev driver is hardwired to add MINIMUM_KEYCODE (=8) to keycodes coming in from udev. There is no per-code mapping though a modified evdev with per-code mapping is available at http://www.thenautilus.net/SW/xf86-input-evdev/

So e.g., the udev keycode 130 (KEY_PROPS) is remapped to the X evdev code 138 which is known in the Xfree86world as keycode <PROPS>.

scancodes and keycodes can be viewed with "sudo showkey" except it does not show the codes for keys with codes > 255.

Issue is that the multimedia keys on the RM518 (the 8 keys that are unique to remote) have keycodes from udev > 255 so they must be remapped using a udev keymap. See my previous post in this thread for the file I am using.

3. X evdev key codes to X keysyms
---------------------------------
Key codes and keysyms can be viewed with xev.

X maps all the evdev key codes to keysyms. For example <PROPS> is mapped to the keysym SunProps.

Mapping can be modified using xmodmap as described below.

X keysyms are a sort of descriptive string like XF86AudioMedia, XF86WWW etc. but we can not use random names. A list of X keysyms can be found in the files /usr/lib/X11/XKeysymDB or /usr/share/X11/XKeysymDB

Then press a multimedia key. If you are lucky it already has a keysym bound to it, so the output of xev for that key will be something like this:

KeyRelease event, serial 36, synthetic NO, window 0x4000001,
root 0xab, subw 0x0, time 23936605, (-236,-203), rootSad865,338),
state 0x0, keycode 138 (keysym 0x1005ff70, SunProps), same_screen YES,
XLookupString gives 0 bytes:
XFilterEvent returns: False

The third row is the one of interest: it says that you have a keycode for that key (138) as well as keysym (SunProps). If you have a keysym then you can use that string to represent your key for purposes such as gnome keybindings or metacity keybindings but to use it with XBMC the keysym must be recognized by both SDL and XBMC. See below.

If you find that the key does not have any keysym assigned to it, like this:

KeyRelease event, serial 28, synthetic NO, window 0x3200001,
root 0xb7, subw 0x0, time 137355697, (401,146), rootSad413,264),
state 0x10, keycode 178 (keysym 0x0, NoSymbol), same_screen YES,
XLookupString gives 0 bytes:

you will have to assign a keysym to the relevant keycode (178). This is done with xmodmap.

First, create a file with your current X keyboard map, in a terminal type:
Code:
xmodmap -pke > xmodmap.conf
Then you are going to add all the missing keysyms to this file: use xev to see which keycode to use, look in the /usr/lib/X11/XKeysymDB or /usr/share/X11/XKeysymDB to find keysym names, open the xmodmap.conf file and fill in the missing keysym using a name which makes sense (i.e. if you have a button with a calculator printed on it, use XF86Calculator as keysym).

Repeat this passage for all your multimedia keys.

When finished, you can apply the changes with:
Code:
xmodmap xmodmap.conf
Now you want to load your new xmodmap.conf when X starts. Copy your xmodmap.conf file into ~/.xmodmap.

4. X keysyms to SDL keysyms
---------------------------
The mapping is hardwired in the code. Unrecognized X keysyms are set to an SDL keysym of 0. None of the X keysyms starting with XF86 is recognized so all are set to 0 in the SDL events.

All the code mentioned in the following is in src/video/X11/SDL_x11events.c in SDL 1.2.15.

Event dispatch is initiated by X11_PumpEvents which calls X11_DispatchEvent for each pending event. X11_DispatchEvent calls XNextEvent to get event from the X server. For key press events it essentially does the following (with some special handling for unicode affecting the .mod & .unicode fields).

Code:
keysym.scancode = keycode; // incoming X11 keycode
keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
keysym.mod = KMOD_NONE;
keysym.unicode = 0;
posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);

X11_TranslateKeycode, for key codes with upper 8 bits of 0x00 to 0x0D, masks off the upper 8 bits. For codes beginning 0xFE it uses the hardwired ODD_keymap and for codes beginnng 0xFF it uses MISC_keymap using the lower 8 bits to index the maps. For any keycode having other values in the upper 8 bits, besides a couple of SunXK keysyms having upper 8 bits of 0x1005FF, or for any keys not in the ODD or MISC keymaps SDLK_UNKNOWN (0) is returned.

The keymaps are initialized in X11_InitKeymap but it is all hard-coded. No environment variables or files are read.

XF86* symbols have key codes beginning 0x1008FF so all of these get converted to SDLK_UKNOWN.

Note how the X key code is now referred to as a scan code, even though it is no such thing.

SDL_PrivateKeyboard (found in src/events/SD_keyboard.c) figures out the current modifier state from the global state modified by any modifier key (shift, etc.) in the passed in keysym->sym and sets keysym->mod to the new value. It then creates an SDL_Event "event" with:

Code:
// parameters to the function are state and keysym.
event.type = state == SDL_PRESSED ? SDL_KEYDOWN : SDL_KEYUP;
event.key.state = state;
event.key.keysym = *keysym;

and pushes this SDL_Event to the SDL client, i.e., XBMC.

5. SDL keysyms to XBMC actions
------------------------------

Starts in xbmc/windowing/WinEventsSDL.cpp CWinEventsSDL::MessagePump.

For keydown:

The incoming SDL_Event is converted to an almost identical XBMC_Event
  • the key.keysym.sym field has the struct type XBMCKey but is otherwise identical to the SDL_Event's.

On linux if key.keysym.sym is 0 XBMC attempts to set sym from a pair of small hardwired tables, SymMappingsEvDev and SymMappingsUbuntu. The former is used when X Windows/evdev is the source of the events. This is my case. If the key.keysym.scancode is not found in these tables sym remains 0.

MessagePump Calls CApplication::OnEvent in xbmc/Application.cpp

CApplicationOnEvent
  • calls CKeyboard:TonguerocessKeyDown passing it the key.keysym field from the incoming XBMC_Event; this returns a CKey.
  • calls CApplication:OnKey with the returned CKey.

CKeyboard:TonguerocessKeyDown (xbmc/input/KeyboardStat.cpp)
  • converts keysym.mod values to a modifiers variable using CKeys:: values
  • Logs "Keyboard: scancode: 0x%02x, sym: 0x%04x, unicode: 0x%04x, modifier: 0x%x" when in debug mode.
  • Attempts to convert the keysym.sym to an XBMC vkey value. If keysym.sym is 0 or unrecognized, vkey is set to 0xF200.

Note that the scancode in the incoming event is NOT included in the returned CKey.

CApplication::OnKey(const CKey& key)
  • calls CButtonTranslator::GetInstance().GetAction(iWin, key). iWin is the active window.
    • uses CKey.GetButtonCode() as the code to match in the translator maps created from the keyboard.xml files.

CKey is in xbmc/guilib/Key.cpp
  • the "button code" is either "vkey | KEY_VKEY | modifiers" or "KEY_UNICODE".

In other words it is the XBMC code for the key so <key id=""> in the keyboard.xml file is fairly useless. You have to plow through the XBMC source
to find the code for any key of interest.

It would be much more interesting if the scancode was included in CKey and a keymap.xml file could include something like

Code:
<key code="0x0F00">command</key>

Yes its not portable but local keyboard.xml files don't need to be portable. If this was done one would not need to worry about SDL and XBMC dropping unrecognized key symbols. You could get the key code from xev and have keyboard.xml map that to a command.

As noted, neither SDL nor XBMC recognize any X symbols names beginning XF86… and there are quite a few of those that would be useful with remote controls.

(2013-03-23, 16:02)msfc Wrote: I suspect maybe adding a <remote device="" name=""> section to keyboard.xml might do it but the instructions on how to specify @Name or @device attributes are extremely scant: "cat /proc/bus/input/devices".
As I have now learned from my code study, the code that processes incoming keyboard events uses only the map built from a <keyboard> section of a keymap. It pays no attention to <remote device=""name""> sections.
Reply
#6
This thread was very helpful in getting my RF remote working. My AHA moment came when I realized a keyboard has twelve function keys (F1-F12) which are not present in a remote!! I have documented the same here http://lifeofpenguin.blogspot.in/2016/01...-htpc.html

EDIT (18/01/16): I tested this on OSMC (Rpi1 model B) and aptosid 4.3.0-3.slh.2-aptosid-amd64
Reply
#7
@atamariya, I am glad the thread was helpful.

@Others, the mapping of udev keyocdes works completely differently in Ubuntu 14.04 and beyond. Following the limited info available shortly after the release of 14.04 I was unable to get the mapping working thus my remote was broken again following the update. I have now replaced my HTPC hardware so will not be doing any further work on this.
Reply

Logout Mark Read Team Forum Stats Members Help
RM518 RF MCE remote control on Ubuntu Precise0