Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 package org.chromium.content.browser.input; | |
| 6 | |
| 7 import android.util.Log; | |
| 8 import android.util.SparseArray; | |
| 9 import android.view.KeyEvent; | |
| 10 import android.view.MotionEvent; | |
| 11 | |
| 12 import org.chromium.base.JNINamespace; | |
| 13 | |
| 14 /** | |
| 15 * Device specific input data converter for Gamepad API. | |
| 16 * Implemented per device by subclasses. | |
| 17 */ | |
| 18 @JNINamespace("content") | |
| 19 abstract class GamepadDataMapper { | |
| 20 private static final String TAG = "GamepadDataMapper"; | |
| 21 | |
| 22 public abstract WebGamepadData map(SparseArray<Float> axes, SparseArray<Bool ean> buttons); | |
| 23 | |
| 24 // Factory method. | |
| 25 public static GamepadDataMapper createDataMapper(String id) { | |
| 26 if (id.equals("Sony PLAYSTATION(R)3 Controller")) { | |
| 27 return new PS3SixAxisGamepadDataMapper(); | |
| 28 } | |
| 29 | |
| 30 // TODO(b.kelemen): testing needed. This is probably not the right devic e name. | |
| 31 if (id.equals("Samsung Game pad EI-GP20")) { | |
| 32 return new SamsungEIGP20GamepadDataMapper(); | |
| 33 } | |
| 34 | |
| 35 Log.e(TAG, "Fallback to generic gamepad data mapper"); | |
| 36 return new GenericGamepadDataMapper(); | |
| 37 } | |
| 38 | |
| 39 // CanonicalButtonIndex and CanonicalAxisIndex mirror the same enums | |
| 40 // from C++ (in gamepad_standard_mappings.h). | |
| 41 | |
| 42 protected enum CanonicalButtonIndex { | |
| 43 BUTTON_PRIMARY, | |
| 44 BUTTON_SECONDARY, | |
| 45 BUTTON_TERTIARY, | |
| 46 BUTTON_QUATERNARY, | |
| 47 BUTTON_LEFT_SHOULDER, | |
| 48 BUTTON_RIGHT_SHOULDER, | |
| 49 BUTTON_LEFT_TRIGGER, | |
| 50 BUTTON_RIGHT_TRIGGER, | |
| 51 BUTTON_BACK_SELECT, | |
| 52 BUTTON_START, | |
| 53 BUTTON_LEFT_THUMBSTICK, | |
| 54 BUTTON_RIGHT_THUMBSTICK, | |
| 55 BUTTON_DPAD_UP, | |
| 56 BUTTON_DPAD_DOWN, | |
| 57 BUTTON_DPAD_LEFT, | |
| 58 BUTTON_DPAD_RIGHT, | |
| 59 BUTTON_META, | |
| 60 NUM_BUTTONS; | |
| 61 }; | |
| 62 | |
| 63 protected static final int NumberOfCanonicalButtons = | |
| 64 CanonicalButtonIndex.NUM_BUTTONS.ordinal(); | |
| 65 | |
| 66 protected enum CanonicalAxisIndex { | |
| 67 AXIS_LEFT_STICK_X, | |
| 68 AXIS_LEFT_STICK_Y, | |
| 69 AXIS_RIGHT_STICK_X, | |
| 70 AXIS_RIGHT_STICK_Y, | |
| 71 NUM_AXES | |
| 72 }; | |
| 73 | |
| 74 protected static final int NumberOfCanonicalAxes = | |
| 75 CanonicalAxisIndex.NUM_AXES.ordinal(); | |
| 76 | |
| 77 protected static float axisValue(Float f) { return f == null ? 0 : f.floatVa lue(); } | |
| 78 protected static float buttonValue(Boolean b) { return (b == null || !b) ? 0 : 1; } | |
| 79 | |
| 80 protected static WebGamepadData createWebGamepadData() { | |
| 81 WebGamepadData data = new WebGamepadData(); | |
| 82 data.axes = new float[NumberOfCanonicalAxes]; | |
| 83 data.buttons = new float[NumberOfCanonicalButtons]; | |
| 84 return data; | |
| 85 } | |
| 86 | |
| 87 protected static void mapCommonXYAxes(WebGamepadData data, SparseArray<Float > axes) { | |
| 88 Float x = (Float) axes.get(MotionEvent.AXIS_X); | |
| 89 Float y = (Float) axes.get(MotionEvent.AXIS_Y); | |
| 90 data.axes[CanonicalAxisIndex.AXIS_LEFT_STICK_X.ordinal()] = axisValue(x) ; | |
| 91 data.axes[CanonicalAxisIndex.AXIS_LEFT_STICK_Y.ordinal()] = axisValue(y) ; | |
| 92 } | |
| 93 | |
| 94 protected static void mapCommonTriggerAxes(WebGamepadData data, SparseArray< Float> axes) { | |
| 95 Float lTrigger = (Float) axes.get(MotionEvent.AXIS_LTRIGGER); | |
| 96 Float rTrigger = (Float) axes.get(MotionEvent.AXIS_RTRIGGER); | |
| 97 data.buttons[CanonicalButtonIndex.BUTTON_LEFT_SHOULDER.ordinal()] = axis Value(lTrigger); | |
| 98 data.buttons[CanonicalButtonIndex.BUTTON_RIGHT_SHOULDER.ordinal()] = axi sValue(rTrigger); | |
| 99 } | |
| 100 | |
| 101 protected static void mapCommonTriggerButtons( | |
| 102 WebGamepadData data, SparseArray<Boolean> buttons) { | |
| 103 Boolean l1 = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_L1); | |
| 104 Boolean r1 = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_R1); | |
| 105 data.buttons[CanonicalButtonIndex.BUTTON_LEFT_TRIGGER.ordinal()] = butto nValue(l1); | |
| 106 data.buttons[CanonicalButtonIndex.BUTTON_RIGHT_TRIGGER.ordinal()] = butt onValue(r1); | |
| 107 } | |
| 108 | |
| 109 protected static void mapCommonThumbstickButtons( | |
| 110 WebGamepadData data, SparseArray<Boolean> buttons) { | |
| 111 Boolean thumbL = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_THUMBL); | |
| 112 Boolean thumbR = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_THUMBR); | |
| 113 data.buttons[CanonicalButtonIndex.BUTTON_LEFT_THUMBSTICK.ordinal()] = bu ttonValue(thumbL); | |
| 114 data.buttons[CanonicalButtonIndex.BUTTON_RIGHT_THUMBSTICK.ordinal()] = b uttonValue(thumbR); | |
| 115 } | |
| 116 | |
| 117 protected static void mapCommonStartSelectButtons( | |
| 118 WebGamepadData data, SparseArray<Boolean> buttons) { | |
| 119 Boolean select = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_SELECT); | |
| 120 Boolean start = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_START); | |
| 121 data.buttons[CanonicalButtonIndex.BUTTON_BACK_SELECT.ordinal()] = button Value(select); | |
| 122 data.buttons[CanonicalButtonIndex.BUTTON_START.ordinal()] = buttonValue( start); | |
| 123 } | |
| 124 | |
| 125 protected static void mapCommonDpadButtons( | |
| 126 WebGamepadData data, SparseArray<Boolean> buttons) { | |
| 127 Boolean dpadDown = (Boolean) buttons.get(KeyEvent.KEYCODE_DPAD_DOWN); | |
| 128 Boolean dpadUp = (Boolean) buttons.get(KeyEvent.KEYCODE_DPAD_UP); | |
| 129 Boolean dpadLeft = (Boolean) buttons.get(KeyEvent.KEYCODE_DPAD_LEFT); | |
| 130 Boolean dpadRight = (Boolean) buttons.get(KeyEvent.KEYCODE_DPAD_RIGHT); | |
| 131 data.buttons[CanonicalButtonIndex.BUTTON_DPAD_DOWN.ordinal()] = buttonVa lue(dpadDown); | |
| 132 data.buttons[CanonicalButtonIndex.BUTTON_DPAD_UP.ordinal()] = buttonValu e(dpadUp); | |
| 133 data.buttons[CanonicalButtonIndex.BUTTON_DPAD_LEFT.ordinal()] = buttonVa lue(dpadLeft); | |
| 134 data.buttons[CanonicalButtonIndex.BUTTON_DPAD_RIGHT.ordinal()] = buttonV alue(dpadRight); | |
| 135 } | |
| 136 | |
| 137 protected static void mapCommonXYABButtons( | |
| 138 WebGamepadData data, SparseArray<Boolean> buttons) { | |
| 139 Boolean bA = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_A); | |
| 140 Boolean bB = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_B); | |
| 141 Boolean bX = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_X); | |
| 142 Boolean bY = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_Y); | |
| 143 data.buttons[CanonicalButtonIndex.BUTTON_PRIMARY.ordinal()] = buttonValu e(bA); | |
| 144 data.buttons[CanonicalButtonIndex.BUTTON_SECONDARY.ordinal()] = buttonVa lue(bB); | |
| 145 data.buttons[CanonicalButtonIndex.BUTTON_TERTIARY.ordinal()] = buttonVal ue(bX); | |
| 146 data.buttons[CanonicalButtonIndex.BUTTON_QUATERNARY.ordinal()] = buttonV alue(bY); | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 // This is a last resort if we find a device that we don't know about. | |
| 151 // The Android API is general enough that this can be better than nothing | |
| 152 // but we should not really rely on this. | |
| 153 class GenericGamepadDataMapper extends GamepadDataMapper { | |
| 154 // Find something for right stick x and y. If there is even more axes, map t hem to | |
| 155 // non-canonical positions. | |
| 156 private static void mapRightAndExtraSticks(WebGamepadData data, SparseArray< Float> axes) { | |
| 157 int position = CanonicalAxisIndex.AXIS_RIGHT_STICK_X.ordinal(); | |
| 158 // position + 1 is AXIS_RIGHT_STICK_Y. | |
| 159 Float x = (Float) axes.get(MotionEvent.AXIS_RX); | |
| 160 Float y = (Float) axes.get(MotionEvent.AXIS_RY); | |
| 161 if (x != null || y != null) { | |
| 162 data.axes[position++] = axisValue(x); | |
| 163 data.axes[position++] = axisValue(y); | |
| 164 } | |
| 165 x = (Float) axes.get(MotionEvent.AXIS_Z); | |
| 166 y = (Float) axes.get(MotionEvent.AXIS_RZ); | |
| 167 if (x != null || y != null) { | |
| 168 data.axes[position++] = axisValue(x); | |
| 169 data.axes[position++] = axisValue(y); | |
| 170 } | |
| 171 x = (Float) axes.get(MotionEvent.AXIS_HAT_X); | |
| 172 y = (Float) axes.get(MotionEvent.AXIS_HAT_Y); | |
| 173 if (x != null || y != null) { | |
| 174 data.axes[position++] = axisValue(x); | |
| 175 data.axes[position++] = axisValue(y); | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 public WebGamepadData map(SparseArray<Float> axes, SparseArray<Boolean> butt ons) { | |
| 180 WebGamepadData data = createWebGamepadData(); | |
| 181 | |
| 182 mapCommonXYAxes(data, axes); | |
| 183 mapRightAndExtraSticks(data, axes); | |
| 184 mapCommonTriggerAxes(data, axes); | |
| 185 mapCommonXYABButtons(data, buttons); | |
| 186 mapCommonTriggerButtons(data, buttons); | |
| 187 mapCommonThumbstickButtons(data, buttons); | |
| 188 mapCommonStartSelectButtons(data, buttons); | |
| 189 mapCommonDpadButtons(data, buttons); | |
| 190 | |
| 191 // TODO(b.kelemen): meta is missing. | |
| 192 | |
| 193 return data; | |
| 194 } | |
| 195 } | |
| 196 | |
| 197 class PS3SixAxisGamepadDataMapper extends GamepadDataMapper { | |
| 198 public WebGamepadData map(SparseArray<Float> axes, SparseArray<Boolean> butt ons) { | |
| 199 WebGamepadData data = createWebGamepadData(); | |
| 200 | |
| 201 mapCommonXYAxes(data, axes); | |
| 202 | |
| 203 Float z = (Float) axes.get(MotionEvent.AXIS_Z); | |
| 204 Float rz = (Float) axes.get(MotionEvent.AXIS_RZ); | |
| 205 data.axes[CanonicalAxisIndex.AXIS_RIGHT_STICK_X.ordinal()] = axisValue(z ); | |
| 206 data.axes[CanonicalAxisIndex.AXIS_RIGHT_STICK_Y.ordinal()] = axisValue(r z); | |
| 207 | |
| 208 mapCommonTriggerAxes(data, axes); | |
| 209 | |
| 210 Boolean bA = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_A); | |
| 211 Boolean bB = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_B); | |
| 212 Boolean bX = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_X); | |
| 213 Boolean bY = (Boolean) buttons.get(KeyEvent.KEYCODE_BUTTON_Y); | |
| 214 data.buttons[CanonicalButtonIndex.BUTTON_PRIMARY.ordinal()] = buttonValu e(bX); | |
| 215 data.buttons[CanonicalButtonIndex.BUTTON_SECONDARY.ordinal()] = buttonVa lue(bY); | |
| 216 data.buttons[CanonicalButtonIndex.BUTTON_TERTIARY.ordinal()] = buttonVal ue(bA); | |
| 217 data.buttons[CanonicalButtonIndex.BUTTON_QUATERNARY.ordinal()] = buttonV alue(bB); | |
| 218 | |
| 219 mapCommonTriggerButtons(data, buttons); | |
| 220 mapCommonThumbstickButtons(data, buttons); | |
| 221 mapCommonStartSelectButtons(data, buttons); | |
| 222 mapCommonDpadButtons(data, buttons); | |
| 223 | |
| 224 // TODO(b.kelemen): PS button is missing. Looks like it is swallowed by Android | |
| 225 // but probably there is a way to configure otherwise and in this case w e should | |
| 226 // handle it. | |
| 227 | |
| 228 return data; | |
| 229 } | |
| 230 } | |
| 231 | |
| 232 // DANGER! Not tested with device yet. | |
| 233 // Based on http://developer.samsung.com/mobile-console. | |
| 234 // TODO(b.kelemen): test. | |
| 235 class SamsungEIGP20GamepadDataMapper extends GamepadDataMapper { | |
|
bajones
2014/03/01 00:04:03
I would prefer to not add mappings that haven't be
| |
| 236 public WebGamepadData map(SparseArray<Float> axes, SparseArray<Boolean> butt ons) { | |
| 237 WebGamepadData data = createWebGamepadData(); | |
| 238 | |
| 239 mapCommonXYAxes(data, axes); | |
| 240 | |
| 241 Float rx = (Float) axes.get(MotionEvent.AXIS_RX); | |
| 242 Float ry = (Float) axes.get(MotionEvent.AXIS_RY); | |
| 243 data.axes[CanonicalAxisIndex.AXIS_RIGHT_STICK_X.ordinal()] = axisValue(r x); | |
| 244 data.axes[CanonicalAxisIndex.AXIS_RIGHT_STICK_Y.ordinal()] = axisValue(r y); | |
| 245 | |
| 246 Float hatX = (Float) axes.get(MotionEvent.AXIS_HAT_X); | |
| 247 Float hatY = (Float) axes.get(MotionEvent.AXIS_HAT_Y); | |
| 248 float hx = axisValue(hatX); | |
| 249 float hy = axisValue(hatY); | |
| 250 float dpadDown = 0, dpadUp = 0, dpadLeft = 0, dpadRight = 0; | |
| 251 if (hx < 0) dpadLeft = -hx; | |
| 252 else dpadRight = hx; | |
| 253 if (hy < 0) dpadUp = -hy; | |
| 254 else dpadDown = hy; | |
| 255 data.buttons[CanonicalButtonIndex.BUTTON_DPAD_DOWN.ordinal()] = dpadDown ; | |
| 256 data.buttons[CanonicalButtonIndex.BUTTON_DPAD_UP.ordinal()] = dpadUp; | |
| 257 data.buttons[CanonicalButtonIndex.BUTTON_DPAD_LEFT.ordinal()] = dpadLeft ; | |
| 258 data.buttons[CanonicalButtonIndex.BUTTON_DPAD_RIGHT.ordinal()] = dpadRig ht; | |
| 259 | |
| 260 mapCommonXYABButtons(data, buttons); | |
| 261 mapCommonStartSelectButtons(data, buttons); | |
| 262 mapCommonTriggerButtons(data, buttons); | |
| 263 | |
| 264 // TODO(b.kelemen): where is the game button? The documentation refers | |
| 265 // to KEYCODE_BUTTON_GAME but there is no such thing. | |
| 266 | |
| 267 return data; | |
| 268 } | |
| 269 } | |
| 270 | |
| 271 // TODO(b.kelemen): add more implementations. It would be nice to support at lea st those that are | |
| 272 // supported on Linux. | |
| OLD | NEW |