issue #4895:Get events from controller to engine[android]

This commit is contained in:
Dhilan007 2014-06-30 03:20:22 +08:00
parent 3c614d5670
commit 5ed581758e
47 changed files with 3163 additions and 0 deletions

View File

@ -0,0 +1,365 @@
/****************************************************************************
Copyright (c) 2014 cocos2d-x.org
Copyright (c) 2014 Chukong Technologies Inc.
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "CCController.h"
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
#include "CCGamepad.h"
#include "CCControllerDirectionPad.h"
#include "CCControllerButtonInput.h"
#include "CCControllerAxisInput.h"
#include "CCControllerThumbstick.h"
#include "ccMacros.h"
#include "CCEventDispatcher.h"
#include "CCEventController.h"
#include "CCEventListenerController.h"
#include "CCDirector.h"
#include "jni/JniHelper.h"
NS_CC_BEGIN
enum class AndroidControllerCode
{
THUMBSTICK_LEFT_X = 100,
THUMBSTICK_LEFT_Y = 101,
THUMBSTICK_RIGHT_X = 102,
THUMBSTICK_RIGHT_Y = 103,
BUTTON_A = 110,
BUTTON_B = 111,
BUTTON_C = 112,
BUTTON_X = 113,
BUTTON_Y = 114,
BUTTON_Z = 115,
BUTTON_LEFT_SHOULDER = 120,
BUTTON_RIGHT_SHOULDER = 121,
BUTTON_LEFT_TRIGGER = 122,
BUTTON_RIGHT_TRIGGER = 123,
BUTTON_DPAD_UP = 130,
BUTTON_DPAD_DOWN = 131,
BUTTON_DPAD_LEFT = 132,
BUTTON_DPAD_RIGHT = 133,
BUTTON_DPAD_CENTER = 134,
BUTTON_LEFT_THUMBSTICK = 140,
BUTTON_RIGHT_THUMBSTICK = 141,
BUTTON_START = 150,
BUTTON_SELECT = 151,
};
class ControllerImpl
{
public:
ControllerImpl(Controller* controller)
: _controller(controller)
, _controllerID(-1)
{
}
static std::vector<Controller*>::iterator findController(const std::string& vendorName, int controllerID)
{
auto iter = std::find_if(Controller::_controllers.begin(), Controller::_controllers.end(), [&](Controller* controller){
return (vendorName == controller->getVendorName()) && (controllerID == controller->_impl->_controllerID);
});
}
static void onConnected(const std::string& vendorName, int controllerID)
{
// Check whether the controller is already connected.
auto iter = findController(vendorName, controllerID);
if (iter != Controller::_controllers.end())
return;
// It's a new controller being connected.
auto controller = new cocos2d::Controller();
controller->_vendorName = vendorName;
Controller::_controllers.push_back(controller);
controller->_impl->_controllerID = controllerID;
EventController evt(EventController::ControllerEventType::CONNECTION, controller, true);
Director::getInstance()->getEventDispatcher()->dispatchEvent(&evt);
}
static void onDisconnected(const std::string& vendorName, int controllerID)
{
auto iter = findController(vendorName, controllerID);
if (iter == Controller::_controllers.end())
{
CCLOGERROR("Could not find the controller!");
return;
}
EventController evt(EventController::ControllerEventType::CONNECTION, *iter, false);
Director::getInstance()->getEventDispatcher()->dispatchEvent(&evt);
Controller::_controllers.erase(iter);
}
void sendEventButton(ControllerButtonInput* button, bool isPressed, float value, bool isAnalog)
{
button->setPressed(isPressed);
if (!isAnalog)
button->setValue(value);
button->setAnalog(isAnalog);
EventController evt(EventController::ControllerEventType::BUTTON_STATUS_CHANGED, _controller, button);
Director::getInstance()->getEventDispatcher()->dispatchEvent(&evt);
}
void sendEventAxis(ControllerAxisInput* axis, float value, bool isAnalog)
{
axis->setValue(value);
axis->setAnalog(isAnalog);
EventController evt(EventController::ControllerEventType::AXIS_STATUS_CHANGED, _controller, axis);
Director::getInstance()->getEventDispatcher()->dispatchEvent(&evt);
}
static void onButtonEvent(const std::string& vendorName, int controllerID, AndroidControllerCode btnCode, bool isPressed, float value, bool isAnalog)
{
auto iter = findController(vendorName, controllerID);
if (iter == Controller::_controllers.end())
{
onConnected(vendorName, controllerID);
iter = findController(vendorName, controllerID);
}
auto gamepad = (*iter)->getGamepad();
auto thiz = (*iter)->getImpl();
switch(btnCode)
{
case AndroidControllerCode::BUTTON_A:
{
thiz->sendEventButton(gamepad->getButtonA(), isPressed, value, isAnalog);
}
break;
case AndroidControllerCode::BUTTON_B:
{
thiz->sendEventButton(gamepad->getButtonB(), isPressed, value, isAnalog);
}
break;
case AndroidControllerCode::BUTTON_X:
{
thiz->sendEventButton(gamepad->getButtonX(), isPressed, value, isAnalog);
}
break;
case AndroidControllerCode::BUTTON_Y:
{
thiz->sendEventButton(gamepad->getButtonY(), isPressed, value, isAnalog);
}
break;
case AndroidControllerCode::BUTTON_LEFT_SHOULDER:
{
thiz->sendEventButton(gamepad->getLeftShoulder(), isPressed, value, isAnalog);
}
break;
case AndroidControllerCode::BUTTON_RIGHT_SHOULDER:
{
thiz->sendEventButton(gamepad->getRightShoulder(), isPressed, value, isAnalog);
}
break;
case AndroidControllerCode::BUTTON_LEFT_TRIGGER:
{
thiz->sendEventButton(gamepad->getLeftTrigger(), isPressed, value, isAnalog);
}
break;
case AndroidControllerCode::BUTTON_RIGHT_TRIGGER:
{
thiz->sendEventButton(gamepad->getRightTrigger(), isPressed, value, isAnalog);
}
break;
case AndroidControllerCode::BUTTON_DPAD_UP:
{
thiz->sendEventButton(gamepad->getDirectionPad()->getUp(), isPressed, value, isAnalog);
}
break;
case AndroidControllerCode::BUTTON_DPAD_DOWN:
{
thiz->sendEventButton(gamepad->getDirectionPad()->getDown(), isPressed, value, isAnalog);
}
break;
case AndroidControllerCode::BUTTON_DPAD_LEFT:
{
thiz->sendEventButton(gamepad->getDirectionPad()->getLeft(), isPressed, value, isAnalog);
}
break;
case AndroidControllerCode::BUTTON_DPAD_RIGHT:
{
thiz->sendEventButton(gamepad->getDirectionPad()->getRight(), isPressed, value, isAnalog);
}
break;
case AndroidControllerCode::BUTTON_START:
{
thiz->sendEventButton(gamepad->getButtonStart(), isPressed, value, isAnalog);
}
break;
case AndroidControllerCode::BUTTON_SELECT:
{
thiz->sendEventButton(gamepad->getButtonSelect(), isPressed, value, isAnalog);
}
break;
case AndroidControllerCode::BUTTON_LEFT_THUMBSTICK:
{
thiz->sendEventButton(gamepad->getLeftThumbstick()->getButton(), isPressed, value, isAnalog);
}
break;
case AndroidControllerCode::BUTTON_RIGHT_THUMBSTICK:
{
thiz->sendEventButton(gamepad->getRightThumbstick()->getButton(), isPressed, value, isAnalog);
}
break;
default:
// CCASSERT(false, "Invalid controller button code!");
break;
}
}
static void onAxisEvent(const std::string& vendorName, int controllerID, AndroidControllerCode axisCode, float value, bool isAnalog)
{
// log("vendorName: %s, controller id: %d, axis: %d, value: %f", vendorName.c_str(), controllerID, axisCode, value);
auto iter = findController(vendorName, controllerID);
if (iter == Controller::_controllers.end())
{
onConnected(vendorName, controllerID);
iter = findController(vendorName, controllerID);
}
auto gamepad = (*iter)->getGamepad();
auto thiz = (*iter)->getImpl();
switch (axisCode)
{
case AndroidControllerCode::THUMBSTICK_LEFT_X:
thiz->sendEventAxis(gamepad->getLeftThumbstick()->getAxisX(), value, isAnalog);
break;
case AndroidControllerCode::THUMBSTICK_LEFT_Y:
thiz->sendEventAxis(gamepad->getLeftThumbstick()->getAxisY(), value, isAnalog);
break;
case AndroidControllerCode::THUMBSTICK_RIGHT_X:
thiz->sendEventAxis(gamepad->getRightThumbstick()->getAxisX(), value, isAnalog);
break;
case AndroidControllerCode::THUMBSTICK_RIGHT_Y:
thiz->sendEventAxis(gamepad->getRightThumbstick()->getAxisY(), value, isAnalog);
break;
default:
CCASSERT(false, "Invalid controller axis code!");
break;
}
}
private:
Controller* _controller;
int _controllerID;
};
std::vector<Controller*> Controller::_controllers;
const std::vector<Controller*>& Controller::getControllers()
{
return _controllers;
}
void Controller::startDiscoveryController()
{
// Empty implementation on Android
}
void Controller::stopDiscoveryController()
{
// Empty implementation on Android
}
const std::string& Controller::getVendorName()
{
return _vendorName;
}
bool Controller::isConnected() const
{
// If there is a controller instance, it means that the controller is connected.
// If a controller is disconnected, the instance will be destroyed.
// So always returns true for this method.
return true;
}
int Controller::getPlayerIndex() const
{
return _playerIndex;
}
void Controller::setPlayerIndex(int playerIndex)
{
_playerIndex = playerIndex;
}
Gamepad* Controller::getGamepad() const
{
return _gamepad;
}
Controller::Controller()
: _playerIndex(PLAYER_INDEX_UNSET)
, _gamepad(new Gamepad)
, _impl(new ControllerImpl(this))
{
_gamepad->_controller = this;
}
Controller::~Controller()
{
CC_SAFE_DELETE(_impl);
CC_SAFE_DELETE(_gamepad);
}
NS_CC_END
extern "C" {
JNIEXPORT void JNICALL Java_org_cocos2dx_lib_GameControllerAdapter_nativeControllerConnected(JNIEnv* env, jobject thiz, jstring vendorName, jint controllerID)
{
CCLOG("controller id: %d connected!", controllerID);
cocos2d::ControllerImpl::onConnected(cocos2d::JniHelper::jstring2string(vendorName), controllerID);
}
JNIEXPORT void JNICALL Java_org_cocos2dx_lib_GameControllerAdapter_nativeControllerDisconnected(JNIEnv* env, jobject thiz, jstring vendorName, jint controllerID)
{
CCLOG("controller id: %d disconnected!", controllerID);
cocos2d::ControllerImpl::onDisconnected(cocos2d::JniHelper::jstring2string(vendorName), controllerID);
}
JNIEXPORT void JNICALL Java_org_cocos2dx_lib_GameControllerAdapter_nativeControllerButtonEvent(JNIEnv* env, jobject thiz, jstring vendorName, jint controllerID, jint button, jboolean isPressed, jfloat value, jboolean isAnalog)
{
CCLOG("controller id: %d, btn code: %d, isPressed: %d, value: %f, isAnalog:%d", controllerID, button, (int)isPressed, value, (int)isAnalog);
cocos2d::ControllerImpl::onButtonEvent(cocos2d::JniHelper::jstring2string(vendorName), controllerID, static_cast<cocos2d::AndroidControllerCode>(button), isPressed, value, isAnalog);
}
JNIEXPORT void JNICALL Java_org_cocos2dx_lib_GameControllerAdapter_nativeControllerAxisEvent(JNIEnv* env, jobject thiz, jstring vendorName, jint controllerID, jint axis, jfloat value, jboolean isAnalog)
{
// CCLOG("controller id: %d, axis code: %d, value: %f, isAnalog:%d", controllerID, axis, value, (int)isAnalog);
cocos2d::ControllerImpl::onAxisEvent(cocos2d::JniHelper::jstring2string(vendorName), controllerID, static_cast<cocos2d::AndroidControllerCode>(axis), value, isAnalog);
}
} // extern "C" {
#endif // #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>libcontrollerdelegate</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,4 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.source=1.6

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.cocos2dx.lib"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="10"/>
</manifest>

View File

@ -0,0 +1,17 @@
# This file is used to override default values used by the Ant build system.
#
# This file must be checked into Version Control Systems, as it is
# integral to the build system of your project.
# This file is only used by the Ant script.
# You can use this to override default values such as
# 'source.dir' for the location of your java source folder and
# 'out.dir' for the location of your output folder.
# You can also use it define how the release builds are signed by declaring
# the following properties:
# 'key.store' for the location of your keystore and
# 'key.alias' for the name of the key to use.
# The password will be asked during the build when you use the 'release' target.

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="androidcontrollerdelegate" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

View File

@ -0,0 +1,20 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,55 @@
package org.cocos2dx.lib;
import android.content.Context;
import android.view.KeyEvent;
import android.view.MotionEvent;
public interface GameControllerDelegate {
public static final int THUMBSTICK_LEFT_X = 100;
public static final int THUMBSTICK_LEFT_Y = 101;
public static final int THUMBSTICK_RIGHT_X = 102;
public static final int THUMBSTICK_RIGHT_Y = 103;
public static final int BUTTON_A = 110;
public static final int BUTTON_B = 111;
public static final int BUTTON_C = 112;
public static final int BUTTON_X = 113;
public static final int BUTTON_Y = 114;
public static final int BUTTON_Z = 115;
public static final int BUTTON_LEFT_SHOULDER = 120;
public static final int BUTTON_RIGHT_SHOULDER = 121;
public static final int BUTTON_LEFT_TRIGGER = 122;
public static final int BUTTON_RIGHT_TRIGGER = 123;
public static final int BUTTON_DPAD_UP = 130;
public static final int BUTTON_DPAD_DOWN = 131;
public static final int BUTTON_DPAD_LEFT = 132;
public static final int BUTTON_DPAD_RIGHT = 133;
public static final int BUTTON_DPAD_CENTER = 134;
public static final int BUTTON_LEFT_THUMBSTICK = 140;
public static final int BUTTON_RIGHT_THUMBSTICK = 141;
public static final int BUTTON_START = 150;
public static final int BUTTON_SELECT = 151;
void onCreate(Context context);
void onPause();
void onResume();
void onDestroy();
boolean dispatchKeyEvent(KeyEvent event);
boolean dispatchGenericMotionEvent(MotionEvent event);
void setControllerEventListener(ControllerEventListener listener);
public interface ControllerEventListener {
void onButtonEvent(String vendorName, int controller, int button, boolean isPressed, float value, boolean isAnalog);
void onAxisEvent(String vendorName, int controller, int axisID, float value, boolean isAnalog);
void onConnected(String vendorName, int controller);
void onDisconnected(String vendorName, int controller);
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>libcontrollermoga</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,4 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.source=1.6

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.cocos2dx.lib"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="10"/>
</manifest>

View File

@ -0,0 +1,17 @@
# This file is used to override default values used by the Ant build system.
#
# This file must be checked into Version Control Systems, as it is
# integral to the build system of your project.
# This file is only used by the Ant script.
# You can use this to override default values such as
# 'source.dir' for the location of your java source folder and
# 'out.dir' for the location of your output folder.
# You can also use it define how the release builds are signed by declaring
# the following properties:
# 'key.store' for the location of your keystore and
# 'key.alias' for the name of the key to use.
# The password will be asked during the build when you use the 'release' target.

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="androidcontrollermoga" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

View File

@ -0,0 +1,23 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-libraryjars com.bda.controller.jar
-dontwarn com.bda.controller.*
-keep class org.cocos2dx.lib.*{*;}

View File

View File

@ -0,0 +1,191 @@
package org.cocos2dx.lib;
import org.cocos2dx.lib.GameControllerDelegate;
import android.content.Context;
import android.os.Handler;
import android.util.SparseIntArray;
import com.bda.controller.Controller;
import com.bda.controller.ControllerListener;
import com.bda.controller.KeyEvent;
import com.bda.controller.MotionEvent;
import com.bda.controller.StateEvent;
public class GameControllerMoga implements ControllerListener, GameControllerDelegate {
private static final String mVendorName = "Moga";
private float mOldLeftThumbstickX = 0.0f;
private float mOldLeftThumbstickY = 0.0f;
private float mOldRightThumbstickX = 0.0f;
private float mOldRightThumbstickY = 0.0f;
private SparseIntArray mKeyMap = null;
public GameControllerMoga() {
mKeyMap = new SparseIntArray(20);
mKeyMap.put(KeyEvent.KEYCODE_BUTTON_A, GameControllerDelegate.BUTTON_A);
mKeyMap.put(KeyEvent.KEYCODE_BUTTON_B, GameControllerDelegate.BUTTON_B);
mKeyMap.put(KeyEvent.KEYCODE_BUTTON_X, GameControllerDelegate.BUTTON_X);
mKeyMap.put(KeyEvent.KEYCODE_BUTTON_Y, GameControllerDelegate.BUTTON_Y);
mKeyMap.put(KeyEvent.KEYCODE_BUTTON_L1,
GameControllerDelegate.BUTTON_LEFT_SHOULDER);
mKeyMap.put(KeyEvent.KEYCODE_BUTTON_R1,
GameControllerDelegate.BUTTON_RIGHT_SHOULDER);
mKeyMap.put(KeyEvent.KEYCODE_BUTTON_L2,
GameControllerDelegate.BUTTON_LEFT_TRIGGER);
mKeyMap.put(KeyEvent.KEYCODE_BUTTON_R2,
GameControllerDelegate.BUTTON_RIGHT_TRIGGER);
mKeyMap.put(KeyEvent.KEYCODE_DPAD_UP,
GameControllerDelegate.BUTTON_DPAD_UP);
mKeyMap.put(KeyEvent.KEYCODE_DPAD_DOWN,
GameControllerDelegate.BUTTON_DPAD_DOWN);
mKeyMap.put(KeyEvent.KEYCODE_DPAD_LEFT,
GameControllerDelegate.BUTTON_DPAD_LEFT);
mKeyMap.put(KeyEvent.KEYCODE_DPAD_RIGHT,
GameControllerDelegate.BUTTON_DPAD_RIGHT);
mKeyMap.put(KeyEvent.KEYCODE_BUTTON_START,
GameControllerDelegate.BUTTON_START);
mKeyMap.put(KeyEvent.KEYCODE_BUTTON_SELECT,
GameControllerDelegate.BUTTON_SELECT);
mKeyMap.put(KeyEvent.KEYCODE_BUTTON_START,
GameControllerDelegate.BUTTON_START);
mKeyMap.put(KeyEvent.KEYCODE_BUTTON_THUMBL,
GameControllerDelegate.BUTTON_LEFT_THUMBSTICK);
mKeyMap.put(KeyEvent.KEYCODE_BUTTON_THUMBR,
GameControllerDelegate.BUTTON_RIGHT_THUMBSTICK);
}
public void onKeyEvent(KeyEvent event) {
boolean isPressed = event.getAction() == KeyEvent.ACTION_DOWN;
int keycode = event.getKeyCode();
boolean isAnalog = false;
if (keycode == KeyEvent.KEYCODE_BUTTON_THUMBL
|| keycode == KeyEvent.KEYCODE_BUTTON_THUMBR) {
isAnalog = true;
}
if (mKeyMap.get(keycode, Integer.MIN_VALUE) != Integer.MIN_VALUE && mControllerEventListener != null) {
mControllerEventListener.onButtonEvent(mVendorName,
event.getControllerId(), mKeyMap.get(keycode), isPressed,
isPressed ? 1.0f : 0.0f, isAnalog);
}
}
@Override
public void onMotionEvent(MotionEvent event) {
if (mControllerEventListener == null) {
return;
}
float newLeftThumbstickX = event.getAxisValue(MotionEvent.AXIS_X);
if (newLeftThumbstickX != mOldLeftThumbstickX) {
mControllerEventListener.onAxisEvent(mVendorName,
event.getControllerId(),
GameControllerDelegate.THUMBSTICK_LEFT_X,
newLeftThumbstickX, true);
mOldLeftThumbstickX = newLeftThumbstickX;
}
float newLeftThumbstickY = event.getAxisValue(MotionEvent.AXIS_Y);
if (newLeftThumbstickY != mOldLeftThumbstickY) {
mControllerEventListener.onAxisEvent(mVendorName,
event.getControllerId(),
GameControllerDelegate.THUMBSTICK_LEFT_Y,
newLeftThumbstickY, true);
mOldLeftThumbstickY = newLeftThumbstickY;
}
float newRightThumbstickX = event.getAxisValue(MotionEvent.AXIS_Z);
if (newRightThumbstickX != mOldRightThumbstickX) {
mControllerEventListener.onAxisEvent(mVendorName,
event.getControllerId(),
GameControllerDelegate.THUMBSTICK_RIGHT_X,
newRightThumbstickX, true);
mOldRightThumbstickX = newRightThumbstickX;
}
float newRightThumbstickY = event.getAxisValue(MotionEvent.AXIS_RZ);
if (newRightThumbstickY != mOldRightThumbstickY) {
mControllerEventListener.onAxisEvent(mVendorName,
event.getControllerId(),
GameControllerDelegate.THUMBSTICK_RIGHT_Y,
newRightThumbstickY, true);
mOldRightThumbstickY = newRightThumbstickY;
}
}
@Override
public void onStateEvent(StateEvent event) {
if (mControllerEventListener != null) {
switch (event.getState()) {
case StateEvent.STATE_CONNECTION:
switch (event.getAction()) {
case StateEvent.ACTION_DISCONNECTED:
// disconnected from controller
mControllerEventListener.onDisconnected(mVendorName,
event.getControllerId());
break;
case StateEvent.ACTION_CONNECTED:
// connected to controller
mControllerEventListener.onConnected(mVendorName,
event.getControllerId());
break;
case StateEvent.ACTION_CONNECTING:
// attempting to connect to controller
break;
}
break;
case StateEvent.STATE_POWER_LOW:
if (event.getAction() == StateEvent.ACTION_TRUE) {
// controller has entered low power state
} else {
// controller has entered normal power state
}
break;
}
}
}
private Controller mController = null;
public void onCreate(Context context) {
mController = Controller.getInstance(context);
mController.init();
mController.setListener(this, new Handler());
}
public void onPause() {
mController.onPause();
}
public void onResume() {
mController.onResume();
}
public void onDestroy() {
mController.exit();
}
private ControllerEventListener mControllerEventListener;
@Override
public void setControllerEventListener(ControllerEventListener listener) {
mControllerEventListener = listener;
}
@Override
public boolean dispatchKeyEvent(android.view.KeyEvent event) {
return false;
}
@Override
public boolean dispatchGenericMotionEvent(android.view.MotionEvent event) {
return false;
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>libcontrollernibiru</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,4 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.source=1.6

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.cocos2dx.lib"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="10"/>
</manifest>

View File

@ -0,0 +1,17 @@
# This file is used to override default values used by the Ant build system.
#
# This file must be checked into Version Control Systems, as it is
# integral to the build system of your project.
# This file is only used by the Ant script.
# You can use this to override default values such as
# 'source.dir' for the location of your java source folder and
# 'out.dir' for the location of your output folder.
# You can also use it define how the release builds are signed by declaring
# the following properties:
# 'key.store' for the location of your keystore and
# 'key.alias' for the name of the key to use.
# The password will be asked during the build when you use the 'release' target.

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="androidcontrollernibiru" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

View File

@ -0,0 +1,20 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

View File

@ -0,0 +1,209 @@
package org.cocos2dx.lib;
import org.cocos2dx.lib.GameControllerDelegate;
import com.nibiru.lib.controller.AccEvent;
import com.nibiru.lib.controller.Controller;
import com.nibiru.lib.controller.ControllerDevice;
import com.nibiru.lib.controller.ControllerKeyEvent;
import com.nibiru.lib.controller.ControllerService;
import com.nibiru.lib.controller.ControllerService.OnControllerSeviceListener;
import com.nibiru.lib.controller.ControllerServiceException;
import com.nibiru.lib.controller.GyroEvent;
import com.nibiru.lib.controller.OnAccListener;
import com.nibiru.lib.controller.OnGyroListener;
import com.nibiru.lib.controller.OnKeyListener;
import com.nibiru.lib.controller.OnSimpleStickListener;
import com.nibiru.lib.controller.OnStateListener;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.KeyEvent;
import android.view.MotionEvent;
public class GameControllerNibiru implements OnControllerSeviceListener, OnKeyListener,
OnSimpleStickListener, OnAccListener, OnGyroListener, OnStateListener, GameControllerDelegate {
private static final String TAG = "NibiruTag";
private static final String mVendorName = "Nibiru";
private Context mContext;
private SparseIntArray mKeyMap;
private ControllerEventListener mControllerEventListener = null;
private ControllerService mControllerService = null;
public GameControllerNibiru() {
mKeyMap = new SparseIntArray(20);
mKeyMap.put(ControllerKeyEvent.KEYCODE_BUTTON_A , GameControllerDelegate.BUTTON_A);
mKeyMap.put(ControllerKeyEvent.KEYCODE_BUTTON_B , GameControllerDelegate.BUTTON_B);
mKeyMap.put(ControllerKeyEvent.KEYCODE_BUTTON_X , GameControllerDelegate.BUTTON_X);
mKeyMap.put(ControllerKeyEvent.KEYCODE_BUTTON_Y , GameControllerDelegate.BUTTON_Y);
mKeyMap.put(ControllerKeyEvent.KEYCODE_BUTTON_L1 , GameControllerDelegate.BUTTON_LEFT_SHOULDER);
mKeyMap.put(ControllerKeyEvent.KEYCODE_BUTTON_R1 , GameControllerDelegate.BUTTON_RIGHT_SHOULDER);
mKeyMap.put(ControllerKeyEvent.KEYCODE_BUTTON_L2, GameControllerDelegate.BUTTON_LEFT_TRIGGER);
mKeyMap.put(ControllerKeyEvent.KEYCODE_BUTTON_R2, GameControllerDelegate.BUTTON_RIGHT_TRIGGER);
mKeyMap.put(ControllerKeyEvent.KEYCODE_UP , GameControllerDelegate.BUTTON_DPAD_UP);
mKeyMap.put(ControllerKeyEvent.KEYCODE_DOWN , GameControllerDelegate.BUTTON_DPAD_DOWN);
mKeyMap.put(ControllerKeyEvent.KEYCODE_LEFT , GameControllerDelegate.BUTTON_DPAD_LEFT);
mKeyMap.put(ControllerKeyEvent.KEYCODE_RIGHT , GameControllerDelegate.BUTTON_DPAD_RIGHT);
mKeyMap.put(ControllerKeyEvent.KEYCODE_BUTTON_START , GameControllerDelegate.BUTTON_START);
mKeyMap.put(ControllerKeyEvent.KEYCODE_BUTTON_SELECT , GameControllerDelegate.BUTTON_SELECT);
mKeyMap.put(ControllerKeyEvent.KEYCODE_BUTTON_THUMBL , GameControllerDelegate.BUTTON_LEFT_THUMBSTICK);
mKeyMap.put(ControllerKeyEvent.KEYCODE_BUTTON_THUMBR , GameControllerDelegate.BUTTON_RIGHT_THUMBSTICK);
}
@Override
public void setControllerEventListener(ControllerEventListener listener) {
mControllerEventListener = listener;
}
public void onCreate(Context context) {
mContext = context;
mControllerService = Controller.getControllerService();
if (mControllerService != null) {
mControllerService.setControllerServiceListener(this);
mControllerService.setStateListener(this);
mControllerService.setKeyListener(this);
mControllerService.setSimpleStickListener(this);
//mControllerService.setAccListener(this);
//mControllerService.setGyroListener(this);
mControllerService.setEnableLR2(true);
mControllerService.setAutoKeyUpMode(false);
mControllerService.checkNibiruInstall(mContext, true);
}
}
public void onPause() {
if (mControllerService != null) {
mControllerService.setEnable(false);
}
}
public void onResume() {
if (mControllerService != null) {
if (mControllerService.isServiceEnable()) {
//onControllerServiceReady(true);
} else {
if (mControllerService.checkNibiruInstall(mContext, false)) {
try {
mControllerService.register(mContext);
} catch (ControllerServiceException e) {
e.printStackTrace();
}
}
}
mControllerService.setEnable(true);
}
}
public void onDestroy() {
if( mControllerService != null ){
mControllerService.unregister();
}
}
@Override
public void onControllerServiceReady(boolean isSucc) {
if( isSucc )
{
if( !mControllerService.hasDeviceConnected() ){
Bundle bun = new Bundle();
bun.putBoolean(ControllerService.FLAG_IS_SHOW_GAMEPAD_TIP, true);
try {
mControllerService.showDeviceManagerUI(mContext, bun);
} catch (ControllerServiceException e) {
e.printStackTrace();
}
}
}
}
@Override
public void onControllerKeyDown(int playerOrder, int keyCode, ControllerKeyEvent event) {
if (mKeyMap.get(keyCode) == 0) {
Log.e(TAG, "Didn't map the key: " + keyCode);
return;
}
if (mControllerEventListener != null) {
mControllerEventListener.onButtonEvent(mVendorName, playerOrder, mKeyMap.get(keyCode), true, 1.0f, false);
}
}
@Override
public void onControllerKeyUp(int playerOrder, int keyCode, ControllerKeyEvent event) {
if (mKeyMap.get(keyCode) == 0) {
Log.e(TAG, "Didn't map the key: " + keyCode);
return;
}
if (mControllerEventListener != null) {
mControllerEventListener.onButtonEvent(mVendorName, playerOrder,
mKeyMap.get(keyCode), false, 0.0f, false);
}
}
@Override
public void onLeftStickChanged(int playerOrder, float x, float y) {
if (mControllerEventListener != null) {
mControllerEventListener.onAxisEvent(mVendorName, playerOrder,
GameControllerDelegate.THUMBSTICK_LEFT_X, x, true);
mControllerEventListener.onAxisEvent(mVendorName, playerOrder,
GameControllerDelegate.THUMBSTICK_LEFT_Y, y, true);
}
}
@Override
public void onRightStickChanged(int playerOrder, float x, float y) {
if (mControllerEventListener != null) {
mControllerEventListener.onAxisEvent(mVendorName, playerOrder,
GameControllerDelegate.THUMBSTICK_RIGHT_X, x, true);
mControllerEventListener.onAxisEvent(mVendorName, playerOrder,
GameControllerDelegate.THUMBSTICK_RIGHT_Y, y, true);
}
}
@Override
public void onControllerStateChanged(int playerOrder, int state, ControllerDevice device) {
if (mControllerEventListener != null) {
if (state == ControllerDevice.STATE_CONN)
{
mControllerEventListener.onConnected(mVendorName, playerOrder);
}
else if (state == ControllerDevice.STATE_DISCONN)
{
mControllerEventListener.onDisconnected(mVendorName, playerOrder);
}
}
}
public boolean dispatchGenericMotionEvent(MotionEvent event){
return mControllerService.handleExternalInput(event);
}
public boolean dispatchKeyEvent(KeyEvent event){
return mControllerService.handleExternalInput(event);
}
@Override
public void onControllerAccEvent(int playerOrder, AccEvent event) {
}
@Override
public void onControllerGyroEvent(int playerOrder, GyroEvent event) {
}
@Override
public void onBluetoothStateChanged(int state) {
Log.d(TAG, "onBluetoothStateChanged:"+state);
}
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>libcontrollerouya</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,4 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.source=1.6

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.cocos2dx.lib"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="10"/>
</manifest>

View File

@ -0,0 +1,17 @@
# This file is used to override default values used by the Ant build system.
#
# This file must be checked into Version Control Systems, as it is
# integral to the build system of your project.
# This file is only used by the Ant script.
# You can use this to override default values such as
# 'source.dir' for the location of your java source folder and
# 'out.dir' for the location of your output folder.
# You can also use it define how the release builds are signed by declaring
# the following properties:
# 'key.store' for the location of your keystore and
# 'key.alias' for the name of the key to use.
# The password will be asked during the build when you use the 'release' target.

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="androidcontrollerouya" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

View File

@ -0,0 +1,20 @@
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

View File

@ -0,0 +1,182 @@
package org.cocos2dx.lib;
import org.cocos2dx.lib.GameControllerDelegate;
import tv.ouya.console.api.OuyaController;
import android.content.Context;
import android.util.SparseIntArray;
import android.view.KeyEvent;
import android.view.MotionEvent;
public class GameControllerOuya implements GameControllerDelegate{
public static final String sVendorName = "Ouya";
private SparseIntArray mKeyMap;
public GameControllerOuya(){
mKeyMap = new SparseIntArray(20);
mKeyMap.put(OuyaController.BUTTON_A, GameControllerDelegate.BUTTON_B);
mKeyMap.put(OuyaController.BUTTON_O, GameControllerDelegate.BUTTON_A);
mKeyMap.put(OuyaController.BUTTON_U, GameControllerDelegate.BUTTON_X);
mKeyMap.put(OuyaController.BUTTON_Y, GameControllerDelegate.BUTTON_Y);
mKeyMap.put(OuyaController.BUTTON_DPAD_DOWN, GameControllerDelegate.BUTTON_DPAD_DOWN);
mKeyMap.put(OuyaController.BUTTON_DPAD_LEFT, GameControllerDelegate.BUTTON_DPAD_LEFT);
mKeyMap.put(OuyaController.BUTTON_DPAD_RIGHT, GameControllerDelegate.BUTTON_DPAD_RIGHT);
mKeyMap.put(OuyaController.BUTTON_DPAD_UP, GameControllerDelegate.BUTTON_DPAD_UP);
mKeyMap.put(OuyaController.BUTTON_L1, GameControllerDelegate.BUTTON_LEFT_SHOULDER);
mKeyMap.put(OuyaController.BUTTON_R1, GameControllerDelegate.BUTTON_RIGHT_SHOULDER);
mKeyMap.put(OuyaController.AXIS_L2, GameControllerDelegate.BUTTON_LEFT_TRIGGER);
mKeyMap.put(OuyaController.AXIS_R2, GameControllerDelegate.BUTTON_RIGHT_TRIGGER);
mKeyMap.put(OuyaController.AXIS_LS_X, GameControllerDelegate.BUTTON_LEFT_THUMBSTICK);
mKeyMap.put(OuyaController.AXIS_LS_Y, GameControllerDelegate.BUTTON_LEFT_THUMBSTICK);
mKeyMap.put(OuyaController.AXIS_RS_X, GameControllerDelegate.BUTTON_RIGHT_THUMBSTICK);
mKeyMap.put(OuyaController.AXIS_RS_Y, GameControllerDelegate.BUTTON_RIGHT_THUMBSTICK);
}
public void onCreate(Context context) {
OuyaController.init(context);
/*GameControllerAdapter.addRunnableToFrameStartList(new Runnable() {
@Override
public void run() {
OuyaController.startOfFrame();
}
});*/
}
private float mOldLeftThumbstickX = 0.0f;
private float mOldLeftThumbstickY = 0.0f;
private float mOldRightThumbstickX = 0.0f;
private float mOldRightThumbstickY = 0.0f;
private float mOldLeftTrigger = 0.0f;
private float mOldRightTrigger = 0.0f;
public boolean dispatchGenericMotionEvent(MotionEvent event) {
boolean handled = OuyaController.onGenericMotionEvent(event);
if (handled && mControllerEventListener != null)
{
OuyaController c = OuyaController.getControllerByDeviceId(event.getDeviceId());
int controllerID = OuyaController.getPlayerNumByDeviceId(event.getDeviceId());
float newLeftTrigger = c.getAxisValue(OuyaController.AXIS_L2);
if (Float.compare(newLeftTrigger, mOldLeftTrigger) != 0) {
if (Float.compare(newLeftTrigger, 0.0f) == 0) {
mControllerEventListener.onButtonEvent(sVendorName, controllerID, GameControllerDelegate.BUTTON_LEFT_TRIGGER, false, 0.0f, true);
}else {
mControllerEventListener.onButtonEvent(sVendorName, controllerID, GameControllerDelegate.BUTTON_LEFT_TRIGGER, true, newLeftTrigger, true);
}
mOldLeftTrigger = newLeftTrigger;
}
float newRightTrigger = c.getAxisValue(OuyaController.AXIS_R2);
if (Float.compare(newRightTrigger, mOldRightTrigger) != 0) {
if (Float.compare(newRightTrigger, 0.0f) == 0) {
mControllerEventListener.onButtonEvent(sVendorName, controllerID, GameControllerDelegate.BUTTON_RIGHT_TRIGGER, false, 0.0f, true);
}else {
mControllerEventListener.onButtonEvent(sVendorName, controllerID, GameControllerDelegate.BUTTON_RIGHT_TRIGGER, true, newRightTrigger, true);
}
mOldRightTrigger = newRightTrigger;
}
float newLeftThumbstickX = c.getAxisValue(OuyaController.AXIS_LS_X);
if (Float.compare(newLeftThumbstickX, mOldLeftThumbstickX) != 0) {
if (Float.compare(newLeftThumbstickX, 0.0f) == 0) {
mControllerEventListener.onAxisEvent(sVendorName, controllerID, GameControllerDelegate.THUMBSTICK_LEFT_X, 0.0f, true);
}else {
mControllerEventListener.onAxisEvent(sVendorName, controllerID, GameControllerDelegate.THUMBSTICK_LEFT_X, newLeftThumbstickX, true);
}
mOldLeftThumbstickX = newLeftThumbstickX;
}
float newLeftThumbstickY = c.getAxisValue(OuyaController.AXIS_LS_Y);
if (Float.compare(newLeftThumbstickY, mOldLeftThumbstickY) != 0) {
if (Float.compare(newLeftThumbstickY, 0.0f) == 0) {
mControllerEventListener.onAxisEvent(sVendorName, controllerID, GameControllerDelegate.THUMBSTICK_LEFT_Y, 0.0f, true);
}else {
mControllerEventListener.onAxisEvent(sVendorName, controllerID, GameControllerDelegate.THUMBSTICK_LEFT_Y, newLeftThumbstickY, true);
}
mOldLeftThumbstickY = newLeftThumbstickY;
}
float newRightThumbstickX = c.getAxisValue(OuyaController.AXIS_RS_X);
if (Float.compare(newRightThumbstickX, mOldRightThumbstickX) != 0) {
if (Float.compare(newRightThumbstickX, 0.0f) == 0) {
mControllerEventListener.onAxisEvent(sVendorName, controllerID, GameControllerDelegate.THUMBSTICK_RIGHT_X, 0.0f, true);
}else {
mControllerEventListener.onAxisEvent(sVendorName, controllerID, GameControllerDelegate.THUMBSTICK_RIGHT_X, newRightThumbstickX, true);
}
mOldRightThumbstickX = newRightThumbstickX;
}
float newRightThumbstickY = c.getAxisValue(OuyaController.AXIS_RS_Y);
if (Float.compare(newRightThumbstickY, mOldRightThumbstickY) != 0) {
if (Float.compare(newRightThumbstickY, 0.0f) == 0) {
mControllerEventListener.onAxisEvent(sVendorName, controllerID, GameControllerDelegate.THUMBSTICK_RIGHT_Y, 0.0f, true);
}else {
mControllerEventListener.onAxisEvent(sVendorName, controllerID, GameControllerDelegate.THUMBSTICK_RIGHT_Y, newRightThumbstickY, true);
}
mOldRightThumbstickY = newRightThumbstickY;
}
}
return handled;
}
public boolean dispatchKeyEvent(KeyEvent event) {
boolean handled = false;
int action = event.getAction();
int keyCode = event.getKeyCode();
if (action == KeyEvent.ACTION_DOWN) {
handled = OuyaController.onKeyDown(keyCode, event);
}
else if (action == KeyEvent.ACTION_UP) {
handled = OuyaController.onKeyUp(keyCode, event);
}
if (handled && mControllerEventListener != null) {
boolean isAnalog = false;
if (keyCode == KeyEvent.KEYCODE_BUTTON_THUMBL || keyCode == KeyEvent.KEYCODE_BUTTON_THUMBR){
isAnalog = true;
}
int controllerID = OuyaController.getPlayerNumByDeviceId(event.getDeviceId());
if (action == KeyEvent.ACTION_DOWN) {
mControllerEventListener.onButtonEvent(sVendorName, controllerID, mKeyMap.get(keyCode), true, 1.0f, isAnalog);
}else {
mControllerEventListener.onButtonEvent(sVendorName, controllerID, mKeyMap.get(keyCode), false, 0.0f, isAnalog);
}
}
return handled;
}
public void onPause() {
// show the mouse cursor
OuyaController.showCursor(true);
}
public void onResume() {
// hide the mouse cursor
OuyaController.showCursor(false);
}
public void onDestroy() {
}
private ControllerEventListener mControllerEventListener;
@Override
public void setControllerEventListener(ControllerEventListener listener) {
mControllerEventListener = listener;
}
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<lint>
<issue id="InlinedApi">
<ignore path="src/org/cocos2dx/lib/GameControllerHelper.java" />
</issue>
<issue id="NewApi">
<ignore path="src/org/cocos2dx/lib/Cocos2dxActivity.java" />
<ignore path="src/org/cocos2dx/lib/GameControllerHelper.java" />
</issue>
</lint>

