Commit 41dada5c authored by skhatri@nvidia.com's avatar skhatri@nvidia.com

Gamepad API support for chrome on android

This change adds code to get gamepad data from java objects and
provide these updates to the GamepadProvider which then writes to
GamepadHardwareBuffer which in turn is read by SharedMemoryReader and
later returned by JS to the web page.

This also adds new framework classes/methods required for Gamepad API
support. Frameworks changes are responsible for :
  - Identifying gamepad devices and their capabilities.
  - Managing connected gamepad devices
  - Map the connected gamepad devices to standard Gamepad format.
  - Keeping gamepads axes/buttons data up-to-date and returning it to
    native whenever requested. In android we cannot get gamepad data
    directly from sources, so framework is modified to capture
    gamepad key and motion events and extract gamepad data from these
    events.

* Class GamepadPlatformDataFetcherAndroid : Android specific
  implementation of gamepad data fetcher.
  - Responsible for communication with java class and accessing gamepad data.
  - It adds methods for communication with singleton java GamepadList class
to get gamepads data.

* Class ContentViewCore : Manages gamepad list and notifies of new
  key/motion event for gamepads.

* Class GamepadList : A new class to manage connected gamepad devices

* Class GamepadDevice : A new class to manage information related to
  each gamepad device.

* Class GamepadMappings : This class is responsible for mapping of
  known gamepads to the standard gamepad.

This change enables gamepad API by default.

Adds support for parsing float array return type in JNI generator.

NVIDIA Shield and XBox360 gamepads are mapped to the standard gamepad

BUG=330094

TEST=http://www.html5rocks.com/en/tutorials/doodles/gamepad/gamepad-tester/tester.html

R=tsepez@chromium.org
R=darin@chromium.org

Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=270620

