Chromium Code Reviews| Index: content/public/android/java/src/org/chromium/content/browser/input/GamepadDataMapper.java |
| diff --git a/content/public/android/java/src/org/chromium/content/browser/input/GamepadDataMapper.java b/content/public/android/java/src/org/chromium/content/browser/input/GamepadDataMapper.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..cd3a863e7aff531249f716362569ad9660469f71 |
| --- /dev/null |
| +++ b/content/public/android/java/src/org/chromium/content/browser/input/GamepadDataMapper.java |
| @@ -0,0 +1,234 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +package org.chromium.content.browser.input; |
| + |
| +import android.util.SparseArray; |
| +import android.view.KeyEvent; |
| +import android.view.MotionEvent; |
| + |
| +import org.chromium.base.JNINamespace; |
| + |
| +/** |
| + * Device specific input data converter for Gamepad API. |
| + * Implemented per device by subclasses. |
| + */ |
| +@JNINamespace("content") |
| +abstract class GamepadDataMapper { |
| + protected static final String PS3_SIXAXIS_DEVICE_NAME = "Sony PLAYSTATION(R)3 Controller"; |
| + |
| + public abstract WebGamepadData map(SparseArray<Float> axes, SparseArray<Boolean> buttons); |
| + |
| + // Factory method. |
| + public static GamepadDataMapper createDataMapper(String deviceName) { |
| + if (deviceName.equals(PS3_SIXAXIS_DEVICE_NAME)) |
| + return new PS3SixAxisGamepadDataMapper(); |
| + |
| + return new GenericGamepadDataMapper(deviceName); |
| + } |
| + |
| + // CanonicalButtonIndex and CanonicalAxisIndex mirror the same enums |
| + // from C++ (in gamepad_standard_mappings.h). |
| + |
| + protected enum CanonicalButtonIndex { |
|
bulach
2014/03/05 12:34:39
enums are a no-go in android :(
http://developer.a
kbalazs
2014/03/05 19:56:11
Should I keep the naming scheme kButtonWhatever? I
|
| + BUTTON_PRIMARY, |
| + BUTTON_SECONDARY, |
| + BUTTON_TERTIARY, |
| + BUTTON_QUATERNARY, |
| + BUTTON_LEFT_SHOULDER, |
| + BUTTON_RIGHT_SHOULDER, |
| + BUTTON_LEFT_TRIGGER, |
| + BUTTON_RIGHT_TRIGGER, |
| + BUTTON_BACK_SELECT, |
| + BUTTON_START, |
| + BUTTON_LEFT_THUMBSTICK, |
| + BUTTON_RIGHT_THUMBSTICK, |
| + BUTTON_DPAD_UP, |
| + BUTTON_DPAD_DOWN, |
| + BUTTON_DPAD_LEFT, |
| + BUTTON_DPAD_RIGHT, |
| + BUTTON_META, |
| + NUM_BUTTONS; |
| + }; |
| + |
| + protected static final int NumberOfCanonicalButtons = |
| + CanonicalButtonIndex.NUM_BUTTONS.ordinal(); |
| + |
| + protected enum CanonicalAxisIndex { |
| + AXIS_LEFT_STICK_X, |
| + AXIS_LEFT_STICK_Y, |
| + AXIS_RIGHT_STICK_X, |
| + AXIS_RIGHT_STICK_Y, |
| + NUM_AXES |
| + }; |
| + |
| + protected static final int NumberOfCanonicalAxes = |
| + CanonicalAxisIndex.NUM_AXES.ordinal(); |
| + |
| + protected static float axisValue(Float f) { return f == null ? 0 : f.floatValue(); } |
| + protected static float buttonValue(Boolean b) { return (b == null || !b) ? 0 : 1; } |
| + |
| + protected static WebGamepadData createWebGamepadData() { |
| + WebGamepadData data = new WebGamepadData(); |
| + data.axes = new float[NumberOfCanonicalAxes]; |
| + data.buttons = new float[NumberOfCanonicalButtons]; |
| + return data; |
| + } |
| + |
| + protected static void mapCommonXYAxes(WebGamepadData data, SparseArray<Float> axes) { |
| + Float x = (Float) axes.get(MotionEvent.AXIS_X); |
| + Float y = (Float) axes.get(MotionEvent.AXIS_Y); |
| + data.axes[CanonicalAxisIndex.AXIS_LEFT_STICK_X.ordinal()] = axisValue(x); |
| + data.axes[CanonicalAxisIndex.AXIS_LEFT_STICK_Y.ordinal()] = axisValue(y); |
| + } |
| + |
| + protected static void mapCommonTriggerAxes(WebGamepadData data, SparseArray<Float> axes) { |
| + Float lTrigger = (Float) axes.get(MotionEvent.AXIS_LTRIGGER); |
| + Float rTrigger = (Float) axes.get(MotionEvent.AXIS_RTRIGGER); |
| + data.buttons[CanonicalButtonIndex.BUTTON_LEFT_SHOULDER.ordinal()] = axisValue(lTrigger); |
| + data.buttons[CanonicalButtonIndex.BUTTON_RIGHT_SHOULDER.ordinal()] = axisValue(rTrigger); |
| + } |
| + |
| + protected static void mapCommonTriggerButtons( |
| + WebGamepadData data, SparseArray<Boolean> buttons) { |
| + Boolean l1 = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_L1); |
| + Boolean r1 = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_R1); |
| + data.buttons[CanonicalButtonIndex.BUTTON_LEFT_TRIGGER.ordinal()] = buttonValue(l1); |
| + data.buttons[CanonicalButtonIndex.BUTTON_RIGHT_TRIGGER.ordinal()] = buttonValue(r1); |
| + } |
| + |
| + protected static void mapCommonThumbstickButtons( |
| + WebGamepadData data, SparseArray<Boolean> buttons) { |
| + Boolean thumbL = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_THUMBL); |
| + Boolean thumbR = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_THUMBR); |
| + data.buttons[CanonicalButtonIndex.BUTTON_LEFT_THUMBSTICK.ordinal()] = buttonValue(thumbL); |
| + data.buttons[CanonicalButtonIndex.BUTTON_RIGHT_THUMBSTICK.ordinal()] = buttonValue(thumbR); |
| + } |
| + |
| + protected static void mapCommonStartSelectButtons( |
| + WebGamepadData data, SparseArray<Boolean> buttons) { |
| + Boolean select = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_SELECT); |
| + Boolean start = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_START); |
| + data.buttons[CanonicalButtonIndex.BUTTON_BACK_SELECT.ordinal()] = buttonValue(select); |
| + data.buttons[CanonicalButtonIndex.BUTTON_START.ordinal()] = buttonValue(start); |
| + } |
| + |
| + protected static void mapCommonDpadButtons( |
| + WebGamepadData data, SparseArray<Boolean> buttons) { |
| + Boolean dpadDown = (Boolean) buttons.get(KeyEvent.KEYCODE_DPAD_DOWN); |
| + Boolean dpadUp = (Boolean) buttons.get(KeyEvent.KEYCODE_DPAD_UP); |
| + Boolean dpadLeft = (Boolean) buttons.get(KeyEvent.KEYCODE_DPAD_LEFT); |
| + Boolean dpadRight = (Boolean) buttons.get(KeyEvent.KEYCODE_DPAD_RIGHT); |
| + data.buttons[CanonicalButtonIndex.BUTTON_DPAD_DOWN.ordinal()] = buttonValue(dpadDown); |
| + data.buttons[CanonicalButtonIndex.BUTTON_DPAD_UP.ordinal()] = buttonValue(dpadUp); |
| + data.buttons[CanonicalButtonIndex.BUTTON_DPAD_LEFT.ordinal()] = buttonValue(dpadLeft); |
| + data.buttons[CanonicalButtonIndex.BUTTON_DPAD_RIGHT.ordinal()] = buttonValue(dpadRight); |
| + } |
| + |
| + protected static void mapCommonXYABButtons( |
| + WebGamepadData data, SparseArray<Boolean> buttons) { |
| + Boolean bA = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_A); |
| + Boolean bB = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_B); |
| + Boolean bX = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_X); |
| + Boolean bY = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_Y); |
| + data.buttons[CanonicalButtonIndex.BUTTON_PRIMARY.ordinal()] = buttonValue(bA); |
| + data.buttons[CanonicalButtonIndex.BUTTON_SECONDARY.ordinal()] = buttonValue(bB); |
| + data.buttons[CanonicalButtonIndex.BUTTON_TERTIARY.ordinal()] = buttonValue(bX); |
| + data.buttons[CanonicalButtonIndex.BUTTON_QUATERNARY.ordinal()] = buttonValue(bY); |
| + } |
| +} |
| + |
| +// This is a last resort if we find a device that we don't know about. |
| +// The Android API is general enough that this can be better than nothing |
| +// but we should not really rely on this. |
| +class GenericGamepadDataMapper extends GamepadDataMapper { |
| + private final String mDeviceName; |
| + |
| + GenericGamepadDataMapper(String deviceName) { |
| + mDeviceName = deviceName; |
| + } |
| + |
| + // Find something for right stick x and y. If there is even more axes, map them to |
| + // non-canonical positions. |
| + private static void mapRightAndExtraSticks(WebGamepadData data, SparseArray<Float> axes) { |
| + int position = CanonicalAxisIndex.AXIS_RIGHT_STICK_X.ordinal(); |
| + // position + 1 is AXIS_RIGHT_STICK_Y. |
| + Float x = (Float) axes.get(MotionEvent.AXIS_RX); |
| + Float y = (Float) axes.get(MotionEvent.AXIS_RY); |
| + if (x != null || y != null) { |
| + data.axes[position++] = axisValue(x); |
| + data.axes[position++] = axisValue(y); |
| + } |
| + x = (Float) axes.get(MotionEvent.AXIS_Z); |
| + y = (Float) axes.get(MotionEvent.AXIS_RZ); |
| + if (x != null || y != null) { |
| + data.axes[position++] = axisValue(x); |
| + data.axes[position++] = axisValue(y); |
| + } |
| + x = (Float) axes.get(MotionEvent.AXIS_HAT_X); |
| + y = (Float) axes.get(MotionEvent.AXIS_HAT_Y); |
| + if (x != null || y != null) { |
| + data.axes[position++] = axisValue(x); |
| + data.axes[position++] = axisValue(y); |
| + } |
| + } |
| + |
| + public WebGamepadData map(SparseArray<Float> axes, SparseArray<Boolean> buttons) { |
| + WebGamepadData data = createWebGamepadData(); |
| + data.id = mDeviceName + " (STANDARD_GAMEPAD)"; |
| + data.mapping = "standard"; |
| + mapCommonXYAxes(data, axes); |
| + mapRightAndExtraSticks(data, axes); |
| + mapCommonTriggerAxes(data, axes); |
| + mapCommonXYABButtons(data, buttons); |
| + mapCommonTriggerButtons(data, buttons); |
| + mapCommonThumbstickButtons(data, buttons); |
| + mapCommonStartSelectButtons(data, buttons); |
| + mapCommonDpadButtons(data, buttons); |
| + |
| + // TODO(b.kelemen): meta is missing. |
| + |
| + return data; |
| + } |
| +} |
| + |
| +class PS3SixAxisGamepadDataMapper extends GamepadDataMapper { |
| + public WebGamepadData map(SparseArray<Float> axes, SparseArray<Boolean> buttons) { |
| + WebGamepadData data = createWebGamepadData(); |
| + data.id = PS3_SIXAXIS_DEVICE_NAME + " (STANDARD_GAMEPAD)"; |
| + data.mapping = "standard"; |
| + |
| + mapCommonXYAxes(data, axes); |
| + |
| + Float z = (Float) axes.get(MotionEvent.AXIS_Z); |
| + Float rz = (Float) axes.get(MotionEvent.AXIS_RZ); |
| + data.axes[CanonicalAxisIndex.AXIS_RIGHT_STICK_X.ordinal()] = axisValue(z); |
| + data.axes[CanonicalAxisIndex.AXIS_RIGHT_STICK_Y.ordinal()] = axisValue(rz); |
| + |
| + mapCommonTriggerAxes(data, axes); |
| + |
| + Boolean bA = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_A); |
| + Boolean bB = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_B); |
| + Boolean bX = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_X); |
| + Boolean bY = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_Y); |
| + data.buttons[CanonicalButtonIndex.BUTTON_PRIMARY.ordinal()] = buttonValue(bX); |
| + data.buttons[CanonicalButtonIndex.BUTTON_SECONDARY.ordinal()] = buttonValue(bY); |
| + data.buttons[CanonicalButtonIndex.BUTTON_TERTIARY.ordinal()] = buttonValue(bA); |
| + data.buttons[CanonicalButtonIndex.BUTTON_QUATERNARY.ordinal()] = buttonValue(bB); |
| + |
| + mapCommonTriggerButtons(data, buttons); |
| + mapCommonThumbstickButtons(data, buttons); |
| + mapCommonStartSelectButtons(data, buttons); |
| + mapCommonDpadButtons(data, buttons); |
| + |
| + // TODO(b.kelemen): PS button is missing. Looks like it is swallowed by Android |
| + // but probably there is a way to configure otherwise and in this case we should |
| + // handle it. |
| + |
| + return data; |
| + } |
| +} |
| + |
| +// TODO(b.kelemen): add more implementations. It would be nice to support at least those that are |
| +// supported on Linux. |