View File

@ -0,0 +1,77 @@
package org.cocos2dx.lib;
import java.util.ArrayList;
public class GameControllerAdapter {
private static ArrayList<Runnable> sRunnableFrameStartList = null;
public static void addRunnableToFrameStartList(Runnable runnable) {
if (sRunnableFrameStartList == null)
sRunnableFrameStartList = new ArrayList<Runnable>();
sRunnableFrameStartList.add(runnable);
}
public static void removeRunnableFromFrameStartList(Runnable runnable) {
if (sRunnableFrameStartList != null)
sRunnableFrameStartList.remove(runnable);
}
public static void onDrawFrameStart() {
if (sRunnableFrameStartList != null)
{
int size = sRunnableFrameStartList.size();
for (int i = 0; i < size; ++i) {
sRunnableFrameStartList.get(i).run();
}
}
}
public static void onConnected(final String vendorName, final int controller)
{
Cocos2dxHelper.runOnGLThread(new Runnable() {
@Override
public void run() {
nativeControllerConnected(vendorName, controller);
}
});
}
public static void onDisconnected(final String vendorName, final int controller)
{
Cocos2dxHelper.runOnGLThread(new Runnable() {
@Override
public void run() {
nativeControllerDisconnected(vendorName, controller);
}
});
}
public static void onButtonEvent(final String vendorName, final int controller, final int button, final boolean isPressed, final float value, final boolean isAnalog)
{
Cocos2dxHelper.runOnGLThread(new Runnable() {
@Override
public void run() {
nativeControllerButtonEvent(vendorName, controller, button, isPressed, value, isAnalog);
}
});
}
public static void onAxisEvent(final String vendorName, final int controller, final int axisID, final float value, final boolean isAnalog)
{
Cocos2dxHelper.runOnGLThread(new Runnable() {
@Override
public void run() {
nativeControllerAxisEvent(vendorName, controller, axisID, value, isAnalog);
}
});
}
private static native void nativeControllerConnected(final String vendorName, final int controller);
private static native void nativeControllerDisconnected(final String vendorName, final int controller);
private static native void nativeControllerButtonEvent(final String vendorName, final int controller, final int button, final boolean isPressed, final float value, final boolean isAnalog);
private static native void nativeControllerAxisEvent(final String vendorName, final int controller, final int axisID, final float value, final boolean isAnalog);
}

