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..6831b71b1c4530d960cfb61104bc22de9e06f80c |
--- /dev/null |
+++ b/content/public/android/java/src/org/chromium/content/browser/input/GamepadDataMapper.java |
@@ -0,0 +1,205 @@ |
+// 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.view.KeyEvent; |
+import android.view.MotionEvent; |
+ |
+import org.chromium.base.JNINamespace; |
+import org.chromium.content.browser.input.gamepad_mapping.CanonicalAxisIndex; |
+import org.chromium.content.browser.input.gamepad_mapping.CanonicalButtonIndex; |
+ |
+import java.util.Arrays; |
+ |
+/** |
+ * 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"; |
+ protected static final String STANDARD_GAMEPAD_NAME = "(STANDARD_GAMEPAD)"; |
+ protected static final String STANDARD_MAPPING = "standard"; |
+ |
+ protected final WebGamepadData mData; |
+ |
+ public abstract WebGamepadData map(float[] axes, boolean[] buttons); |
+ |
+ // Factory method. |
+ public static GamepadDataMapper createDataMapper(String deviceName) { |
+ if (deviceName.equals(PS3_SIXAXIS_DEVICE_NAME)) |
+ return new PS3SixAxisGamepadDataMapper(); |
+ |
+ return new GenericGamepadDataMapper(deviceName); |
+ } |
+ |
+ protected GamepadDataMapper(String deviceName) { |
+ mData = new WebGamepadData(); |
+ mData.id = deviceName + " " + STANDARD_GAMEPAD_NAME; |
+ mData.mapping = STANDARD_MAPPING; |
+ mData.axes = new float[CanonicalAxisIndex.NUM_CANONICAL_AXES]; |
+ mData.buttons = new float[CanonicalButtonIndex.NUM_CANONICAL_BUTTONS]; |
+ } |
+ |
+ protected void clearAxesAndButtons() { |
+ Arrays.fill(mData.axes, 0); |
+ Arrays.fill(mData.buttons, 0); |
+ } |
+ |
+ // Most of the time we jut use 1 for pressed and 0 for not pressed. |
+ // Note that however some devices can represent some buttons of the standard gamepad |
+ // with analog values so we still want to store the button values as floats. |
+ // For example the Samsung EI-GP20 maps dpad to AXIS_HAT_X and AXIS_HAT_Y. |
+ protected float buttonValue(boolean pressed) { return pressed ? 1.0f : 0.0f; } |
+ |
+ protected void mapCommonXYAxes(float[] axes) { |
+ mData.axes[CanonicalAxisIndex.AXIS_LEFT_STICK_X] = axes[MotionEvent.AXIS_X]; |
+ mData.axes[CanonicalAxisIndex.AXIS_LEFT_STICK_Y] = axes[MotionEvent.AXIS_Y]; |
+ } |
+ |
+ protected void mapCommonTriggerAxes(float[] axes) { |
+ mData.buttons[CanonicalButtonIndex.BUTTON_LEFT_SHOULDER] = axes[MotionEvent.AXIS_LTRIGGER]; |
+ mData.buttons[CanonicalButtonIndex.BUTTON_RIGHT_SHOULDER] = axes[MotionEvent.AXIS_RTRIGGER]; |
+ } |
+ |
+ protected void mapCommonTriggerButtons(boolean[] buttons) { |
+ boolean l1 = buttons[KeyEvent.KEYCODE_BUTTON_L1]; |
+ boolean r1 = buttons[KeyEvent.KEYCODE_BUTTON_R1]; |
+ mData.buttons[CanonicalButtonIndex.BUTTON_LEFT_TRIGGER] = buttonValue(l1); |
+ mData.buttons[CanonicalButtonIndex.BUTTON_RIGHT_TRIGGER] = buttonValue(r1); |
+ } |
+ |
+ protected void mapCommonThumbstickButtons(boolean[] buttons) { |
+ boolean thumbL = buttons[KeyEvent.KEYCODE_BUTTON_THUMBL]; |
+ boolean thumbR = buttons[KeyEvent.KEYCODE_BUTTON_THUMBR]; |
+ mData.buttons[CanonicalButtonIndex.BUTTON_LEFT_THUMBSTICK] = buttonValue(thumbL); |
+ mData.buttons[CanonicalButtonIndex.BUTTON_RIGHT_THUMBSTICK] = buttonValue(thumbR); |
+ } |
+ |
+ protected void mapCommonStartSelectButtons(boolean[] buttons) { |
+ boolean select = buttons[KeyEvent.KEYCODE_BUTTON_SELECT]; |
+ boolean start = buttons[KeyEvent.KEYCODE_BUTTON_START]; |
+ mData.buttons[CanonicalButtonIndex.BUTTON_BACK_SELECT] = buttonValue(select); |
+ mData.buttons[CanonicalButtonIndex.BUTTON_START] = buttonValue(start); |
+ } |
+ |
+ protected void mapCommonDpadButtons(boolean[] buttons) { |
+ boolean dpadDown = buttons[KeyEvent.KEYCODE_DPAD_DOWN]; |
+ boolean dpadUp = buttons[KeyEvent.KEYCODE_DPAD_UP]; |
+ boolean dpadLeft = buttons[KeyEvent.KEYCODE_DPAD_LEFT]; |
+ boolean dpadRight = buttons[KeyEvent.KEYCODE_DPAD_RIGHT]; |
+ mData.buttons[CanonicalButtonIndex.BUTTON_DPAD_DOWN] = buttonValue(dpadDown); |
+ mData.buttons[CanonicalButtonIndex.BUTTON_DPAD_UP] = buttonValue(dpadUp); |
+ mData.buttons[CanonicalButtonIndex.BUTTON_DPAD_LEFT] = buttonValue(dpadLeft); |
+ mData.buttons[CanonicalButtonIndex.BUTTON_DPAD_RIGHT] = buttonValue(dpadRight); |
+ } |
+ |
+ protected void mapCommonXYABButtons(boolean[] buttons) { |
+ boolean bA = buttons[KeyEvent.KEYCODE_BUTTON_A]; |
+ boolean bB = buttons[KeyEvent.KEYCODE_BUTTON_B]; |
+ boolean bX = buttons[KeyEvent.KEYCODE_BUTTON_X]; |
+ boolean bY = buttons[KeyEvent.KEYCODE_BUTTON_Y]; |
+ mData.buttons[CanonicalButtonIndex.BUTTON_PRIMARY] = buttonValue(bA); |
+ mData.buttons[CanonicalButtonIndex.BUTTON_SECONDARY] = buttonValue(bB); |
+ mData.buttons[CanonicalButtonIndex.BUTTON_TERTIARY] = buttonValue(bX); |
+ mData.buttons[CanonicalButtonIndex.BUTTON_QUATERNARY] = 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) { |
+ super(deviceName); |
+ mDeviceName = deviceName; |
+ } |
+ |
+ // Find something for right stick x and y. |
+ private void mapRightSticks(float[] axes) { |
+ int position = CanonicalAxisIndex.AXIS_RIGHT_STICK_X; |
+ // position + 1 is AXIS_RIGHT_STICK_Y. |
+ assert mData.axes.length > position + 1; |
+ float x = axes[MotionEvent.AXIS_RX]; |
+ float y = axes[MotionEvent.AXIS_RY]; |
+ if (x != 0 || y != 0) { |
+ mData.axes[position++] = x; |
+ mData.axes[position] = y; |
+ return; |
+ } |
+ x = axes[MotionEvent.AXIS_Z]; |
+ y = axes[MotionEvent.AXIS_RZ]; |
+ if (x != 0 || y != 0) { |
+ mData.axes[position++] = x; |
+ mData.axes[position] = y; |
+ return; |
+ } |
+ x = axes[MotionEvent.AXIS_HAT_X]; |
+ y = axes[MotionEvent.AXIS_HAT_Y]; |
+ if (x != 0 || y != 0) { |
+ mData.axes[position++] = x; |
+ mData.axes[position] = y; |
+ } |
+ } |
+ |
+ public WebGamepadData map(float[] axes, boolean[] buttons) { |
+ clearAxesAndButtons(); |
+ |
+ mapCommonXYAxes(axes); |
+ mapRightSticks(axes); |
+ mapCommonTriggerAxes(axes); |
+ mapCommonXYABButtons(buttons); |
+ mapCommonTriggerButtons(buttons); |
+ mapCommonThumbstickButtons(buttons); |
+ mapCommonStartSelectButtons(buttons); |
+ mapCommonDpadButtons(buttons); |
+ |
+ // TODO(b.kelemen): meta is missing. |
+ |
+ return mData; |
+ } |
+} |
+ |
+class PS3SixAxisGamepadDataMapper extends GamepadDataMapper { |
+ PS3SixAxisGamepadDataMapper() { |
+ super(PS3_SIXAXIS_DEVICE_NAME); |
+ } |
+ |
+ public WebGamepadData map(float[] axes, boolean[] buttons) { |
+ clearAxesAndButtons(); |
+ |
+ mapCommonXYAxes(axes); |
+ |
+ mData.axes[CanonicalAxisIndex.AXIS_RIGHT_STICK_X] = axes[MotionEvent.AXIS_Z]; |
+ mData.axes[CanonicalAxisIndex.AXIS_RIGHT_STICK_Y] = axes[MotionEvent.AXIS_RZ]; |
+ |
+ mapCommonTriggerAxes(axes); |
+ |
+ boolean bA = buttons[KeyEvent.KEYCODE_BUTTON_A]; |
+ boolean bB = buttons[KeyEvent.KEYCODE_BUTTON_B]; |
+ boolean bX = buttons[KeyEvent.KEYCODE_BUTTON_X]; |
+ boolean bY = buttons[KeyEvent.KEYCODE_BUTTON_Y]; |
+ mData.buttons[CanonicalButtonIndex.BUTTON_PRIMARY] = buttonValue(bX); |
+ mData.buttons[CanonicalButtonIndex.BUTTON_SECONDARY] = buttonValue(bY); |
+ mData.buttons[CanonicalButtonIndex.BUTTON_TERTIARY] = buttonValue(bA); |
+ mData.buttons[CanonicalButtonIndex.BUTTON_QUATERNARY] = buttonValue(bB); |
+ |
+ mapCommonTriggerButtons(buttons); |
+ mapCommonThumbstickButtons(buttons); |
+ mapCommonStartSelectButtons(buttons); |
+ mapCommonDpadButtons(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 mData; |
+ } |
+} |
+ |
+// TODO(b.kelemen): add more implementations. It would be nice to support at least those that are |
+// supported on Linux. |