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 |