View File

@ -0,0 +1,870 @@
package org.cocos2dx.lib;
import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.json.JSONArray;
import org.json.JSONObject;
import org.apache.http.Header;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.FileAsyncHttpResponseHandler;
import com.loopj.android.http.JsonHttpResponseHandler;
import dalvik.system.DexClassLoader;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Environment;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.widget.Toast;
public class GameControllerHelper {
private final static String TAG = GameControllerHelper.class.getSimpleName();
public static final String StandardControllerName = "Standard";
public static final String[] DRIVERS_NAME = {"nibiru","moga","ouya",StandardControllerName};
public static final int DRIVERTYPE_NIBIRU = 0;
public static final int DRIVERTYPE_MOGA = 1;
public static final int DRIVERTYPE_OUYA = 2;
public static final int DRIVERTYPE_STANDARD = 3;
public static final int DRIVERTYPE_UNKNOWN = 4;
public static final String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";
SparseIntArray ControllerKeyMap;
private static final String COCOS_CONTROLLER_URL = "http://115.28.134.83:9000/download/cocoscontroller/";
private static final String COCOS_CONTROLLER_CONFIG = "controller.json";
private static final String NIBIRU_DEP_PACKAGE = "com.nibiru";
private static final String MOGA__DEP_PACKAGE = "com.bda.pivot.mogapgp";
private static Cocos2dxActivity sCocos2dxActivity;
private static GameControllerHelper sControllerHelper;
private List<String> mNibiruSupportedDrives;
private String mNibiruDepFileName;
private String mNibiruLibFileName;
private int mNibiruLibFileSize;
private int mNibiruDepFileSize;
private List<String> mMogaSupportedDrives;
private String mMogaDepFileName;
private String mMogaLibFileName;
private int mMogaLibFileSize;
private int mMogaDepFileSize;
private List<String> mOuyaSupportedDrives;
private String mOuyaLibFileName;
private int mOuyaLibFileSize;
private AsyncHttpClient mDownDepsHttpClient = null;
private BluetoothAdapter mBluetoothAdapter = null;
private ArrayList<BluetoothDevice> mBluetoothDevices = null;
private SparseIntArray mDevicesDriver;
private int mClearDevices = 0;
private String mConfigFilePath;
private String mLocalSavePath = null;
private boolean mLazyInit = true;
private boolean mLazyConfigInit = true;
private static ControllerListener mControllerListener = null;
public static interface ControllerListener{
void onDownloadConfigStarted();
void onDownloadConfigFinished(boolean isSuccess);
void onControllerDiscoveryStarted();
//
void onControllerDiscoveryFinish(ArrayList<BluetoothDevice> devices);
void onDownloadDepsStarted();
void onDownloadDepsProgress(int bytesWritten, int totalSize);
void onDownloadDepsFinished(boolean isSuccess);
void onInstallDriver(String filePath);
void onConnectController();
}
public void setControllerListener(ControllerListener listener){
mControllerListener = listener;
}
public GameControllerHelper(Cocos2dxActivity activity){
sCocos2dxActivity = activity;
sControllerHelper = this;
ControllerKeyMap = new SparseIntArray(25);
ControllerKeyMap.put(KeyEvent.KEYCODE_BUTTON_A, GameControllerDelegate.BUTTON_A);
ControllerKeyMap.put(KeyEvent.KEYCODE_BUTTON_B, GameControllerDelegate.BUTTON_B);
ControllerKeyMap.put(KeyEvent.KEYCODE_BUTTON_C, GameControllerDelegate.BUTTON_C);
ControllerKeyMap.put(KeyEvent.KEYCODE_BUTTON_X, GameControllerDelegate.BUTTON_X);
ControllerKeyMap.put(KeyEvent.KEYCODE_BUTTON_Y, GameControllerDelegate.BUTTON_Y);
ControllerKeyMap.put(KeyEvent.KEYCODE_BUTTON_Z, GameControllerDelegate.BUTTON_Z);
ControllerKeyMap.put(KeyEvent.KEYCODE_DPAD_UP, GameControllerDelegate.BUTTON_DPAD_UP);
ControllerKeyMap.put(KeyEvent.KEYCODE_DPAD_DOWN, GameControllerDelegate.BUTTON_DPAD_DOWN);
ControllerKeyMap.put(KeyEvent.KEYCODE_DPAD_LEFT, GameControllerDelegate.BUTTON_DPAD_LEFT);
ControllerKeyMap.put(KeyEvent.KEYCODE_DPAD_RIGHT, GameControllerDelegate.BUTTON_DPAD_RIGHT);
ControllerKeyMap.put(KeyEvent.KEYCODE_DPAD_CENTER, GameControllerDelegate.BUTTON_DPAD_CENTER);
ControllerKeyMap.put(KeyEvent.KEYCODE_BUTTON_THUMBL, GameControllerDelegate.BUTTON_LEFT_THUMBSTICK);
ControllerKeyMap.put(KeyEvent.KEYCODE_BUTTON_THUMBR, GameControllerDelegate.BUTTON_RIGHT_THUMBSTICK);
ControllerKeyMap.put(KeyEvent.KEYCODE_BUTTON_L1, GameControllerDelegate.BUTTON_LEFT_SHOULDER);
ControllerKeyMap.put(KeyEvent.KEYCODE_BUTTON_R1, GameControllerDelegate.BUTTON_RIGHT_SHOULDER);
ControllerKeyMap.put(KeyEvent.KEYCODE_BUTTON_L2, GameControllerDelegate.BUTTON_LEFT_TRIGGER);
ControllerKeyMap.put(KeyEvent.KEYCODE_BUTTON_R2, GameControllerDelegate.BUTTON_RIGHT_TRIGGER);
ControllerKeyMap.put(MotionEvent.AXIS_X, GameControllerDelegate.THUMBSTICK_LEFT_X);
ControllerKeyMap.put(MotionEvent.AXIS_Y, GameControllerDelegate.THUMBSTICK_LEFT_Y);
ControllerKeyMap.put(MotionEvent.AXIS_Z, GameControllerDelegate.THUMBSTICK_RIGHT_X);
ControllerKeyMap.put(MotionEvent.AXIS_RZ, GameControllerDelegate.THUMBSTICK_RIGHT_Y);
ControllerKeyMap.put(KeyEvent.KEYCODE_BUTTON_START, GameControllerDelegate.BUTTON_START);
ControllerKeyMap.put(KeyEvent.KEYCODE_BUTTON_SELECT, GameControllerDelegate.BUTTON_SELECT);
//KEYCODE_BUTTON_MODE
}
public void connectController(){
if (mLazyInit) {
mLazyInit = false;
mNibiruSupportedDrives = new ArrayList<String>(30);
mMogaSupportedDrives = new ArrayList<String>(5);
mOuyaSupportedDrives = new ArrayList<String>(5);
mLocalSavePath = Environment.getExternalStorageDirectory() + File.separator + "CocosGameController" + File.separator;
mConfigFilePath = sCocos2dxActivity.getFilesDir().getAbsolutePath() + File.separator + COCOS_CONTROLLER_CONFIG;
mDownDepsHttpClient = new AsyncHttpClient();
mDownDepsHttpClient.setTimeout(360 * 1000);
}
if (mControllerListener != null) {
mControllerListener.onDownloadConfigStarted();
}
if (mLazyConfigInit) {
if (mDownDepsHttpClient != null) {
mDownDepsHttpClient.cancelRequests(sCocos2dxActivity, true);
}
requestControllerConfig();
}
else {
scanBluetoothDrive();
}
}
public Set<BluetoothDevice> getBondedDevices(){
if (mBluetoothAdapter == null) {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
return null;
}
}
return mBluetoothAdapter.getBondedDevices();
}
public void destrory(){
if (mDownDepsHttpClient != null) {
mDownDepsHttpClient.cancelRequests(sCocos2dxActivity, true);
}
}
private boolean scanBluetoothDrive(){
if (mControllerListener != null) {
mControllerListener.onDownloadConfigFinished(true);
}
if (mBluetoothAdapter == null) {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
return false;
}
if (mBluetoothDevices == null) {
mBluetoothDevices = new ArrayList<BluetoothDevice>(5);
mDevicesDriver = new SparseIntArray();
}
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
//filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
//filter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
//filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
sCocos2dxActivity.registerReceiver(mBluetoothReceiver, filter);
IntentFilter appFilter = new IntentFilter();
appFilter.addAction("android.intent.action.PACKAGE_ADDED");
appFilter.addDataScheme("package");
sCocos2dxActivity.registerReceiver(mAppReceiver, appFilter);
}
if (!mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.enable();
}
if (mBluetoothAdapter.isDiscovering()) {
mBluetoothAdapter.cancelDiscovery();
}
mBluetoothAdapter.startDiscovery();
return true;
}
public int checkDriverType(BluetoothDevice device){
String deviceName = device.getName();
if (mNibiruSupportedDrives.contains(deviceName)) {
return DRIVERTYPE_NIBIRU;
}
else if (mMogaSupportedDrives.contains(deviceName)) {
return DRIVERTYPE_MOGA;
}
else if (mOuyaSupportedDrives.contains(deviceName)) {
return DRIVERTYPE_OUYA;
}
else {
}
return DRIVERTYPE_UNKNOWN;
}
public static void installApplication(String filePath){
if (sCocos2dxActivity != null) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + filePath), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
sCocos2dxActivity.startActivity(intent);
}
}
public static boolean checkApplication(String packName){
try {
ApplicationInfo applicationInfo = sCocos2dxActivity.getPackageManager().getApplicationInfo(packName, PackageManager.GET_UNINSTALLED_PACKAGES);
Log.d(TAG, applicationInfo.toString());
return true;
} catch (NameNotFoundException e) {
return false;
}
}
private BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (mBluetoothDevices.contains(device)) {
return;
}
Log.d(TAG, "Remote device discovered :" + device.getName());
//We can't ensure non-controller can be filtered out.Some game controller marked with computer class.
/*String deviceName = device.getName();
if(device.getBluetoothClass().getMajorDeviceClass() == BluetoothClass.Device.Major.COMPUTER
|| device.getBluetoothClass().getMajorDeviceClass() == BluetoothClass.Device.Major.PHONE)
{
Log.w(TAG, "Remote device discovered :" + deviceName + " is computer or phone." + device.getBluetoothClass().getMajorDeviceClass());
return;
}*/
mBluetoothDevices.add(device);
int type = checkDriverType(device);
if (type != DRIVERTYPE_UNKNOWN) {
mTargetDriverType = type;
mClearDevices += 1;
}
mDevicesDriver.append(mBluetoothDevices.size() - 1, type);
}
else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
Log.d(TAG, "The local Bluetooth adapter has finished the device discovery process.");
if (mControllerListener != null) {
mControllerListener.onControllerDiscoveryFinish(mBluetoothDevices);
}
else {
if (mBluetoothDevices.size() == 0) {
if (checkApplication(NIBIRU_DEP_PACKAGE)) {
downControllerDeps(DRIVERTYPE_NIBIRU);
}
Log.w(TAG, "Not found any supported bluetooth game controller!");
}else {
if (mClearDevices == 1 ) {
downControllerDeps(mTargetDriverType);
}
else {
Log.i(TAG, "More than one device");
//todo:show sel
}
}
}
}
else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
Log.d(TAG, "The local Bluetooth adapter has started the remote device discovery process.");
if(mControllerListener != null){
mControllerListener.onControllerDiscoveryStarted();
}
mBluetoothDevices.clear();
mDevicesDriver.clear();
mClearDevices = 0;
mTargetDriverType = DRIVERTYPE_UNKNOWN;
//check moga controller
Iterator<BluetoothDevice> it = mBluetoothAdapter.getBondedDevices().iterator();
while (it.hasNext()) {
BluetoothDevice device = it.next();
//if(device.getBluetoothClass().getMajorDeviceClass() != BluetoothClass.Device.Major.COMPUTER
// && device.getBluetoothClass().getMajorDeviceClass() != BluetoothClass.Device.Major.PHONE)
{
if (!mBluetoothDevices.contains(device)) {
mBluetoothDevices.add(device);
int type = checkDriverType(device);
Log.d(TAG, "BluetoothDevice objects that are bonded (paired) to the local adapter :" + device.getName());
if (type != DRIVERTYPE_UNKNOWN) {
mClearDevices += 1;
mTargetDriverType = type;
}
mDevicesDriver.append(mBluetoothDevices.size() - 1, type);
}
}
}
}
}
};
private static int depsCount = 0;
private static int mTargetDriverType = DRIVERTYPE_UNKNOWN;
private static int mDownloadTotalSize;
private static int mDownloadLibSize;
private static int mLibDownloadCompletedSize;
private static int mDepDownloadCompletedSize;
public void downControllerDeps(int driverType){
if (driverType == DRIVERTYPE_STANDARD || driverType == DRIVERTYPE_UNKNOWN) {
return;
}
if (mControllerListener != null) {
mControllerListener.onDownloadDepsStarted();
}
mDownloadTotalSize = 0;
mLibDownloadCompletedSize = 0;
mDepDownloadCompletedSize = 0;
mTargetDriverType = driverType;
depsCount = 1;
GameControllerUtils.ensureDirectoryExist(mLocalSavePath);
String remoteDir = COCOS_CONTROLLER_URL + DRIVERS_NAME[driverType] + File.separator;
if (driverType == DRIVERTYPE_NIBIRU) {
mDownloadLibSize = mNibiruLibFileSize;
mDownloadTotalSize += mNibiruLibFileSize;
if (!checkApplication(NIBIRU_DEP_PACKAGE)) {
depsCount += 1;
mDownloadTotalSize += mNibiruDepFileSize;
mDownDepsHttpClient.get(remoteDir + mNibiruDepFileName, new MyDepsAsyncHandler(
new File(mLocalSavePath + mNibiruDepFileName), MyDepsAsyncHandler.FILETYPE_DEP_APK));
}
File libFile = new File(mLocalSavePath + mNibiruLibFileName);
if (libFile.exists() && libFile.length() == mNibiruLibFileSize) {
depsCount -= 1;
if (depsCount == 0) {
onDepsReady();
}
}
else {
mDownDepsHttpClient.get(remoteDir + mNibiruLibFileName, new MyDepsAsyncHandler(
libFile, MyDepsAsyncHandler.FILETYPE_JAR));
}
}
else if (driverType == DRIVERTYPE_MOGA) {
mDownloadLibSize = mMogaLibFileSize;
mDownloadTotalSize += mMogaLibFileSize;
if (!checkApplication(MOGA__DEP_PACKAGE)) {
mDownloadTotalSize += mMogaDepFileSize;
depsCount += 1;
mDownDepsHttpClient.get(remoteDir + mMogaDepFileName, new MyDepsAsyncHandler(
new File(mLocalSavePath + mMogaDepFileName), MyDepsAsyncHandler.FILETYPE_DEP_APK));
}
File libFile = new File(mLocalSavePath + mMogaLibFileName);
if (libFile.exists() && libFile.length() == mMogaLibFileSize) {
depsCount -= 1;
if (depsCount == 0) {
onDepsReady();
}
}else {
mDownDepsHttpClient.get(remoteDir + mMogaLibFileName, new MyDepsAsyncHandler(
libFile, MyDepsAsyncHandler.FILETYPE_JAR));
}
}
else if(driverType == DRIVERTYPE_OUYA){
mDownloadLibSize = mOuyaLibFileSize;
mDownloadTotalSize += mOuyaLibFileSize;
File libFile = new File(mLocalSavePath + mOuyaLibFileName);
if (libFile.exists() && libFile.length() == mOuyaLibFileSize) {
depsCount -= 1;
if (depsCount == 0) {
onDepsReady();
}
}else {
mDownDepsHttpClient.get(remoteDir + mOuyaLibFileName, new MyDepsAsyncHandler(
new File(mLocalSavePath + mOuyaLibFileName), MyDepsAsyncHandler.FILETYPE_JAR));
}
}
}
static class MyDepsAsyncHandler extends FileAsyncHttpResponseHandler{
public static final int FILETYPE_DEP_APK = 0;
public static final int FILETYPE_JAR = 1;
private int mFileType = FILETYPE_DEP_APK;
public MyDepsAsyncHandler(File file, int fileType) {
super(file);
mFileType = fileType;
}
@Override
public void onFailure(int statusCode, Header[] headers,
Throwable e, File file) {
if (mFileType == FILETYPE_JAR) {
if (file.exists() && file.length() == mDownloadLibSize) {
depsCount -= 1;
if (depsCount == 0) {
if (mControllerListener != null) {
mControllerListener.onDownloadDepsFinished(true);
}
sControllerHelper.onDepsReady();
}
}
}
else if (mFileType == FILETYPE_DEP_APK) {
if (mControllerListener != null) {
mControllerListener.onDownloadDepsFinished(false);
}
}
Log.e(TAG,"Failed to download:" + file.getName());
}
@Override
public void onSuccess(File file) {
Log.d(TAG, "Down file success:" + file.getName());
depsCount -= 1;
if (depsCount == 0) {
if (mControllerListener != null) {
mControllerListener.onDownloadDepsFinished(true);
}
sControllerHelper.onDepsReady();
}
}
@Override
public void onProgress(int bytesWritten, int totalSize) {
if (mFileType == FILETYPE_JAR) {
mLibDownloadCompletedSize = bytesWritten;
} else {
mDepDownloadCompletedSize = bytesWritten;
}
if (mControllerListener != null) {
mControllerListener.onDownloadDepsProgress(mLibDownloadCompletedSize + mDepDownloadCompletedSize, mDownloadTotalSize);
}
Log.d(TAG, "totalSize:" + totalSize + ", bytesWritten:" + bytesWritten);
}
}
private void onDepsReady(){
Log.d(TAG, "onDepsReady:" + mTargetDriverType);
if (mTargetDriverType == DRIVERTYPE_NIBIRU) {
if (checkApplication(NIBIRU_DEP_PACKAGE)) {
createControllerInstance(mLocalSavePath + mNibiruLibFileName, mTargetDriverType);
}
else {
if (mControllerListener != null) {
mControllerListener.onInstallDriver(mLocalSavePath + mMogaDepFileName);
}
installApplication(mLocalSavePath + mNibiruDepFileName);
}
}
else if (mTargetDriverType == DRIVERTYPE_MOGA) {
if (checkApplication(MOGA__DEP_PACKAGE)) {
createControllerInstance(mLocalSavePath + mMogaLibFileName, mTargetDriverType);
}
else {
if (mControllerListener != null) {
mControllerListener.onInstallDriver(mLocalSavePath + mMogaDepFileName);
}
installApplication(mLocalSavePath + mMogaDepFileName);
}
}
else if (mTargetDriverType == DRIVERTYPE_OUYA) {
/*if (checkApplication(OUYA_FRAMEWORK_PACKAGE)) {
if (checkApplication(OUYA_LAUNCHER_PACKAGE)) {
createControllerInstance(mLocalSavePath + mOuyaLibFileName, mTargetSDK);
}
else {
installApplication(mLocalSavePath + mOuyaLauncherFileName);
}
}
else {
installApplication(mLocalSavePath + mOuyaFrameworkFileName);
}*/
createControllerInstance(mLocalSavePath + mOuyaLibFileName, mTargetDriverType);
}
}
private static final String CONFIGKEY_DRIVES = "drives";
private static final String CONFIGKEY_LIB_FILENAME = "lib";
private static final String CONFIGKEY_LIB_FILESIZE = "lib-size";
private static final String CONFIGKEY_DEP_FILENAME = "dep-apk";
private static final String CONFIGKEY_DEP_FILESIZE = "dep-size";
private boolean parseConfig(String jsonString){
mMogaSupportedDrives.clear();
mNibiruSupportedDrives.clear();
mOuyaSupportedDrives.clear();
try {
JSONObject configObject = new JSONObject(jsonString);
JSONObject nibiruObject = configObject.getJSONObject("nibiru");
JSONArray drives = nibiruObject.getJSONArray(CONFIGKEY_DRIVES);
int count = drives.length();
for (int i = 0; i < count; i++) {
mNibiruSupportedDrives.add(drives.getString(i));
}
mNibiruDepFileName = nibiruObject.getString(CONFIGKEY_DEP_FILENAME);
mNibiruDepFileSize = nibiruObject.getInt(CONFIGKEY_DEP_FILESIZE);
mNibiruLibFileName = nibiruObject.getString(CONFIGKEY_LIB_FILENAME);
mNibiruLibFileSize = nibiruObject.getInt(CONFIGKEY_LIB_FILESIZE);
JSONObject mogaObject = configObject.getJSONObject("moga");
drives = mogaObject.getJSONArray(CONFIGKEY_DRIVES);
count = drives.length();
for (int i = 0; i < count; i++) {
mMogaSupportedDrives.add(drives.getString(i));
}
mMogaDepFileName = mogaObject.getString(CONFIGKEY_DEP_FILENAME);
mMogaDepFileSize = mogaObject.getInt(CONFIGKEY_DEP_FILESIZE);
mMogaLibFileName = mogaObject.getString(CONFIGKEY_LIB_FILENAME);
mMogaLibFileSize = mogaObject.getInt(CONFIGKEY_LIB_FILESIZE);
JSONObject ouyaObject = configObject.getJSONObject("ouya");
drives = ouyaObject.getJSONArray(CONFIGKEY_DRIVES);
count = drives.length();
for (int i = 0; i < count; i++) {
mOuyaSupportedDrives.add(drives.getString(i));
}
mOuyaLibFileName = ouyaObject.getString(CONFIGKEY_LIB_FILENAME);
mOuyaLibFileSize = ouyaObject.getInt(CONFIGKEY_LIB_FILESIZE);
//mOuyaFrameworkFileName = ouyaObject.getString("dep-framework");
//mOuyaLauncherFileName = ouyaObject.getString("dep-launcher");
mLazyConfigInit = false;
return true;
} catch (Exception e1) {
e1.printStackTrace();
return false;
}
}
private void requestControllerConfig() {
final JsonHttpResponseHandler configResponseHandler = new JsonHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers,
String responseBody, Throwable e) {
Log.e(TAG, "Failed to download game controller config!");
String configJSON = GameControllerUtils.readJsonFile(mConfigFilePath);
if (configJSON != null) {
if (parseConfig(configJSON)) {
scanBluetoothDrive();
return;
}
}
if (mControllerListener != null) {
mControllerListener.onDownloadConfigFinished(false);
}
/*new AlertDialog.Builder(sCocos2dxActivity)
.setTitle("Loading controller config failed!")
.setMessage(
"Please make sure internet connection works ok!")
.setPositiveButton("Retry",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
dialog.dismiss();
requestControllerConfig();
}
}).setCancelable(false).show();*/
}
@Override
public void onSuccess(int statusCode, Header[] headers,
String responseBody) {
String jsonString = responseBody.trim();
try {
if (parseConfig(jsonString)) {
scanBluetoothDrive();
showToast("Get controller config succeed!");
File configFile = new File(mConfigFilePath);
FileOutputStream outputStream = new FileOutputStream(configFile);
byte[] contentString = jsonString.getBytes();
outputStream.write(contentString, 0, contentString.length);
outputStream.flush();
outputStream.close();
return;
}
else {
String jsonStr = GameControllerUtils.readJsonFile(mConfigFilePath);
if (jsonStr != null) {
if (parseConfig(jsonStr)) {
scanBluetoothDrive();
showToast("Get controller config succeed!");
return;
}
}
}
} catch (Exception e1) {
e1.printStackTrace();
}
if (mControllerListener != null) {
mControllerListener.onDownloadConfigFinished(false);
}
Log.e(TAG, "Failed to download controller config!");
}
};
mDownDepsHttpClient.get(COCOS_CONTROLLER_URL + COCOS_CONTROLLER_CONFIG, configResponseHandler);
}
private static void showToast(String message){
Toast.makeText(sCocos2dxActivity, message, Toast.LENGTH_SHORT).show();
}
private static void createControllerInstance(String libFilePath,int sdkType) {
File libFile = new File(libFilePath);
if (! libFile.exists()) {
Log.w(TAG, libFile.toString() + "not exist!");
return;
}
DexClassLoader classLoader = null;
try {
File dexOutputDir = sCocos2dxActivity.getDir("dex", Context.MODE_PRIVATE);
classLoader = new DexClassLoader(libFile.getCanonicalPath(), dexOutputDir.getCanonicalPath(),
null, sCocos2dxActivity.getClassLoader());
} catch (Exception e1) {
e1.printStackTrace();
}
try {
Class<?> controllerDelegate = null;
if (sdkType == DRIVERTYPE_MOGA) {
controllerDelegate = classLoader.loadClass("org.cocos2dx.lib.GameControllerMoga");
} else if (sdkType == DRIVERTYPE_NIBIRU) {
controllerDelegate = classLoader.loadClass("org.cocos2dx.lib.GameControllerNibiru");
} else if (sdkType == DRIVERTYPE_OUYA) {
controllerDelegate = classLoader.loadClass("org.cocos2dx.lib.GameControllerOuya");
}
GameControllerDelegate instance = (GameControllerDelegate)controllerDelegate.newInstance();
if (mControllerListener != null) {
mControllerListener.onConnectController();
}
sCocos2dxActivity.setGameControllerInstance(instance);
if (sdkType == DRIVERTYPE_NIBIRU) {
Method method = controllerDelegate.getDeclaredMethod("onResume");
method.invoke(instance);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
private BroadcastReceiver mAppReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String packageName = intent.getDataString();
Log.d(TAG, "mAppReceiver:" + intent);
if (packageName.contains(NIBIRU_DEP_PACKAGE)) {
createControllerInstance(mLocalSavePath + mNibiruLibFileName, DRIVERTYPE_NIBIRU);
}
else if (packageName.contains(MOGA__DEP_PACKAGE)) {
createControllerInstance(mLocalSavePath + mMogaLibFileName, DRIVERTYPE_MOGA);
}
}
};
private float mOldLeftThumbstickX = 0.0f;
private float mOldLeftThumbstickY = 0.0f;
private float mOldRightThumbstickX = 0.0f;
private float mOldRightThumbstickY = 0.0f;
private float mOldLeftTrigger = 0.0f;
private float mOldRightTrigger = 0.0f;
private float mOldThrottle = 0.0f;
private float mOldBrake = 0.0f;
public boolean dispatchGenericMotionEvent(MotionEvent event) {
boolean handled = false;
int eventSource = event.getSource();
if ( ((eventSource & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
|| ((eventSource & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK) )
{
if (event.getAction() == MotionEvent.ACTION_MOVE) {
int devicedId = event.getDeviceId();
float newAXIS_LX = event.getAxisValue(MotionEvent.AXIS_X);
if (Float.compare(newAXIS_LX , mOldLeftThumbstickX) != 0) {
GameControllerAdapter.onAxisEvent(StandardControllerName, devicedId, GameControllerDelegate.THUMBSTICK_LEFT_X, newAXIS_LX, true);
mOldLeftThumbstickX = newAXIS_LX;
handled = true;
}
float newAXIS_LY = event.getAxisValue(MotionEvent.AXIS_Y);
if (Float.compare(newAXIS_LY , mOldLeftThumbstickY) != 0) {
GameControllerAdapter.onAxisEvent(StandardControllerName, devicedId, GameControllerDelegate.THUMBSTICK_LEFT_Y, newAXIS_LY, true);
mOldLeftThumbstickY = newAXIS_LY;
handled = true;
}
float newAXIS_RX = event.getAxisValue(MotionEvent.AXIS_Z);
if (Float.compare(newAXIS_RX , mOldRightThumbstickX) != 0) {
GameControllerAdapter.onAxisEvent(StandardControllerName, devicedId, GameControllerDelegate.THUMBSTICK_RIGHT_X, newAXIS_RX, true);
mOldRightThumbstickX = newAXIS_RX;
handled = true;
}
float newAXIS_RY = event.getAxisValue(MotionEvent.AXIS_RZ);
if (Float.compare(newAXIS_RY , mOldRightThumbstickY) != 0) {
GameControllerAdapter.onAxisEvent(StandardControllerName, devicedId, GameControllerDelegate.THUMBSTICK_RIGHT_Y, newAXIS_RY, true);
mOldRightThumbstickY = newAXIS_RY;
handled = true;
}
float newAXIS_LTRIGGER = event.getAxisValue(MotionEvent.AXIS_LTRIGGER);
if (Float.compare(newAXIS_LTRIGGER , mOldLeftTrigger) != 0) {
if (Float.compare(newAXIS_LTRIGGER, 0.0f) == 0) {
GameControllerAdapter.onButtonEvent(StandardControllerName, devicedId, GameControllerDelegate.BUTTON_LEFT_TRIGGER, false, 0.0f, true);
}else {
GameControllerAdapter.onButtonEvent(StandardControllerName, devicedId, GameControllerDelegate.BUTTON_LEFT_TRIGGER, true, newAXIS_LTRIGGER, true);
}
mOldLeftTrigger = newAXIS_LTRIGGER;
handled = true;
}
float newAXIS_RTRIGGER = event.getAxisValue(MotionEvent.AXIS_RTRIGGER);
if (Float.compare(newAXIS_RTRIGGER , mOldRightTrigger) != 0) {
if (Float.compare(newAXIS_RTRIGGER, 0.0f) == 0) {
GameControllerAdapter.onButtonEvent(StandardControllerName, devicedId, GameControllerDelegate.BUTTON_RIGHT_TRIGGER, false, 0.0f, true);
}else {
GameControllerAdapter.onButtonEvent(StandardControllerName, devicedId, GameControllerDelegate.BUTTON_RIGHT_TRIGGER, true, newAXIS_RTRIGGER, true);
}
mOldRightTrigger = newAXIS_RTRIGGER;
handled = true;
}
float newAXIS_BRAKE = event.getAxisValue(MotionEvent.AXIS_BRAKE);
if (Float.compare(newAXIS_BRAKE , mOldBrake) != 0) {
if (Float.compare(newAXIS_BRAKE, 0.0f) == 0) {
GameControllerAdapter.onButtonEvent(StandardControllerName, devicedId, GameControllerDelegate.BUTTON_LEFT_TRIGGER, false, 0.0f, true);
}else {
GameControllerAdapter.onButtonEvent(StandardControllerName, devicedId, GameControllerDelegate.BUTTON_LEFT_TRIGGER, true, newAXIS_BRAKE, true);
}
mOldBrake = newAXIS_BRAKE;
handled = true;
}
float newAXIS_THROTTLE = event.getAxisValue(MotionEvent.AXIS_THROTTLE);
if (Float.compare(newAXIS_THROTTLE , mOldThrottle) != 0) {
if (Float.compare(newAXIS_THROTTLE, 0.0f) == 0) {
GameControllerAdapter.onButtonEvent(StandardControllerName, devicedId, GameControllerDelegate.BUTTON_RIGHT_TRIGGER, false, 0.0f, true);
}else {
GameControllerAdapter.onButtonEvent(StandardControllerName, devicedId, GameControllerDelegate.BUTTON_RIGHT_TRIGGER, true, newAXIS_THROTTLE, true);
}
mOldThrottle = newAXIS_THROTTLE;
handled = true;
}
}
}
return handled;
}
public boolean dispatchKeyEvent(KeyEvent event) {
boolean handled = false;
int eventSource = event.getSource();
int controllerKey = ControllerKeyMap.get(event.getKeyCode());
if (controllerKey != 0 && (((eventSource & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
|| ((eventSource & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)
|| ((eventSource & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD)))
{
int action = event.getAction();
if (action == KeyEvent.ACTION_DOWN) {
handled = true;
GameControllerAdapter.onButtonEvent(StandardControllerName,event.getDeviceId(), controllerKey,true, 1.0f, false);
}else if (action == KeyEvent.ACTION_UP) {
handled = true;
GameControllerAdapter.onButtonEvent(StandardControllerName,event.getDeviceId(), controllerKey,false, 0.0f, false);
}
}
return handled;
}
}

View File

@ -0,0 +1,43 @@
package org.cocos2dx.lib;
import java.io.File;
import java.io.FileInputStream;
public class GameControllerUtils {
public static void ensureDirectoryExist(String path){
File sdkDir = new File(path);
if(!sdkDir.exists()){
sdkDir.mkdirs();
}
}
public static String readJsonFile(String filePath) {
File file = new File(filePath);
if (!file.exists()){
return null;
}
try {
FileInputStream is = new FileInputStream(file);;
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
String jsonstr = new String(buffer, "UTF-8");
return jsonstr;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,140 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.cocos2dx.lib.inputmanagercompat;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.view.InputDevice;
import android.view.MotionEvent;
public interface InputManagerCompat {
/**
* Gets information about the input device with the specified id.
*
* @param id The device id
* @return The input device or null if not found
*/
public InputDevice getInputDevice(int id);
/**
* Gets the ids of all input devices in the system.
*
* @return The input device ids.
*/
public int[] getInputDeviceIds();
/**
* Registers an input device listener to receive notifications about when
* input devices are added, removed or changed.
*
* @param listener The listener to register.
* @param handler The handler on which the listener should be invoked, or
* null if the listener should be invoked on the calling thread's
* looper.
*/
public void registerInputDeviceListener(InputManagerCompat.InputDeviceListener listener,
Handler handler);
/**
* Unregisters an input device listener.
*
* @param listener The listener to unregister.
*/
public void unregisterInputDeviceListener(InputManagerCompat.InputDeviceListener listener);
/*
* The following three calls are to simulate V16 behavior on pre-Jellybean
* devices. If you don't call them, your callback will never be called
* pre-API 16.
*/
/**
* Pass the motion events to the InputManagerCompat. This is used to
* optimize for polling for controllers. If you do not pass these events in,
* polling will cause regular object creation.
*
* @param event the motion event from the app
*/
public void onGenericMotionEvent(MotionEvent event);
/**
* Tell the V9 input manager that it should stop polling for disconnected
* devices. You can call this during onPause in your activity, although you
* might want to call it whenever your game is not active (or whenever you
* don't care about being notified of new input devices)
*/
public void onPause();
/**
* Tell the V9 input manager that it should start polling for disconnected
* devices. You can call this during onResume in your activity, although you
* might want to call it less often (only when the gameplay is actually
* active)
*/
public void onResume();
public interface InputDeviceListener {
/**
* Called whenever the input manager detects that a device has been
* added. This will only be called in the V9 version when a motion event
* is detected.
*
* @param deviceId The id of the input device that was added.
*/
void onInputDeviceAdded(int deviceId);
/**
* Called whenever the properties of an input device have changed since
* they were last queried. This will not be called for the V9 version of
* the API.
*
* @param deviceId The id of the input device that changed.
*/
void onInputDeviceChanged(int deviceId);
/**
* Called whenever the input manager detects that a device has been
* removed. For the V9 version, this can take some time depending on the
* poll rate.
*
* @param deviceId The id of the input device that was removed.
*/
void onInputDeviceRemoved(int deviceId);
}
/**
* Use this to construct a compatible InputManager.
*/
public static class Factory {
/**
* Constructs and returns a compatible InputManger
*
* @param context the Context that will be used to get the system
* service from
* @return a compatible implementation of InputManager
*/
public static InputManagerCompat getInputManager(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
return new InputManagerV16(context);
} else {
return new InputManagerV9();
}
}
}
}

View File

@ -0,0 +1,107 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.cocos2dx.lib.inputmanagercompat;
import android.annotation.TargetApi;
import android.content.Context;
import android.hardware.input.InputManager;
import android.os.Build;
import android.os.Handler;
import android.view.InputDevice;
import android.view.MotionEvent;
import java.util.HashMap;
import java.util.Map;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class InputManagerV16 implements InputManagerCompat {
private final InputManager mInputManager;
private final Map<InputManagerCompat.InputDeviceListener, V16InputDeviceListener> mListeners;
public InputManagerV16(Context context) {
mInputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE);
mListeners = new HashMap<InputManagerCompat.InputDeviceListener, V16InputDeviceListener>();
}
@Override
public InputDevice getInputDevice(int id) {
return mInputManager.getInputDevice(id);
}
@Override
public int[] getInputDeviceIds() {
return mInputManager.getInputDeviceIds();
}
static class V16InputDeviceListener implements InputManager.InputDeviceListener {
final InputManagerCompat.InputDeviceListener mIDL;
public V16InputDeviceListener(InputDeviceListener idl) {
mIDL = idl;
}
@Override
public void onInputDeviceAdded(int deviceId) {
mIDL.onInputDeviceAdded(deviceId);
}
@Override
public void onInputDeviceChanged(int deviceId) {
mIDL.onInputDeviceChanged(deviceId);
}
@Override
public void onInputDeviceRemoved(int deviceId) {
mIDL.onInputDeviceRemoved(deviceId);
}
}
@Override
public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) {
V16InputDeviceListener v16Listener = new V16InputDeviceListener(listener);
mInputManager.registerInputDeviceListener(v16Listener, handler);
mListeners.put(listener, v16Listener);
}
@Override
public void unregisterInputDeviceListener(InputDeviceListener listener) {
V16InputDeviceListener curListener = mListeners.remove(listener);
if (null != curListener)
{
mInputManager.unregisterInputDeviceListener(curListener);
}
}
@Override
public void onGenericMotionEvent(MotionEvent event) {
// unused in V16
}
@Override
public void onPause() {
// unused in V16
}
@Override
public void onResume() {
// unused in V16
}
}

View File

@ -0,0 +1,211 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.cocos2dx.lib.inputmanagercompat;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
import android.view.InputDevice;
import android.view.MotionEvent;
import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
public class InputManagerV9 implements InputManagerCompat {
private static final String LOG_TAG = "InputManagerV9";
private static final int MESSAGE_TEST_FOR_DISCONNECT = 101;
private static final long CHECK_ELAPSED_TIME = 3000L;
private static final int ON_DEVICE_ADDED = 0;
private static final int ON_DEVICE_CHANGED = 1;
private static final int ON_DEVICE_REMOVED = 2;
private final SparseArray<long[]> mDevices;
private final Map<InputDeviceListener, Handler> mListeners;
private final Handler mDefaultHandler;
private static class PollingMessageHandler extends Handler {
private final WeakReference<InputManagerV9> mInputManager;
PollingMessageHandler(InputManagerV9 im) {
mInputManager = new WeakReference<InputManagerV9>(im);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MESSAGE_TEST_FOR_DISCONNECT:
InputManagerV9 imv = mInputManager.get();
if (null != imv) {
long time = SystemClock.elapsedRealtime();
int size = imv.mDevices.size();
for (int i = 0; i < size; i++) {
long[] lastContact = imv.mDevices.valueAt(i);
if (null != lastContact) {
if (time - lastContact[0] > CHECK_ELAPSED_TIME) {
// check to see if the device has been
// disconnected
int id = imv.mDevices.keyAt(i);
if (null == InputDevice.getDevice(id)) {
// disconnected!
imv.notifyListeners(ON_DEVICE_REMOVED, id);
imv.mDevices.remove(id);
} else {
lastContact[0] = time;
}
}
}
}
sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT,
CHECK_ELAPSED_TIME);
}
break;
}
}
}
public InputManagerV9() {
mDevices = new SparseArray<long[]>();
mListeners = new HashMap<InputDeviceListener, Handler>();
mDefaultHandler = new PollingMessageHandler(this);
// as a side-effect, populates our collection of watched
// input devices
getInputDeviceIds();
}
@Override
public InputDevice getInputDevice(int id) {
return InputDevice.getDevice(id);
}
@Override
public int[] getInputDeviceIds() {
// add any hitherto unknown devices to our
// collection of watched input devices
int[] activeDevices = InputDevice.getDeviceIds();
long time = SystemClock.elapsedRealtime();
for ( int id : activeDevices ) {
long[] lastContact = mDevices.get(id);
if ( null == lastContact ) {
// we have a new device
mDevices.put(id, new long[] { time });
}
}
return activeDevices;
}
@Override
public void registerInputDeviceListener(InputDeviceListener listener, Handler handler) {
mListeners.remove(listener);
if (handler == null) {
handler = mDefaultHandler;
}
mListeners.put(listener, handler);
}
@Override
public void unregisterInputDeviceListener(InputDeviceListener listener) {
mListeners.remove(listener);
}
private void notifyListeners(int why, int deviceId) {
// the state of some device has changed
if (!mListeners.isEmpty()) {
// yes... this will cause an object to get created... hopefully
// it won't happen very often
for (InputDeviceListener listener : mListeners.keySet()) {
Handler handler = mListeners.get(listener);
DeviceEvent odc = DeviceEvent.getDeviceEvent(why, deviceId, listener);
handler.post(odc);
}
}
}
private static class DeviceEvent implements Runnable {
private int mMessageType;
private int mId;
private InputDeviceListener mListener;
private static Queue<DeviceEvent> sEventQueue = new ArrayDeque<DeviceEvent>();
private DeviceEvent() {
}
static DeviceEvent getDeviceEvent(int messageType, int id,
InputDeviceListener listener) {
DeviceEvent curChanged = sEventQueue.poll();
if (null == curChanged) {
curChanged = new DeviceEvent();
}
curChanged.mMessageType = messageType;
curChanged.mId = id;
curChanged.mListener = listener;
return curChanged;
}
@Override
public void run() {
switch (mMessageType) {
case ON_DEVICE_ADDED:
mListener.onInputDeviceAdded(mId);
break;
case ON_DEVICE_CHANGED:
mListener.onInputDeviceChanged(mId);
break;
case ON_DEVICE_REMOVED:
mListener.onInputDeviceRemoved(mId);
break;
default:
Log.e(LOG_TAG, "Unknown Message Type");
break;
}
// dump this runnable back in the queue
sEventQueue.offer(this);
}
}
@Override
public void onGenericMotionEvent(MotionEvent event) {
// detect new devices
int id = event.getDeviceId();
long[] timeArray = mDevices.get(id);
if (null == timeArray) {
notifyListeners(ON_DEVICE_ADDED, id);
timeArray = new long[1];
mDevices.put(id, timeArray);
}
long time = SystemClock.elapsedRealtime();
timeArray[0] = time;
}
@Override
public void onPause() {
mDefaultHandler.removeMessages(MESSAGE_TEST_FOR_DISCONNECT);
}
@Override
public void onResume() {
mDefaultHandler.sendEmptyMessage(MESSAGE_TEST_FOR_DISCONNECT);
}
}