Table of Contents

Using OsmAnd with a Remote Controller

OsmAnd paierd with a Bluetooth remote controller I'm an early joiner of the OpenStreetMap project, so I'm a big fan of the OsmAnd app. It is my preferred choice for motorbike on-board navigation.

A long-standing issue was the impossiblity to operate the map while wearing gloves. To be clear: panning and zooming on the Android touchscreen using gloves is impossibile. Here we explore the possibility to use a little Bluetooth remote controller to get at least the basic pan/zoom functions; in short: it could work!

The Mocute Universal Wireless Remote Controller

The Mocute Remote Controller

It is a low-cost (5-10 euros) Bluetooth device, sold under different brands. At present (Jan 2020) you can find it on Amazon or Aliexpress.com under the generic terms Android gamepad Bluetooth controller. It has an internal rechargeable battery which should last about 10 hours. The small size is quite convenient for using it on the handlebar of a motorbike, the biggest problem being to be not water-proof.

Low price (5-10 €).
Very small size.
No waterproof.
Cannot remap buttons: some presets available, but not user-configurable.
Auto stand-by if not operated for 15 minutes. Need to press start and wait 3 seconds to operate again.
Only 10 hours operating time per charge.
Non replaceable battery.

Once paired with the Android device, you can get some information using cat /proc/bus/input/devices:

I: Bus=0005 Vendor=ffff Product=0000 Version=0000
N: Name="MOCUTE-032_S23-AUTO"
P: Phys=
S: Sysfs=/devices/virtual/misc/uhid/0005:FFFF:0000.0001/input/input9
U: Uniq=E6:25:A1:48:F8:E0
H: Handlers=sysrq gpufreq_ib event9
B: PROP=0
B: EV=10001f
B: KEY=3f0003007f 0 0 483ffff17aff32d bf54444600000000 6fdb0000001f0001
   130f938b17c007 ffff7bfad9415fff febeffdfffefffff fffffffffffffffe
B: REL=143
B: ABS=100030627
B: MSC=10

Android ScanCodes and KeyCodes

Generally speaking, an Android input device generates a different hardware ScanCode when you press each different key. Using an appropriate keylayout file, each ScanCode is translated into an Android KeyCode, which is sent to the application. For example: the Mocute controller generates the ScanCode 114 when you press the A button, looking at /system/usr/keylayout/Generic.kl the scancode is translated into the mnemonic KEYCODE_VOLUME_DOWN (which in turn is the decimal value 25) and sent to the app. The app decides what to do with that key press.

Android Key Layouts

Many key layouts exists into an Android device, they are stored into the /system/usr/keylayout/ directory. The most important one is the Generic.kl file, which is applied if not specific case are found. This is an excerpt of the file:

...
key 10    9
key 11    0
key 12    MINUS
key 13    EQUALS
key 14    DEL
key 15    TAB
key 16    Q
key 17    W
key 18    E
...
key 113   VOLUME_MUTE
key 114   VOLUME_DOWN
key 115   VOLUME_UP
...

Mocute default key mapping

The Mocute-032 controller has a little slide switch with two positions: GAME and KEY. Each mode generates different ScanCodes for the four buttons. The joystick operates differently: in KEY mode it emulates four digital switches (keyboard keys which generate the ScanCode), while in GAME mode it operates as an analog joystick with two axis (without generating a ScanCode).

Key mapping in GAME mode

The joystick in GAME mode

In GAME mode, each axis position is reported as a floating point number ragining from -1.0 to 1.0, where the zero is at the central position. When the joystick is pushed near to one side, an Android KeyCode is generated. This means that beside the axes position, an appropriate KEYCODE_DPAD_UP, KEYCODE_DPAD_DOWN, KEYCODE_DPAD_LEFT or KEYCODE_DPAD_RIGHT is sent to the application. The Android app receives a KeyCode, but the device does not generate any ScanCode.

You can see joystick axes values with apps like Gamepad tester. You can see key events (ScanCodes and KeyCodes) with apps like KeyEvent Display.

KEY Mode GAME Mode
ScanCode Android key code ScanCode Android key code
UP 163 87 KEYCODE_MEDIA_NEXT AXIS Y 0x01 -0.8 19 KEYCODE_DPAD_UP
DOWN 165 88 KEYCODE_MEDIA_PREVIOUS AXIS Y 0x01 1.0 20 KEYCODE_DPAD_DOWN
LEFT 208 90 KEYCODE_MEDIA_FAST_FORWARD AXIS X 0x00 -1.0 21 KEYCODE_DPAD_LEFT
RIGHT 168 89 KEYCODE_MEDIA_REWIND AXIS X 0x00 0.8 22 KEYCODE_DPAD_RIGHT
A 114 25 KEYCODE_VOLUME_DOWN 304 96 KEYCODE_BUTTON_A
B 28 66 KEYCODE_ENTER 305 97 KEYCODE_BUTTON_B
X 115 24 KEYCODE_VOLUME_UP 307 99 KEYCODE_BUTTON_X
Y 158 4 KEYCODE_BACK 308 100 KEYCODE_BUTTON_Y

Connecting the external input device to OsmAnd

OsmAnd 3.5.5 supports some external input devices, to use the Mocute controller we need to enable the generic keyboard external input device; from the Menu button ⇒ Configure profile ⇒ General settings ⇒ External input devicesKeyboard.

At the moment OsmAnd recognized only a few KeyCodes:

Android KeyCode OsmAnd Action
KEYCODE_DPAD_RIGHT Scroll right
KEYCODE_DPAD_LEFT Scroll left
KEYCODE_DPAD_UP Scroll up
KEYCODE_DPAD_DOWN Scroll down
KEYCODE_PLUS Zoom in
KEYCODE_MINUS Zoom out

Remapping the controller keys (root required)

The GAME mode is somewhat working out-of-the-box, but with map scroll only. We want the following:

  1. Swap the X with the Y axis and invert the X. This is because we want to use the controller in vertical position.
  2. Associate the X button to zoom in, and Y button to zoom out.

In theory - to remap the functions of our controller - it should be possible to provide a specific keylayout file for just this controller: Android's instructions say to simply create a file with the name Vendor_ffff_Product_0000.kl (see the vendor and product read from the /proc/bus/input/devices pseudofile). Unfortunately this does not work, may be because ffff and 0000 are not valid ID values.

So we have to change the /system/usr/keylayout/Generic.kl file, redefining some ScanCodes and axis (the rest of the file must remain untouched):

key 304   MINUS
key 305   MINUS
key 307   PLUS
key 308   PLUS
axis 0x00 Y
axis 0x01 invert X

NOTICE: I have redefined scancodes 304 and 308 as duplicates of 305 and 307. This is because the default action for scancode 304 was BUTTON_A, which opens the Actions menu in OsmAnd 3.5.5; opening this menu by accident is very annoying because you can close it only using the touchscreen!

This change - unfortunately - have the side effect to remap all the external gamepads that we will connect to our Android device!

Key Mapping Test

Using the KeyEvent Display Android app, you can see what ScanCode and what associated Android key code is generated by each key pressed.

Using the Key Tester Android app, you can check what Android key code is received by the app when you press a key. So you can check if the key layout (mapping from ScanCode to Android KeyCode) is applied as expected.

Using the Gamepad tester Android app, you can see what joystick axis are associated with a gamepad, and the analogic values reported for each joystick position.

Other remote controllers

Web References