Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions | |
| 6 * are met: | |
| 7 * * Redistributions of source code must retain the above copyright | |
| 8 * notice, this list of conditions and the following disclaimer. | |
| 9 * * Redistributions in binary form must reproduce the above copyright | |
| 10 * notice, this list of conditions and the following disclaimer in the | |
| 11 * documentation and/or other materials provided with the distribution. | |
| 12 * * Neither the name of NVIDIA CORPORATION nor the names of its | |
| 13 * contributors may be used to endorse or promote products derived | |
| 14 * from this software without specific prior written permission. | |
| 15 * | |
| 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY | |
| 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
| 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |
| 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| 23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
| 24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 27 */ | |
| 28 | |
| 29 package org.chromium.content.browser; | |
| 30 | |
| 31 import android.os.SystemClock; | |
| 32 import android.view.InputDevice; | |
| 33 import android.view.InputDevice.MotionRange; | |
| 34 import android.view.KeyCharacterMap; | |
| 35 import android.view.KeyEvent; | |
| 36 import android.view.MotionEvent; | |
| 37 | |
| 38 import java.util.Iterator; | |
| 39 import java.util.LinkedHashMap; | |
| 40 | |
| 41 /* | |
| 42 * Class to manage information related to each connected gamepad device. | |
| 43 */ | |
| 44 | |
| 45 class GamepadDevice { | |
| 46 // An id for the gamepad. | |
| 47 protected int mDeviceId; | |
| 48 // The index of the gamepad in the Navigator. | |
| 49 protected int mDeviceIndex; | |
| 50 // An identification string for the gamepad. | |
| 51 protected String mDeviceName; | |
| 52 // Last time the data for this gamepad was updated. | |
| 53 protected long mTimestamp; | |
| 54 | |
| 55 // Array of values for all axes of the gamepad. | |
| 56 // All axis values must be linearly normalized to the range [-1.0 .. 1.0]. | |
| 57 // As appropriate, -1.0 should correspond to "up" or "left", and 1.0 | |
| 58 // should correspond to "down" or "right". | |
| 59 protected float[] mAxisValues; | |
| 60 // Array of axes ids. | |
| 61 private int[] mAxes; | |
| 62 | |
| 63 // List of keycodes that can be sent by a standard gamepad. Standard gamepad can have | |
| 64 // buttons as per the spec: | |
| 65 // https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#remapping | |
| 66 // Need to maintain this list to get input device capabilities. We query | |
| 67 // input devices with this list and device returns list mentioning which | |
| 68 // Keycodes out of these can be sent by a gamepad device. | |
| 69 private static final int[] standardGamepadKeyCodes = { | |
| 70 KeyEvent.KEYCODE_BUTTON_A, // Button 0 | |
| 71 KeyEvent.KEYCODE_BUTTON_B, // Button 1 | |
| 72 KeyEvent.KEYCODE_BUTTON_X, // Button 2 | |
| 73 KeyEvent.KEYCODE_BUTTON_Y, // Button 3 | |
| 74 KeyEvent.KEYCODE_BUTTON_L1, // Button 4 | |
| 75 KeyEvent.KEYCODE_BUTTON_R1, // Button 5 | |
| 76 KeyEvent.KEYCODE_BUTTON_L2, // Button 6 | |
| 77 KeyEvent.KEYCODE_BUTTON_R2, // Button 7 | |
| 78 KeyEvent.KEYCODE_BUTTON_SELECT, // Button 8 | |
| 79 KeyEvent.KEYCODE_BUTTON_START, // Button 9 | |
| 80 KeyEvent.KEYCODE_BUTTON_THUMBL, // Button 10 | |
| 81 KeyEvent.KEYCODE_BUTTON_THUMBR, // Button 11 | |
| 82 KeyEvent.KEYCODE_DPAD_UP, // Button 12 | |
| 83 KeyEvent.KEYCODE_DPAD_DOWN, // Button 13 | |
| 84 KeyEvent.KEYCODE_DPAD_LEFT, // Button 14 | |
| 85 KeyEvent.KEYCODE_DPAD_RIGHT, // Button 15 | |
| 86 KeyEvent.KEYCODE_BUTTON_MODE, // Button 16?? | |
| 87 }; | |
| 88 | |
| 89 // Standard gamepad buttons. | |
| 90 private static class StandardButtons { | |
| 91 public static final int BUTTON_A = 0; | |
| 92 public static final int BUTTON_B = 1; | |
| 93 public static final int BUTTON_X = 2; | |
| 94 public static final int BUTTON_Y = 3; | |
| 95 public static final int LEFT_TRIGGER = 4; | |
| 96 public static final int RIGHT_TRIGGER = 5; | |
| 97 public static final int BOTTOM_LEFT_TRIGGER = 6; | |
| 98 public static final int BOTTOM_RIGHT_TRIGGER = 7; | |
| 99 public static final int SELECT = 8; | |
| 100 public static final int START = 9; | |
| 101 public static final int LEFT_THUMB = 10; | |
| 102 public static final int RIGHT_THUMB = 11; | |
| 103 public static final int DPAD_UP = 12; | |
| 104 public static final int DPAD_DOWN = 13; | |
| 105 public static final int DPAD_LEFT = 14; | |
| 106 public static final int DPAD_RIGHT = 15; | |
| 107 public static final int MODE = 16; | |
| 108 public static final int MAX_BUTTONS = 17; | |
| 109 } | |
| 110 | |
| 111 // Standard gamepad axes. | |
| 112 private static class StandardAxes { | |
| 113 public static final int AXIS_0 = 0; | |
| 114 public static final int AXIS_1 = 1; | |
| 115 public static final int AXIS_2 = 2; | |
| 116 public static final int AXIS_3 = 3; | |
| 117 public static final int MAX_AXES = 4; | |
| 118 } | |
| 119 | |
| 120 // We guess the gamepad inputDevice type from its name and then map it to th e | |
| 121 // standard gamepad if it is one of the known gamepads. | |
| 122 protected enum GamepadType { | |
| 123 Shield, | |
| 124 XBox360, | |
| 125 Unknown | |
| 126 } | |
| 127 protected GamepadType mGamepadType; | |
| 128 | |
| 129 // Following values should be changed if the gamepad layout changes | |
|
xwang
2014/01/14 03:03:22
Will it better to separate the device specific stu
SaurabhK
2014/01/15 16:57:08
Will add another class in next patch set.
| |
| 130 // or frameworks exposes different axes / buttons for a particular gamepad. | |
| 131 // mRawShieldAxes is the total raw axes on known shield gamepad. | |
| 132 private static final int mRawShieldAxes = 10; | |
| 133 // mRawShieldButtons is the total raw buttons on known shield gamepad. | |
| 134 private static final int mRawShieldButtons = 10; | |
| 135 // mRawXBoxAxes is the total raw axes on known XBox gamepad. | |
| 136 private static final int mRawXBoxAxes = 10; | |
| 137 // mRawXBoxButtons is the total raw buttons on known XBox gamepad. | |
| 138 private static final int mRawXBoxButtons = 9; | |
| 139 | |
| 140 // Hash map of supported keycodes and their current value linearly | |
| 141 // normalized to the range [0.0 .. 1.0]. | |
| 142 // 0.0 must mean fully unpressed, and 1.0 must mean fully pressed. | |
| 143 protected LinkedHashMap<Integer, Float> mKeyCodeValueMap = new LinkedHashMap <Integer, Float>(); | |
| 144 | |
| 145 GamepadDevice(int index, InputDevice inputDevice) { | |
| 146 mDeviceIndex = index; | |
| 147 mDeviceId = inputDevice.getId(); | |
| 148 mDeviceName = inputDevice.getName(); | |
| 149 mTimestamp = SystemClock.uptimeMillis(); | |
| 150 // Get the total number of axes supported by gamepad. | |
| 151 int totalAxes = 0; | |
| 152 for (MotionRange range : inputDevice.getMotionRanges()) { | |
| 153 if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { | |
| 154 totalAxes++; | |
| 155 } | |
| 156 } | |
| 157 // Get axis ids and initialize axes values. | |
| 158 mAxes = new int[totalAxes]; | |
| 159 mAxisValues = new float[totalAxes]; | |
| 160 int i = 0; | |
| 161 for (MotionRange range : inputDevice.getMotionRanges()) { | |
| 162 if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { | |
| 163 mAxes[i] = range.getAxis(); | |
| 164 mAxisValues[i] = 0.0f; | |
| 165 i++; | |
| 166 } | |
| 167 } | |
| 168 // Update supported buttons list. | |
| 169 KeyCharacterMap kcm = inputDevice.getKeyCharacterMap(); | |
| 170 boolean[] deviceKeys = kcm.deviceHasKeys(standardGamepadKeyCodes); | |
| 171 int j; | |
| 172 for (j = 0; j < standardGamepadKeyCodes.length; ++j) { | |
| 173 if (deviceKeys[j]) { | |
| 174 mKeyCodeValueMap.put(standardGamepadKeyCodes[j], 0.0f); | |
| 175 } | |
| 176 } | |
| 177 | |
| 178 // When the user agent recognizes the attached inputDevice, it is recomm ended | |
| 179 // that it be remapped to a canonical ordering when possible. Devices | |
| 180 // that are not recognized should still be exposed in their raw form. | |
| 181 setGamepadType(); | |
| 182 } | |
| 183 | |
| 184 GamepadDevice() {} | |
| 185 | |
| 186 public int getId() { return mDeviceId; } | |
| 187 | |
| 188 public String getName() { return mDeviceName; } | |
| 189 | |
| 190 public int getIndex() { return mDeviceIndex; } | |
| 191 | |
| 192 public long getTimestamp() { return mTimestamp; } | |
| 193 | |
| 194 public float[] getAxes() { | |
| 195 if ( mGamepadType != GamepadType.Unknown) { | |
| 196 return mapToStandardGamepadAxes(mAxisValues); | |
| 197 } | |
| 198 return mAxisValues; | |
| 199 } | |
| 200 | |
| 201 public float[] getButtons() { | |
| 202 int size = mKeyCodeValueMap.size(); | |
| 203 float[] values = new float[size]; | |
| 204 int i = 0; | |
| 205 Iterator itr = mKeyCodeValueMap.values().iterator(); | |
| 206 while (itr.hasNext()) { | |
| 207 values[i++] = (Float)itr.next(); | |
| 208 } | |
| 209 if ( mGamepadType != GamepadType.Unknown) { | |
| 210 return mapToStandardGamepadButtons(values, mAxisValues); | |
| 211 } | |
| 212 return values; | |
| 213 } | |
| 214 | |
| 215 public boolean updateForEvent(KeyEvent event) { | |
| 216 mTimestamp = SystemClock.uptimeMillis(); | |
| 217 // Ignore event if it is not for standard gamepad key. | |
| 218 int keyCode = event.getKeyCode(); | |
| 219 if (mKeyCodeValueMap.get(keyCode) == null) { | |
| 220 return true; | |
| 221 } | |
| 222 // Button value 0.0 must mean fully unpressed, and 1.0 must mean fully p ressed. | |
| 223 if (event.getAction() == KeyEvent.ACTION_DOWN) { | |
| 224 mKeyCodeValueMap.put(keyCode, 1.0f); | |
| 225 } else if (event.getAction() == KeyEvent.ACTION_UP) { | |
| 226 mKeyCodeValueMap.put(keyCode, 0.0f); | |
| 227 } | |
| 228 | |
| 229 return true; | |
| 230 } | |
| 231 | |
| 232 public boolean updateForEvent(MotionEvent event) { | |
| 233 mTimestamp = SystemClock.uptimeMillis(); | |
| 234 // Update axes values. | |
| 235 for (int i = 0; i < mAxes.length; ++i) { | |
| 236 mAxisValues[i] = event.getAxisValue(mAxes[i]); | |
| 237 } | |
| 238 return true; | |
| 239 } | |
| 240 | |
| 241 public boolean isKnownGamepadLayout() { | |
| 242 return mGamepadType != GamepadType.Unknown; | |
| 243 } | |
| 244 | |
| 245 protected void setGamepadType() { | |
| 246 if (isKnownShieldGamepad()) { | |
| 247 mGamepadType = GamepadType.Shield; | |
| 248 } else if (isKnownXBoxGamepad()) { | |
| 249 mGamepadType = GamepadType.XBox360; | |
| 250 } else { | |
| 251 // TODO: Add support for mapping other common gamepads to the standa rd gamepads. | |
| 252 mGamepadType = GamepadType.Unknown; | |
| 253 } | |
| 254 } | |
| 255 | |
| 256 private boolean isKnownShieldGamepad() { | |
| 257 if (mDeviceName.contains("NVIDIA") && mDeviceName.contains("Controller") ) { | |
| 258 // Known shield gamepad should have mRawShieldAxes and mRawShieldBut tons. | |
| 259 if (mAxisValues.length == mRawShieldAxes && | |
| 260 mKeyCodeValueMap.size() == mRawShieldButtons) { | |
| 261 return true; | |
| 262 } | |
| 263 } | |
| 264 return false; | |
| 265 } | |
| 266 | |
| 267 private boolean isKnownXBoxGamepad() { | |
| 268 if (mDeviceName.contains("Microsoft") && mDeviceName.contains("X-Box") & & | |
| 269 mDeviceName.contains("360") && mDeviceName.contains("pad")) { | |
| 270 // Known XBox gamepad should have mRawXBoxAxes and mRawXBoxButtons. | |
| 271 if (mAxisValues.length == mRawXBoxAxes && mKeyCodeValueMap.size() == mRawXBoxButtons) { | |
| 272 return true; | |
| 273 } | |
| 274 } | |
| 275 return false; | |
| 276 } | |
| 277 | |
| 278 private float[] mapToStandardGamepadAxes(float[] rawAxes) { | |
| 279 switch (mGamepadType) { | |
| 280 case Shield: | |
| 281 return mapShieldAxes(rawAxes); | |
| 282 case XBox360: | |
| 283 return mapXBox360Axes(rawAxes); | |
| 284 } | |
| 285 return rawAxes; | |
| 286 } | |
| 287 | |
| 288 private float[] mapToStandardGamepadButtons(float[] rawButtons, float[] rawA xes) { | |
| 289 switch (mGamepadType) { | |
| 290 case Shield: | |
| 291 return mapShieldButtons(rawButtons, rawAxes); | |
| 292 case XBox360: | |
| 293 return mapXBox360Buttons(rawButtons, rawAxes); | |
| 294 } | |
| 295 return rawAxes; | |
| 296 } | |
| 297 | |
| 298 private float negativeAxisValueAsButton(float input) { | |
| 299 return (input < -0.5f) ? 1.f : 0.f; | |
| 300 } | |
| 301 | |
| 302 private float positiveAxisValueAsButton(float input) { | |
| 303 return (input > 0.5f) ? 1.f : 0.f; | |
| 304 } | |
| 305 | |
| 306 /** | |
| 307 * Method for mapping Nvidia gamepad axis values to | |
| 308 * standard gamepad axis values. | |
| 309 */ | |
| 310 private float[] mapShieldAxes(float[] rawAxes) { | |
| 311 float[] values = new float[StandardAxes.MAX_AXES]; | |
| 312 // Standard gamepad can have only four axes. | |
| 313 values[StandardAxes.AXIS_0] = rawAxes[0]; | |
| 314 values[StandardAxes.AXIS_1] = rawAxes[1]; | |
| 315 values[StandardAxes.AXIS_2] = rawAxes[4]; | |
| 316 values[StandardAxes.AXIS_3] = rawAxes[5]; | |
| 317 return values; | |
| 318 } | |
| 319 | |
| 320 /** | |
| 321 * Method for mapping Nvidia gamepad axis and button values | |
| 322 * to standard gamepad button values. | |
| 323 */ | |
| 324 public float[] mapShieldButtons(float[] rawButtons, float[] rawAxes) { | |
| 325 float[] values = new float[StandardButtons.MAX_BUTTONS]; | |
| 326 // First four buttons on Nvidia gamepad appear in correct order so no ma pping is required. | |
| 327 values[StandardButtons.BUTTON_A] = rawButtons[0]; | |
| 328 values[StandardButtons.BUTTON_B] = rawButtons[1]; | |
| 329 values[StandardButtons.BUTTON_X] = rawButtons[2]; | |
| 330 values[StandardButtons.BUTTON_Y] = rawButtons[3]; | |
| 331 // Third axis on Nvidia gamepad acts as a bottom left trigger button. | |
| 332 values[StandardButtons.BOTTOM_LEFT_TRIGGER] = rawAxes[2]; | |
| 333 values[StandardButtons.LEFT_TRIGGER] = rawButtons[4]; | |
| 334 values[StandardButtons.RIGHT_TRIGGER] = rawButtons[5]; | |
| 335 values[StandardButtons.SELECT] = rawButtons[6]; | |
| 336 values[StandardButtons.START] = rawButtons[7]; | |
| 337 values[StandardButtons.LEFT_THUMB] = rawButtons[8]; | |
| 338 values[StandardButtons.RIGHT_THUMB] = rawButtons[9]; | |
| 339 // Seventh axis on Nvidia gamepad acts as a bottom right trigger button. | |
| 340 values[StandardButtons.BOTTOM_RIGHT_TRIGGER] = rawAxes[6]; | |
| 341 // Ninth axis on Nvidia gamepad acts as directional pad right and left b utton. | |
| 342 // Positive axis value indicates dpad right. | |
| 343 // Negative value indicates dpad left. | |
| 344 values[StandardButtons.DPAD_RIGHT] = positiveAxisValueAsButton(rawAxes[8 ]); | |
| 345 values[StandardButtons.DPAD_LEFT] = negativeAxisValueAsButton(rawAxes[8] ); | |
| 346 // Tenth axis on Nvidia gamepad acts as directional pad up and down butt on. | |
| 347 // Positive axis value indicates dpad down. | |
| 348 // Negative value indicates dpad up. | |
| 349 values[StandardButtons.DPAD_DOWN] = positiveAxisValueAsButton(rawAxes[9] ); | |
| 350 values[StandardButtons.DPAD_UP] = negativeAxisValueAsButton(rawAxes[9]); | |
| 351 // Other standard buttons are either not present on the gamepad or not e xposed to an | |
| 352 // application. | |
| 353 values[StandardButtons.MODE] = 0.0f; | |
| 354 return values; | |
| 355 } | |
| 356 | |
| 357 /** | |
| 358 * Method for mapping Microsoft XBox 360 gamepad axis values to | |
| 359 * standard gamepad axis values. | |
| 360 */ | |
| 361 private float[] mapXBox360Axes(float[] rawAxes) { | |
| 362 float[] values = new float[StandardAxes.MAX_AXES]; | |
| 363 // Standard gamepad can have only four axes. | |
| 364 values[StandardAxes.AXIS_0] = rawAxes[0]; | |
| 365 values[StandardAxes.AXIS_1] = rawAxes[1]; | |
| 366 values[StandardAxes.AXIS_2] = rawAxes[4]; | |
| 367 values[StandardAxes.AXIS_3] = rawAxes[5]; | |
| 368 return values; | |
| 369 } | |
| 370 | |
| 371 /** | |
| 372 * Method for mapping Microsoft XBox 360 gamepad axis and button values | |
| 373 * to standard gamepad button values. | |
| 374 */ | |
| 375 private float[] mapXBox360Buttons(float[] rawButtons, float[] rawAxes) { | |
| 376 float[] values = new float[StandardButtons.MAX_BUTTONS]; | |
| 377 // First four buttons on Microsoft XBox 360 gamepad appear in correct or der so no mapping | |
| 378 // is required. | |
| 379 values[StandardButtons.BUTTON_A] = rawButtons[0]; | |
| 380 values[StandardButtons.BUTTON_B] = rawButtons[1]; | |
| 381 values[StandardButtons.BUTTON_X] = rawButtons[2]; | |
| 382 values[StandardButtons.BUTTON_Y] = rawButtons[3]; | |
| 383 // Third axis on Microsoft XBox 360 gamepad acts as a left bottom should er button. | |
| 384 values[StandardButtons.BOTTOM_LEFT_TRIGGER] = rawAxes[2]; | |
| 385 values[StandardButtons.LEFT_TRIGGER] = rawButtons[4]; | |
| 386 values[StandardButtons.RIGHT_TRIGGER] = rawButtons[5]; | |
| 387 values[StandardButtons.START] = rawButtons[6]; | |
| 388 values[StandardButtons.LEFT_THUMB] = rawButtons[7]; | |
| 389 values[StandardButtons.RIGHT_THUMB] = rawButtons[8]; | |
| 390 // Seventh axis on Microsoft XBox 360 gamepad acts as a right bottom sho ulder button. | |
| 391 values[StandardButtons.BOTTOM_RIGHT_TRIGGER] = rawAxes[6]; | |
| 392 // Ninth axis on Microsoft XBox 360 gamepad acts as directional pad righ t and left button. | |
| 393 // Positive axis value indicates dpad right. | |
| 394 // Negative value indicates dpad left. | |
| 395 values[StandardButtons.DPAD_RIGHT] = positiveAxisValueAsButton(rawAxes[8 ]); | |
| 396 values[StandardButtons.DPAD_LEFT] = negativeAxisValueAsButton(rawAxes[8] ); | |
| 397 // Tenth axis on Microsoft XBox 360 gamepad acts as directional pad up a nd down button. | |
| 398 // Positive axis value indicates dpad down. | |
| 399 // Negative value indicates dpad up. | |
| 400 values[StandardButtons.DPAD_DOWN] = positiveAxisValueAsButton(rawAxes[9] ); | |
| 401 values[StandardButtons.DPAD_UP] = negativeAxisValueAsButton(rawAxes[9]); | |
| 402 // Other standard buttons are either not present on the gamepad or not e xposed to an | |
| 403 // application. | |
| 404 values[StandardButtons.SELECT] = 0.0f; | |
| 405 values[StandardButtons.MODE] = 0.0f; | |
| 406 return values; | |
| 407 } | |
| 408 | |
| 409 } | |
| OLD | NEW |