Review URL: https://codereview.chromium.org/133943002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274212 0039d316-1c4b-4281-b951-d872f2087c98
parent a80607d2
......@@ -61,6 +61,8 @@ $(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chro
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/browser/GestureEventType.java \
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/browser/PageTransitionTypes.java \
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/browser/SpeechRecognitionError.java \
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/browser/input/CanonicalAxisIndex.java \
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/browser/input/CanonicalButtonIndex.java \
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/browser/input/PopupItemType.java \
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/common/ResultCodes.java \
$(call intermediates-dir-for,GYP,shared,,,$(TARGET_2ND_ARCH))/templates/org/chromium/content/common/ScreenOrientationValues.java \
......
......@@ -26,6 +26,7 @@
'dependencies': [
'../base/base.gyp:base_java_application_state',
'../base/base.gyp:base_java_memory_pressure_level_list',
'../content/content.gyp:content_gamepad_mapping',
'../content/content.gyp:gesture_event_type_java',
'../content/content.gyp:page_transition_types_java',
'../content/content.gyp:popup_item_type_java',
......
......@@ -408,6 +408,7 @@ def GetStaticCastForReturnType(return_type):
'short[]': 'jshortArray',
'int[]': 'jintArray',
'long[]': 'jlongArray',
'float[]': 'jfloatArray',
'double[]': 'jdoubleArray' }
ret = type_map.get(return_type, None)
if ret:
......
......@@ -26,6 +26,7 @@
#include "content/browser/battery_status/battery_status_manager.h"
#include "content/browser/device_sensors/sensor_manager_android.h"
#include "content/browser/frame_host/navigation_controller_android.h"
#include "content/browser/gamepad/gamepad_platform_data_fetcher_android.h"
#include "content/browser/geolocation/location_api_adapter_android.h"
#include "content/browser/media/android/media_drm_credential_manager.h"
#include "content/browser/media/android/media_resource_getter_impl.h"
......@@ -62,6 +63,8 @@ base::android::RegistrationMethod kContentRegisteredMethods[] = {
{"DateTimePickerAndroid", content::RegisterDateTimeChooserAndroid},
{"DownloadControllerAndroidImpl",
content::DownloadControllerAndroidImpl::RegisterDownloadController},
{"GamepadList", content::GamepadPlatformDataFetcherAndroid::
RegisterGamepadPlatformDataFetcherAndroid},
{"InterstitialPageDelegateAndroid",
content::InterstitialPageDelegateAndroid::
RegisterInterstitialPageDelegateAndroid},
......
// 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.
// This file intentionally does not have header guards, it's included
// inside a macro to generate enum values.
// This file defines the canonical axes mapping order for gamepad-like devices.
// TODO(SaurabhK): Consolidate with CanonicalAxisIndex enum in
// gamepad_standard_mappings.h, crbug.com/351558.
CANONICAL_AXIS_INDEX(AXIS_LEFT_STICK_X, 0)
CANONICAL_AXIS_INDEX(AXIS_LEFT_STICK_Y, 1)
CANONICAL_AXIS_INDEX(AXIS_RIGHT_STICK_X, 2)
CANONICAL_AXIS_INDEX(AXIS_RIGHT_STICK_Y, 3)
CANONICAL_AXIS_INDEX(NUM_CANONICAL_AXES, 4)
// 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.
// This file intentionally does not have header guards, it's included
// inside a macro to generate enum values.
// This defines the canonical button mapping order for gamepad-like devices.
// TODO(SaurabhK): Consolidate with CanonicalButtonIndex enum in
// gamepad_standard_mappings.h, crbug.com/351558.
CANONICAL_BUTTON_INDEX(BUTTON_PRIMARY, 0)
CANONICAL_BUTTON_INDEX(BUTTON_SECONDARY, 1)
CANONICAL_BUTTON_INDEX(BUTTON_TERTIARY, 2)
CANONICAL_BUTTON_INDEX(BUTTON_QUATERNARY, 3)
CANONICAL_BUTTON_INDEX(BUTTON_LEFT_SHOULDER, 4)
CANONICAL_BUTTON_INDEX(BUTTON_RIGHT_SHOULDER, 5)
CANONICAL_BUTTON_INDEX(BUTTON_LEFT_TRIGGER, 6)
CANONICAL_BUTTON_INDEX(BUTTON_RIGHT_TRIGGER, 7)
CANONICAL_BUTTON_INDEX(BUTTON_BACK_SELECT, 8)
CANONICAL_BUTTON_INDEX(BUTTON_START, 9)
CANONICAL_BUTTON_INDEX(BUTTON_LEFT_THUMBSTICK, 10)
CANONICAL_BUTTON_INDEX(BUTTON_RIGHT_THUMBSTICK, 11)
CANONICAL_BUTTON_INDEX(BUTTON_DPAD_UP, 12)
CANONICAL_BUTTON_INDEX(BUTTON_DPAD_DOWN, 13)
CANONICAL_BUTTON_INDEX(BUTTON_DPAD_LEFT, 14)
CANONICAL_BUTTON_INDEX(BUTTON_DPAD_RIGHT, 15)
CANONICAL_BUTTON_INDEX(BUTTON_META, 16)
CANONICAL_BUTTON_INDEX(NUM_CANONICAL_BUTTONS, 17)
\ No newline at end of file
......@@ -12,7 +12,9 @@
#include "base/compiler_specific.h"
#include "content/browser/gamepad/gamepad_data_fetcher.h"
#if defined(OS_WIN)
#if defined(OS_ANDROID)
#include "content/browser/gamepad/gamepad_platform_data_fetcher_android.h"
#elif defined(OS_WIN)
#include "content/browser/gamepad/gamepad_platform_data_fetcher_win.h"
#elif defined(OS_MACOSX)
#include "content/browser/gamepad/gamepad_platform_data_fetcher_mac.h"
......@@ -22,7 +24,11 @@
namespace content {
#if defined(OS_WIN)
#if defined(OS_ANDROID)
typedef GamepadPlatformDataFetcherAndroid GamepadPlatformDataFetcher;
#elif defined(OS_WIN)
typedef GamepadPlatformDataFetcherWin GamepadPlatformDataFetcher;
......
// 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.
#include "content/browser/gamepad/gamepad_platform_data_fetcher_android.h"
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/debug/trace_event.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "jni/GamepadList_jni.h"
#include "third_party/WebKit/public/platform/WebGamepads.h"
using base::android::AttachCurrentThread;
using base::android::CheckException;
using base::android::ClearException;
using base::android::ConvertJavaStringToUTF8;
using base::android::ScopedJavaLocalRef;
using blink::WebGamepad;
using blink::WebGamepads;
namespace content {
bool
GamepadPlatformDataFetcherAndroid::RegisterGamepadPlatformDataFetcherAndroid(
JNIEnv* env) {
return RegisterNativesImpl(env);
}
GamepadPlatformDataFetcherAndroid::GamepadPlatformDataFetcherAndroid() {
PauseHint(false);
}
GamepadPlatformDataFetcherAndroid::~GamepadPlatformDataFetcherAndroid() {
PauseHint(true);
}
void GamepadPlatformDataFetcherAndroid::GetGamepadData(
blink::WebGamepads* pads,
bool devices_changed_hint) {
TRACE_EVENT0("GAMEPAD", "GetGamepadData");
pads->length = 0;
JNIEnv* env = AttachCurrentThread();
if (!env)
return;
Java_GamepadList_updateGamepadData(env, reinterpret_cast<intptr_t>(pads));
}
void GamepadPlatformDataFetcherAndroid::PauseHint(bool paused) {
JNIEnv* env = AttachCurrentThread();
if (!env)
return;
Java_GamepadList_notifyForGamepadsAccess(env, paused);
}
static void SetGamepadData(JNIEnv* env,
jobject obj,
jlong gamepads,
jint index,
jboolean mapping,
jboolean connected,
jstring devicename,
jlong timestamp,
jfloatArray jaxes,
jfloatArray jbuttons) {
DCHECK(gamepads);
blink::WebGamepads* pads = reinterpret_cast<WebGamepads*>(gamepads);
DCHECK_EQ(pads->length, unsigned(index));
DCHECK_LT(index, static_cast<int>(blink::WebGamepads::itemsLengthCap));
++pads->length;
blink::WebGamepad& pad = pads->items[index];
pad.connected = connected;
pad.timestamp = timestamp;
// Do not set gamepad parameters for all the gamepad devices that are not
// attached.
if (!connected)
return;
// Map the Gamepad DeviceName String to the WebGamepad Id. Ideally it should
// be mapped to vendor and product information but it is only available at
// kernel level and it can not be queried using class
// android.hardware.input.InputManager.
// TODO(SaurabhK): Store a cached WebGamePad object in
// GamepadPlatformDataFetcherAndroid and only update constant WebGamepad
// values when a device has changed.
base::string16 device_name;
base::android::ConvertJavaStringToUTF16(env, devicename, &device_name);
const size_t name_to_copy =
std::min(device_name.size(), WebGamepad::idLengthCap - 1);
memcpy(pad.id,
device_name.data(),
name_to_copy * sizeof(base::string16::value_type));
pad.id[name_to_copy] = 0;
base::string16 mapping_name = base::UTF8ToUTF16(mapping ? "standard" : "");
const size_t mapping_to_copy =
std::min(mapping_name.size(), WebGamepad::mappingLengthCap - 1);
memcpy(pad.mapping,
mapping_name.data(),
mapping_to_copy * sizeof(base::string16::value_type));
pad.mapping[mapping_to_copy] = 0;
pad.timestamp = timestamp;
std::vector<float> axes;
base::android::JavaFloatArrayToFloatVector(env, jaxes, &axes);
// Set WebGamepad axeslength to total number of axes on the gamepad device.
// Only return the first axesLengthCap if axeslength captured by GamepadList
// is larger than axesLengthCap.
pad.axesLength = std::min(static_cast<int>(axes.size()),
static_cast<int>(WebGamepad::axesLengthCap));
// Copy axes state to the WebGamepad axes[].
for (unsigned int i = 0; i < pad.axesLength; i++) {
pad.axes[i] = static_cast<double>(axes[i]);
}
std::vector<float> buttons;
base::android::JavaFloatArrayToFloatVector(env, jbuttons, &buttons);
// Set WebGamepad buttonslength to total number of axes on the gamepad
// device. Only return the first buttonsLengthCap if axeslength captured by
// GamepadList is larger than buttonsLengthCap.
pad.buttonsLength = std::min(static_cast<int>(buttons.size()),
static_cast<int>(WebGamepad::buttonsLengthCap));
// Copy buttons state to the WebGamepad buttons[].
for (unsigned int j = 0; j < pad.buttonsLength; j++) {
pad.buttons[j].pressed = buttons[j];
pad.buttons[j].value = buttons[j];
}
}
} // namespace content
// 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.
// Define the data fetcher that GamepadProvider will use for android port.
// (GamepadPlatformDataFetcher).
#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_ANDROID_H_
#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_ANDROID_H_
#include <jni.h>
#include "base/android/jni_android.h"
#include "content/browser/gamepad/gamepad_data_fetcher.h"
#include "content/browser/gamepad/gamepad_provider.h"
#include "content/browser/gamepad/gamepad_standard_mappings.h"
#include "third_party/WebKit/public/platform/WebGamepads.h"
namespace content {
class GamepadPlatformDataFetcherAndroid : public GamepadDataFetcher {
public:
GamepadPlatformDataFetcherAndroid();
virtual ~GamepadPlatformDataFetcherAndroid();
virtual void PauseHint(bool paused) OVERRIDE;
virtual void GetGamepadData(blink::WebGamepads* pads,
bool devices_changed_hint) OVERRIDE;
// Registers the JNI methods for GamepadsReader.
static bool RegisterGamepadPlatformDataFetcherAndroid(JNIEnv* env);
private:
DISALLOW_COPY_AND_ASSIGN(GamepadPlatformDataFetcherAndroid);
};
} // namespace content
#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_PLATFORM_DATA_FETCHER_ANDROID_H_
......@@ -131,6 +131,10 @@ void GamepadProvider::Initialize(scoped_ptr<GamepadDataFetcher> fetcher) {
// On Linux, the data fetcher needs to watch file descriptors, so the message
// loop needs to be a libevent loop.
const base::MessageLoop::Type kMessageLoopType = base::MessageLoop::TYPE_IO;
#elif defined(OS_ANDROID)
// On Android, keeping a message loop of default type.
const base::MessageLoop::Type kMessageLoopType =
base::MessageLoop::TYPE_DEFAULT;
#else
// On Mac, the data fetcher uses IOKit which depends on CFRunLoop, so the
// message loop needs to be a UI-type loop. On Windows it must be a UI loop
......
......@@ -12,6 +12,7 @@
#if defined(OS_ANDROID)
#include <cpu-features.h>
#include "base/android/build_info.h"
#include "media/base/android/media_codec_bridge.h"
#endif
......@@ -33,8 +34,10 @@ static void SetRuntimeFeatureDefaultsForPlatform() {
media::MediaCodecBridge::IsAvailable() &&
((android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM) ||
(android_getCpuFamily() == ANDROID_CPU_FAMILY_X86)));
// Android does not support the Gamepad API.
WebRuntimeFeatures::enableGamepad(false);
// Android supports gamepad API for JellyBean and beyond
WebRuntimeFeatures::enableGamepad(
base::android::BuildInfo::GetInstance()->sdk_int() >= 16);
// Android does not have support for PagePopup
WebRuntimeFeatures::enablePagePopup(false);
// Android does not yet support the Web Notification API. crbug.com/115320
......
......@@ -384,6 +384,7 @@
'common_aidl',
'content_common',
'content_strings_grd',
'content_gamepad_mapping',
'gesture_event_type_java',
'page_transition_types_java',
'popup_item_type_java',
......@@ -545,6 +546,22 @@
}],
],
},
{
'target_name': 'content_gamepad_mapping',
'type': 'none',
'sources': [
'public/android/java/src/org/chromium/content/browser/input/CanonicalButtonIndex.template',
'public/android/java/src/org/chromium/content/browser/input/CanonicalAxisIndex.template',
],
'variables': {
'package_name': 'org/chromium/content/browser/input',
'template_deps': [
'browser/gamepad/canonical_axis_index_list.h',
'browser/gamepad/canonical_button_index_list.h',
],
},
'includes': [ '../build/android/java_cpp_template.gypi' ],
},
],
}], # OS == "android"
],
......
......@@ -596,6 +596,8 @@
'browser/gamepad/gamepad_consumer.h',
'browser/gamepad/gamepad_data_fetcher.h',
'browser/gamepad/gamepad_platform_data_fetcher.h',
'browser/gamepad/gamepad_platform_data_fetcher_android.cc',
'browser/gamepad/gamepad_platform_data_fetcher_android.h',
'browser/gamepad/gamepad_platform_data_fetcher_linux.cc',
'browser/gamepad/gamepad_platform_data_fetcher_linux.h',
'browser/gamepad/gamepad_platform_data_fetcher_mac.h',
......@@ -1426,7 +1428,7 @@
'browser/power_profiler/power_data_provider_dummy.cc'
]
}],
['OS!="win" and OS!="mac" and (OS!="linux" or use_udev==0)', {
['OS!="win" and OS!="mac" and OS!="android" and (OS!="linux" or use_udev==0)', {
'sources': [
'browser/gamepad/gamepad_platform_data_fetcher.cc',
]
......
......@@ -22,6 +22,7 @@
'public/android/java/src/org/chromium/content/browser/ContentViewStatics.java',
'public/android/java/src/org/chromium/content/browser/DeviceSensors.java',
'public/android/java/src/org/chromium/content/browser/DownloadController.java',
'public/android/java/src/org/chromium/content/browser/input/GamepadList.java',
'public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java',
'public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java',
'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java',
......
......@@ -59,6 +59,7 @@ import org.chromium.content.browser.ScreenOrientationListener.ScreenOrientationO
import org.chromium.content.browser.accessibility.AccessibilityInjector;
import org.chromium.content.browser.accessibility.BrowserAccessibilityManager;
import org.chromium.content.browser.input.AdapterInputConnection;
import org.chromium.content.browser.input.GamepadList;
import org.chromium.content.browser.input.HandleView;
import org.chromium.content.browser.input.ImeAdapter;
import org.chromium.content.browser.input.ImeAdapter.AdapterInputConnectionFactory;
......@@ -1386,6 +1387,7 @@ public class ContentViewCore
setAccessibilityState(mAccessibilityManager.isEnabled());
ScreenOrientationListener.getInstance().addObserver(this, mContext);
GamepadList.onAttachedToWindow(mContext);
}
/**
......@@ -1400,6 +1402,7 @@ public class ContentViewCore
unregisterAccessibilityContentObserver();
ScreenOrientationListener.getInstance().removeObserver(this);
GamepadList.onDetachedFromWindow();
}
/**
......@@ -1601,6 +1604,7 @@ public class ContentViewCore
* @see View#dispatchKeyEvent(KeyEvent)
*/
public boolean dispatchKeyEvent(KeyEvent event) {
if (GamepadList.dispatchKeyEvent(event)) return true;
if (getContentViewClient().shouldOverrideKeyEvent(event)) {
return mContainerViewInternals.super_dispatchKeyEvent(event);
}
......@@ -1646,6 +1650,7 @@ public class ContentViewCore
* @see View#onGenericMotionEvent(MotionEvent)
*/
public boolean onGenericMotionEvent(MotionEvent event) {
if (GamepadList.onGenericMotionEvent(event)) return true;
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
switch (event.getAction()) {
case MotionEvent.ACTION_SCROLL:
......
// 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;
public class CanonicalAxisIndex {
#define CANONICAL_AXIS_INDEX(name, value) public static final int name = value;
#include "content/browser/gamepad/canonical_axis_index_list.h"
}
\ No newline at end of file
// 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;
public class CanonicalButtonIndex {
#define CANONICAL_BUTTON_INDEX(name, value) public static final int name = value;
#include "content/browser/gamepad/canonical_button_index_list.h"
}
\ No newline at end of file
// 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.os.SystemClock;
import android.view.InputDevice;
import android.view.InputDevice.MotionRange;
import android.view.KeyEvent;
import android.view.MotionEvent;
import java.util.Arrays;
/**
* Manages information related to each connected gamepad device.
*/
class GamepadDevice {
// An id for the gamepad.
private int mDeviceId;
// The index of the gamepad in the Navigator.
private int mDeviceIndex;
// Last time the data for this gamepad was updated.
private long mTimestamp;
// If this gamepad is mapped to standard gamepad?
private boolean mIsStandardGamepad;
// Array of values for all axes of the gamepad.
// All axis values must be linearly normalized to the range [-1.0 .. 1.0].
// As appropriate, -1.0 should correspond to "up" or "left", and 1.0
// should correspond to "down" or "right".
private float[] mAxisValues;
private float[] mButtonsValues;
// When the user agent recognizes the attached inputDevice, it is recommended
// that it be remapped to a canonical ordering when possible. Devices that are
// not recognized should still be exposed in their raw form. Therefore we must
// pass the raw Button and raw Axis values.
private float[] mRawButtons;
private float[] mRawAxes;
// An identification string for the gamepad.
private String mDeviceName;
// Array of axes ids.
private int[] mAxes;
GamepadDevice(int index, InputDevice inputDevice) {
mDeviceIndex = index;
mDeviceId = inputDevice.getId();
mDeviceName = inputDevice.getName();
mTimestamp = SystemClock.uptimeMillis();
mButtonsValues = new float[CanonicalButtonIndex.NUM_CANONICAL_BUTTONS];
mAxisValues = new float[CanonicalAxisIndex.NUM_CANONICAL_AXES];
mRawButtons = new float[256];
// Get the total number of axes supported by gamepad.
int totalAxes = 0;
for (MotionRange range : inputDevice.getMotionRanges()) {
if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
totalAxes++;
}
}
// Get axis ids and initialize axes values.
mAxes = new int[totalAxes];
mRawAxes = new float[totalAxes];
int i = 0;
for (MotionRange range : inputDevice.getMotionRanges()) {
if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
mAxes[i] = range.getAxis();
mRawAxes[i] = 0.0f;
i++;
}
}
}
/**
* Updates the axes and buttons maping of a gamepad device to a standard gamepad format.
*/
public void updateButtonsAndAxesMapping() {
mIsStandardGamepad = GamepadMappings.mapToStandardGamepad(
mAxisValues, mButtonsValues, mRawAxes, mRawButtons, mDeviceName);
}
/**
* @return Device Id of the gamepad device.
*/
public int getId() { return mDeviceId; }
/**
* @return Mapping status of the gamepad device.
*/
public boolean isStandardGamepad() { return mIsStandardGamepad; }
/**
* @return Device name of the gamepad device.
*/
public String getName() { return mDeviceName; }
/**
* @return Device index of the gamepad device.
*/
public int getIndex() { return mDeviceIndex; }
/**
* @return The timestamp when the gamepad device was last interacted.
*/
public long getTimestamp() { return mTimestamp; }
/**
* @return The axes state of the gamepad device.
*/
public float[] getAxes() { return mAxisValues; }
/**
* @return The buttons state of the gamepad device.
*/
public float[] getButtons() { return mButtonsValues; }
/**
* Reset the axes and buttons data of the gamepad device everytime gamepad data access is
* paused.
*/
public void clearData() {
Arrays.fill(mAxisValues, 0);
Arrays.fill(mRawAxes, 0);
Arrays.fill(mButtonsValues, 0);
Arrays.fill(mRawButtons, 0);
}
/**
* Handles key event from the gamepad device.
* @return True if the key event from the gamepad device has been consumed.
*/
public boolean handleKeyEvent(KeyEvent event) {
// Ignore event if it is not for standard gamepad key.
if (!GamepadList.isGamepadEvent(event)) return false;
int keyCode = event.getKeyCode();
assert keyCode < 256;
// Button value 0.0 must mean fully unpressed, and 1.0 must mean fully pressed.
if (event.getAction() == KeyEvent.ACTION_DOWN) {
mRawButtons[keyCode] = 1.0f;
} else if (event.getAction() == KeyEvent.ACTION_UP) {
mRawButtons[keyCode] = 0.0f;
}
mTimestamp = event.getEventTime();
return true;
}
/**
* Handles motion event from the gamepad device.
* @return True if the motion event from the gamepad device has been consumed.
*/
public boolean handleMotionEvent(MotionEvent event) {
// Ignore event if it is not a standard gamepad motion event.
if (!GamepadList.isGamepadEvent(event)) return false;
// Update axes values.
for (int i = 0; i < mAxes.length; i++) {
mRawAxes[i] = event.getAxisValue(mAxes[i]);
}
mTimestamp = event.getEventTime();
return true;
}
}
// 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;
/**
* Class to manage mapping information related to each supported gamepad controller device.
*/
class GamepadMappings {
public static boolean mapToStandardGamepad(float[] mappedAxis, float[] mappedButtons,
float[] rawAxes, float[] rawButtons, String deviceName) {
if (deviceName.contains("NVIDIA Corporation NVIDIA Controller")) {
mapShieldGamepad(mappedButtons, rawButtons, mappedAxis, rawAxes);
return true;
} else if (deviceName.contains("Microsoft X-Box 360 pad")) {
mapXBox360Gamepad(mappedButtons, rawButtons, mappedAxis, rawAxes);
return true;
}
mapUnknownGamepad(mappedButtons, rawButtons, mappedAxis, rawAxes);
return false;
}
private static void mapCommonButtons(float[] mappedButtons, float[] rawButtons) {
mappedButtons[CanonicalButtonIndex.BUTTON_PRIMARY] = rawButtons[KeyEvent.KEYCODE_BUTTON_A];
mappedButtons[CanonicalButtonIndex.BUTTON_SECONDARY] =
rawButtons[KeyEvent.KEYCODE_BUTTON_B];
mappedButtons[CanonicalButtonIndex.BUTTON_TERTIARY] =
rawButtons[KeyEvent.KEYCODE_BUTTON_X];
mappedButtons[CanonicalButtonIndex.BUTTON_QUATERNARY] =
rawButtons[KeyEvent.KEYCODE_BUTTON_Y];
mappedButtons[CanonicalButtonIndex.BUTTON_LEFT_SHOULDER] =
rawButtons[KeyEvent.KEYCODE_BUTTON_L1];
mappedButtons[CanonicalButtonIndex.BUTTON_RIGHT_SHOULDER] =
rawButtons[KeyEvent.KEYCODE_BUTTON_R1];
mappedButtons[CanonicalButtonIndex.BUTTON_BACK_SELECT] =
rawButtons[KeyEvent.KEYCODE_BUTTON_SELECT];
mappedButtons[CanonicalButtonIndex.BUTTON_START] =
rawButtons[KeyEvent.KEYCODE_BUTTON_START];
mappedButtons[CanonicalButtonIndex.BUTTON_LEFT_THUMBSTICK] =
rawButtons[KeyEvent.KEYCODE_BUTTON_THUMBL];
mappedButtons[CanonicalButtonIndex.BUTTON_RIGHT_THUMBSTICK] =
rawButtons[KeyEvent.KEYCODE_BUTTON_THUMBR];
mappedButtons[CanonicalButtonIndex.BUTTON_META] = rawButtons[KeyEvent.KEYCODE_BUTTON_MODE];
}
private static void mapDpadButtonsToAxes(float[] mappedButtons, float[] rawAxes) {
// Negative value indicates dpad up.
mappedButtons[CanonicalButtonIndex.BUTTON_DPAD_UP] = negativeAxisValueAsButton(rawAxes[9]);
// Positive axis value indicates dpad down.
mappedButtons[CanonicalButtonIndex.BUTTON_DPAD_DOWN] =
positiveAxisValueAsButton(rawAxes[9]);
// Positive axis value indicates dpad right.
mappedButtons[CanonicalButtonIndex.BUTTON_DPAD_RIGHT] =
positiveAxisValueAsButton(rawAxes[8]);
// Negative value indicates dpad left.
mappedButtons[CanonicalButtonIndex.BUTTON_DPAD_LEFT] =
negativeAxisValueAsButton(rawAxes[8]);
}
private static void mapAxes(float[] mappedAxis, float[] rawAxes) {
// Standard gamepad can have only four axes.
mappedAxis[CanonicalAxisIndex.AXIS_LEFT_STICK_X] = rawAxes[0];
mappedAxis[CanonicalAxisIndex.AXIS_LEFT_STICK_Y] = rawAxes[1];
mappedAxis[CanonicalAxisIndex.AXIS_RIGHT_STICK_X] = rawAxes[4];
mappedAxis[CanonicalAxisIndex.AXIS_RIGHT_STICK_Y] = rawAxes[5];
}
private static float negativeAxisValueAsButton(float input) {
return (input < -0.5f) ? 1.f : 0.f;
}
private static float positiveAxisValueAsButton(float input) {
return (input > 0.5f) ? 1.f : 0.f;
}
/**
* Method for mapping Nvidia gamepad axis and button values
* to standard gamepad button and axes values.
*/
private static void mapShieldGamepad(float[] mappedButtons, float[] rawButtons,
float[] mappedAxis, float[] rawAxes) {
mapCommonButtons(mappedButtons, rawButtons);
mappedButtons[CanonicalButtonIndex.BUTTON_LEFT_TRIGGER] = rawAxes[2];
mappedButtons[CanonicalButtonIndex.BUTTON_RIGHT_TRIGGER] = rawAxes[6];
mapDpadButtonsToAxes(mappedButtons, rawAxes);
mapAxes(mappedAxis, rawAxes);
}
/**
* Method for mapping Microsoft XBox 360 gamepad axis and button values
* to standard gamepad button and axes values.
*/
private static void mapXBox360Gamepad(float[] mappedButtons, float[] rawButtons,
float[] mappedAxis, float[] rawAxes) {
mapCommonButtons(mappedButtons, rawButtons);
mappedButtons[CanonicalButtonIndex.BUTTON_LEFT_TRIGGER] = rawAxes[2];
mappedButtons[CanonicalButtonIndex.BUTTON_RIGHT_TRIGGER] = rawAxes[6];
mapDpadButtonsToAxes(mappedButtons, rawAxes);
mapAxes(mappedAxis, rawAxes);
}
/**
* Method for mapping Unkown gamepad axis and button values
* to standard gamepad button and axes values.
*/
private static void mapUnknownGamepad(float[] mappedButtons, float[] rawButtons,
float[] mappedAxis, float[] rawAxes) {
mapCommonButtons(mappedButtons, rawButtons);
mappedButtons[CanonicalButtonIndex.BUTTON_LEFT_TRIGGER] =
rawButtons[KeyEvent.KEYCODE_BUTTON_L2];
mappedButtons[CanonicalButtonIndex.BUTTON_RIGHT_TRIGGER] =
rawButtons[KeyEvent.KEYCODE_BUTTON_R2];
mappedButtons[CanonicalButtonIndex.BUTTON_DPAD_UP] = rawButtons[KeyEvent.KEYCODE_DPAD_UP];
mappedButtons[CanonicalButtonIndex.BUTTON_DPAD_DOWN] =
rawButtons[KeyEvent.KEYCODE_DPAD_DOWN];
mappedButtons[CanonicalButtonIndex.BUTTON_DPAD_RIGHT] =
rawButtons[KeyEvent.KEYCODE_DPAD_RIGHT];
mappedButtons[CanonicalButtonIndex.BUTTON_DPAD_LEFT] =
rawButtons[KeyEvent.KEYCODE_DPAD_LEFT];
mapAxes(mappedAxis, rawAxes);
}
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment