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.os.SystemClock; 8 import android.view.InputDevice; 9 import android.view.InputDevice.MotionRange; 10 import android.view.KeyEvent; 11 import android.view.MotionEvent; 12 13 import java.util.Arrays; 14 import java.util.List; 15 16 /** 17 * Manages information related to each connected gamepad device. 18 */ 19 class GamepadDevice { 20 // An id for the gamepad. 21 private int mDeviceId; 22 // The index of the gamepad in the Navigator. 23 private int mDeviceIndex; 24 // Last time the data for this gamepad was updated. 25 private long mTimestamp; 26 // If this gamepad is mapped to standard gamepad? 27 private boolean mIsStandardGamepad; 28 29 // Array of values for all axes of the gamepad. 30 // All axis values must be linearly normalized to the range [-1.0 .. 1.0]. 31 // As appropriate, -1.0 should correspond to "up" or "left", and 1.0 32 // should correspond to "down" or "right". 33 private final float[] mAxisValues = new float[CanonicalAxisIndex.NUM_CANONICAL_AXES]; 34 35 private final float[] mButtonsValues = new float[CanonicalButtonIndex.NUM_CANONICAL_BUTTONS];; 36 37 // When the user agent recognizes the attached inputDevice, it is recommended 38 // that it be remapped to a canonical ordering when possible. Devices that are 39 // not recognized should still be exposed in their raw form. Therefore we must 40 // pass the raw Button and raw Axis values. 41 private final float[] mRawButtons = new float[256]; 42 private final float[] mRawAxes = new float[256]; 43 44 // An identification string for the gamepad. 45 private String mDeviceName; 46 47 // Array of axes ids. 48 private int[] mAxes; 49 GamepadDevice(int index, InputDevice inputDevice)50 GamepadDevice(int index, InputDevice inputDevice) { 51 mDeviceIndex = index; 52 mDeviceId = inputDevice.getId(); 53 mDeviceName = inputDevice.getName(); 54 mTimestamp = SystemClock.uptimeMillis(); 55 // Get axis ids and initialize axes values. 56 final List<MotionRange> ranges = inputDevice.getMotionRanges(); 57 mAxes = new int[ranges.size()]; 58 int i = 0; 59 for (MotionRange range : ranges) { 60 if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) { 61 int axis = range.getAxis(); 62 assert axis < 256; 63 mAxes[i++] = axis; 64 } 65 } 66 } 67 68 /** 69 * Updates the axes and buttons maping of a gamepad device to a standard gamepad format. 70 */ 71 public void updateButtonsAndAxesMapping() { 72 mIsStandardGamepad = GamepadMappings.mapToStandardGamepad( 73 mAxisValues, mButtonsValues, mRawAxes, mRawButtons, mDeviceName); 74 } 75 76 /** 77 * @return Device Id of the gamepad device. 78 */ 79 public int getId() { return mDeviceId; } 80 81 /** 82 * @return Mapping status of the gamepad device. 83 */ 84 public boolean isStandardGamepad() { return mIsStandardGamepad; } 85 86 /** 87 * @return Device name of the gamepad device. 88 */ 89 public String getName() { return mDeviceName; } 90 91 /** 92 * @return Device index of the gamepad device. 93 */ 94 public int getIndex() { return mDeviceIndex; } 95 96 /** 97 * @return The timestamp when the gamepad device was last interacted. 98 */ 99 public long getTimestamp() { return mTimestamp; } 100 101 /** 102 * @return The axes state of the gamepad device. 103 */ 104 public float[] getAxes() { return mAxisValues; } 105 106 /** 107 * @return The buttons state of the gamepad device. 108 */ 109 public float[] getButtons() { return mButtonsValues; } 110 111 /** 112 * Reset the axes and buttons data of the gamepad device everytime gamepad data access is 113 * paused. 114 */ 115 public void clearData() { 116 Arrays.fill(mAxisValues, 0); 117 Arrays.fill(mRawAxes, 0); 118 Arrays.fill(mButtonsValues, 0); 119 Arrays.fill(mRawButtons, 0); 120 } 121 122 /** 123 * Handles key event from the gamepad device. 124 * @return True if the key event from the gamepad device has been consumed. 125 */ 126 public boolean handleKeyEvent(KeyEvent event) { 127 // Ignore event if it is not for standard gamepad key. 128 if (!GamepadList.isGamepadEvent(event)) return false; 129 int keyCode = event.getKeyCode(); 130 assert keyCode < 256; 131 // Button value 0.0 must mean fully unpressed, and 1.0 must mean fully pressed. 132 if (event.getAction() == KeyEvent.ACTION_DOWN) { 133 mRawButtons[keyCode] = 1.0f; 134 } else if (event.getAction() == KeyEvent.ACTION_UP) { 135 mRawButtons[keyCode] = 0.0f; 136 } 137 mTimestamp = event.getEventTime(); 138 139 return true; 140 } 141 142 /** 143 * Handles motion event from the gamepad device. 144 * @return True if the motion event from the gamepad device has been consumed. 145 */ 146 public boolean handleMotionEvent(MotionEvent event) { 147 // Ignore event if it is not a standard gamepad motion event. 148 if (!GamepadList.isGamepadEvent(event)) return false; 149 // Update axes values. 150 for (int i = 0; i < mAxes.length; i++) { 151 int axis = mAxes[i]; 152 mRawAxes[axis] = event.getAxisValue(axis); 153 } 154 mTimestamp = event.getEventTime(); 155 return true; 156 } 157 } 158