OUYA controller on an Android phone

I wanted to use an OUYA controller gamepad to control my Parrot Bebop drone - Parrot says it is possible . For that I had to make the controller work on a standard Android 6 phone, my Wileyfox Swift with Cyanogenmod 13.1.

I used the Gamepad Tester app from the Google play store to see how the buttons are mapped, and the standard mapping was awful.

I knew from my USB-Joysticks-on-OUYA adventure that the controller key mappings happen in key layout files. So I took the original Vendor_2836_Product_0001.kl from my OUYA and installed it onto the phone:

$ adb push Vendor_2836_Product_0001.kl /sdcard/
$ adb shell
$ su
$ mount -o remount,rw /system
$ mv /sdcard/Vendor_2836_Product_0001.kl /system/usr/keylayout/

Disconnecting and repairing the controller did not help, and adb logcat told me why:

I InputReader: Device added: id=18, name='OUYA Game Controller', sources=0x01000511
E KeyLayoutMap: /system/usr/keylayout/Vendor_2836_Product_0001.kl:41: Expected key flag label, got 'ALT'.

So the key layout format used on the OUYA seems to bedifferent from standard Android. I fixed it:

--- Vendor_2836_Product_0001.kl  2015-10-05 20:42:48.044701138 +0200
+++ Vendor_2836_Product_0001.kl  2016-03-18 21:16:12.035450036 +0100
@@ -38,7 +38,7 @@
 # Power and Home Key
 key 0x13e    HOME      #Short Press
-key 0x13f    HOME ALT  #Long Press
+key 0x13f    MENU  #Long Press
 # Left (0x00, 0x01) and right (0x03, 0x04) analog control stick.
 # The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.

After pushing that onto the phone, it got loaded fine:

I EventHub: New device: id=19, fd=161, path='/dev/input/event13',
 name='OUYA Game Controller', classes=0x80000141, configuration='',
 builtinKeyboard=false, wakeMechanism=EPOLLWAKEUP, usingClockIoctl=true

GamepadTest also showed that the mapping was fine.

FreeFlight 3

Then I started the Bebop drone and its FreeFlight 3 app, version 3.8.15. The app detected the bluetooth controller (OSD controls were gone), but nearly nothing worked:

Taking off and landing
Digital pad (DPAD) keys
Navigate the OSD buttons
Left and right thumb stick press
Activate the selected OSD button

That's all. Navigating the quadcopter with the thumb sticks did not work, and the shoulder buttons (R1, R2, L1, L2) did also not do anything.


I decompiled the Freeflight3 files and looked at the input configuration. There is SkyControllerInputDeviceState and GamePadInputDeviceState. Since I don't own a Sky Controller, I thought the gamepad input would be the right one. That one has the following input handling code:

this.leftJoystickX = getCenteredAxis(paramMotionEvent, 0);
this.leftJoystickY = getCenteredAxis(paramMotionEvent, 1);
this.rightJoystickX = getCenteredAxis(paramMotionEvent, 11);
if (this.rightJoystickX == 0.0F) {
    this.rightJoystickX = getCenteredAxis(paramMotionEvent, 12);
this.rightJoystickY = getCenteredAxis(paramMotionEvent, 14);
if (this.rightJoystickY == 0.0F) {
    this.rightJoystickY = getCenteredAxis(paramMotionEvent, 13);

The numbers did not get decompiled to the constants that were originally used, so I had to look them up in the Android source code at android/view/MotionEvent.java:

left joystick:
 0 - AXIS_X
 1 - AXIS_Y

right joystick:
 11 - AXIS_Z
 12 - AXIS_RX

 14 - AXIS_RZ
 13 - AXIS_RY

I had the hope that I could change my controller's input mapping to match Freeflight's expectations, but it turns out that OUYA controller is already mapped that way:

axis 0x00 X flat 4096
axis 0x01 Y flat 4096
axis 0x03 Z flat 4096
axis 0x04 RZ flat 4096

Neither jd-gui 1.4.0 nor jadx-gui 0.6.1 are able to show the java code for com.parrot.freeflight3.menusmanager.MainARActivity because they don't support some smali features used there. That class seems to be responsible for setting up the controller, so there might be information in it that could help me. But reading 16k lines of .smali isn't something I want to do this year.

I'm stuck here.

Written by Christian Weiske.

Comments? Please send an e-mail.