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..6089c2c60f6b21b3466941d5bfd9d8b6f5f7d695 |
--- /dev/null |
+++ b/content/public/android/java/src/org/chromium/content/browser/input/GamepadDataMapper.java |
@@ -0,0 +1,272 @@ |
+// 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.Log; |
+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 { |
+ private static final String TAG = "GamepadDataMapper"; |
+ |
+ public abstract WebGamepadData map(SparseArray<Float> axes, SparseArray<Boolean> buttons); |
+ |
+ // Factory method. |
+ public static GamepadDataMapper createDataMapper(String id) { |
+ if (id.equals("Sony PLAYSTATION(R)3 Controller")) { |
+ return new PS3SixAxisGamepadDataMapper(); |
+ } |
+ |
+ // TODO(b.kelemen): testing needed. This is probably not the right device name. |
+ if (id.equals("Samsung Game pad EI-GP20")) { |
+ return new SamsungEIGP20GamepadDataMapper(); |
+ } |
+ |
+ Log.e(TAG, "Fallback to generic gamepad data mapper"); |
+ return new GenericGamepadDataMapper(); |
+ } |
+ |
+ // CanonicalButtonIndex and CanonicalAxisIndex mirror the same enums |
+ // from C++ (in gamepad_standard_mappings.h). |
+ |
+ protected enum CanonicalButtonIndex { |
+ 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 { |
+ // 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(); |
+ |
+ 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(); |
+ |
+ 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; |
+ } |
+} |
+ |
+// DANGER! Not tested with device yet. |
+// Based on http://developer.samsung.com/mobile-console. |
+// TODO(b.kelemen): test. |
+class SamsungEIGP20GamepadDataMapper extends GamepadDataMapper { |
bajones
2014/03/01 00:04:03
I would prefer to not add mappings that haven't be
|
+ public WebGamepadData map(SparseArray<Float> axes, SparseArray<Boolean> buttons) { |
+ WebGamepadData data = createWebGamepadData(); |
+ |
+ mapCommonXYAxes(data, axes); |
+ |
+ Float rx = (Float) axes.get(MotionEvent.AXIS_RX); |
+ Float ry = (Float) axes.get(MotionEvent.AXIS_RY); |
+ data.axes[CanonicalAxisIndex.AXIS_RIGHT_STICK_X.ordinal()] = axisValue(rx); |
+ data.axes[CanonicalAxisIndex.AXIS_RIGHT_STICK_Y.ordinal()] = axisValue(ry); |
+ |
+ Float hatX = (Float) axes.get(MotionEvent.AXIS_HAT_X); |
+ Float hatY = (Float) axes.get(MotionEvent.AXIS_HAT_Y); |
+ float hx = axisValue(hatX); |
+ float hy = axisValue(hatY); |
+ float dpadDown = 0, dpadUp = 0, dpadLeft = 0, dpadRight = 0; |
+ if (hx < 0) dpadLeft = -hx; |
+ else dpadRight = hx; |
+ if (hy < 0) dpadUp = -hy; |
+ else dpadDown = hy; |
+ data.buttons[CanonicalButtonIndex.BUTTON_DPAD_DOWN.ordinal()] = dpadDown; |
+ data.buttons[CanonicalButtonIndex.BUTTON_DPAD_UP.ordinal()] = dpadUp; |
+ data.buttons[CanonicalButtonIndex.BUTTON_DPAD_LEFT.ordinal()] = dpadLeft; |
+ data.buttons[CanonicalButtonIndex.BUTTON_DPAD_RIGHT.ordinal()] = dpadRight; |
+ |
+ mapCommonXYABButtons(data, buttons); |
+ mapCommonStartSelectButtons(data, buttons); |
+ mapCommonTriggerButtons(data, buttons); |
+ |
+ // TODO(b.kelemen): where is the game button? The documentation refers |
+ // to KEYCODE_BUTTON_GAME but there is no such thing. |
+ |
+ return data; |
+ } |
+} |
+ |
+// TODO(b.kelemen): add more implementations. It would be nice to support at least those that are |
+// supported on Linux. |