From 6ef76c1fec4701774ef42ffeb89f744254f8653c Mon Sep 17 00:00:00 2001 From: Hugh Sanderson Date: Thu, 5 Sep 2024 16:52:45 +0800 Subject: [PATCH] Get android controllers working --- project/src/android/AndroidFrame.cpp | 33 +++-- src/nme/display/Stage.hx | 60 ++------ src/nme/ui/GameInput.hx | 26 ++++ src/nme/ui/GameInputDevice.hx | 6 +- src/nme/ui/GamepadButton.hx | 21 +-- .../extension-api/src/org/haxe/nme/NME.java | 1 + .../java/org/haxe/nme/GameActivity.java | 76 +++++++--- .../android/java/org/haxe/nme/MainView.java | 135 ++++++++++++++---- 8 files changed, 247 insertions(+), 111 deletions(-) diff --git a/project/src/android/AndroidFrame.cpp b/project/src/android/AndroidFrame.cpp index d8326b95c..077cb6a02 100644 --- a/project/src/android/AndroidFrame.cpp +++ b/project/src/android/AndroidFrame.cpp @@ -359,18 +359,33 @@ class AndroidStage : public Stage { //__android_log_print(ANDROID_LOG_INFO, "NME", "OnJoy %d %d %d", inDeviceId, inCode, inDown); Event joystick( inDown ? etJoyButtonDown : etJoyButtonUp ); - joystick.id = inDeviceId; + joystick.value = inDeviceId; joystick.code = inCode; HandleEvent(joystick); } - void OnJoyMotion(int inDeviceId, int inAxis, float inValue) + void OnJoyMotion(int inDeviceId, int inAxis, bool isGamepad, float inSx, float inSy) { - Event joystick(etJoyAxisMove); - joystick.id = inDeviceId; - joystick.code = inAxis; - joystick.value = inValue; - HandleEvent(joystick); + if (inAxis<6) + { + Event joystick(etJoyAxisMove); + joystick.value = inDeviceId; + joystick.code = inAxis; + joystick.scaleX = inSx; + joystick.scaleY = inSy; + joystick.y = isGamepad; + HandleEvent(joystick); + } + else // DPad/hat + { + Event joystick(etJoyHatMove); + joystick.value = inDeviceId; + joystick.code = 0; + joystick.scaleX = inSx; + joystick.scaleY = inSy; + joystick.y = true; + HandleEvent(joystick); + } } void OnTrackball(double inX, double inY) @@ -911,11 +926,11 @@ JAVA_EXPORT int JNICALL Java_org_haxe_nme_NME_onJoyChange(JNIEnv * env, jobject return nme::GetResult(); } -JAVA_EXPORT int JNICALL Java_org_haxe_nme_NME_onJoyMotion(JNIEnv * env, jobject obj, int deviceId, int axis, float value) +JAVA_EXPORT int JNICALL Java_org_haxe_nme_NME_onJoyMotion(JNIEnv * env, jobject obj, int deviceId, int axis, bool isGame, float inSx, float inSy) { AutoHaxe haxe("onJoyMotion"); if (nme::sStage) - nme::sStage->OnJoyMotion(deviceId,axis,value); + nme::sStage->OnJoyMotion(deviceId, axis, isGame, inSx, inSy); return nme::GetResult(); } diff --git a/src/nme/display/Stage.hx b/src/nme/display/Stage.hx index cd5581fbb..b728ce31e 100644 --- a/src/nme/display/Stage.hx +++ b/src/nme/display/Stage.hx @@ -800,44 +800,17 @@ class Stage extends DisplayObjectContainer implements nme.app.IPollClient implem } - private inline function axismap( code:Int ) - { - #if openfl_legacy - switch(code) - { - case 3: code = 4; - case 2: code = 3; - case 4: code = 2; - } - #end - return code; - } - private inline function buttonmap( code:Int ) - { - #if openfl_legacy - switch(code) - { - case 9: code = GamepadButton.LEFT_SHOULDER; - case 4: code = GamepadButton.BACK; - case 8: code = GamepadButton.RIGHT_STICK; - case 10: code = GamepadButton.RIGHT_SHOULDER; - case 6: code = GamepadButton.START; - case 7: code = GamepadButton.LEFT_STICK; - } - #end - return code; - } - public function onJoystick(inEvent:AppEvent, inType:String):Void { var data:Array = null; + // user = deviceId var user = inEvent.value; var isGamePad:Bool = inEvent.y>0; if(inEvent.flags > 0) { ///is axis move event if(inEvent.flags==1) - { + { if(nmeJoyAxisData[user]==null) nmeJoyAxisData[user] = [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ]; @@ -846,37 +819,26 @@ class Stage extends DisplayObjectContainer implements nme.app.IPollClient implem data[ inEvent.code+1 ] = inEvent.sy; } else if(inEvent.flags==3) - { + { //isGamePad if(nmeJoyAxisData[user]==null) nmeJoyAxisData[user] = [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 ]; data = nmeJoyAxisData[user]; - data[ axismap(inEvent.code) ] = inEvent.sx; - data[ axismap(inEvent.code+1) ] = inEvent.sy; + data[ inEvent.code ] = inEvent.sx; + data[ inEvent.code+1 ] = inEvent.sy; } else if(inEvent.flags==2) { if(nmeJoyAxisData[user]!=null) - for(d in nmeJoyAxisData[user]) - d = 0.0; + for(d in 0...nmeJoyAxisData[user].length) + nmeJoyAxisData[user][d] = 0.0; } } - #if openfl_legacy - if(isGamePad && StringTools.startsWith(inType,"button")) - { - //map sdl controller to legacy xinput - var evt:JoystickEvent = new JoystickEvent(inType, false, false, inEvent.id, buttonmap(inEvent.code), - inEvent.value, inEvent.sx, inEvent.sy, data, isGamePad); - nmeDispatchEvent(evt); - } - else - #end - { - var evt:JoystickEvent = new JoystickEvent(inType, false, false, inEvent.id, inEvent.code, - inEvent.value, inEvent.sx, inEvent.sy, data, isGamePad); - nmeDispatchEvent(evt); - } + + var evt:JoystickEvent = new JoystickEvent(inType, false, false, inEvent.id, inEvent.code, + inEvent.value, inEvent.sx, inEvent.sy, data, isGamePad); + nmeDispatchEvent(evt); if(GameInput.hasInstances()) { diff --git a/src/nme/ui/GameInput.hx b/src/nme/ui/GameInput.hx index 4e6b609aa..9abc063c2 100644 --- a/src/nme/ui/GameInput.hx +++ b/src/nme/ui/GameInput.hx @@ -17,6 +17,9 @@ class GameInput extends EventDispatcher static var nmeInstances = []; static var nmeKeyboardDevices = new Array(); static var added = false; + #if android + static var getDeviceName:Dynamic; + #end public function new() @@ -27,14 +30,21 @@ class GameInput extends EventDispatcher #if android if (!added) { + getDeviceName = JNI.createStaticMethod( + "org/haxe/nme/GameActivity", + "getDeviceName", + "(I)Ljava/lang/String;" ); + var setInputManagerCallback = JNI.createStaticMethod( "org/haxe/nme/GameActivity", "setInputManagerCallback", "(Lorg/haxe/nme/HaxeObject;)[I" ); added = true; + var existing:Array = setInputManagerCallback(this); for(device in existing) nme.app.Application.runOnMainThread( () -> nmeGamepadConnect(device) ); + consumeGamepadButtons(true); } #end @@ -49,6 +59,18 @@ class GameInput extends EventDispatcher //} } + // Consuming the 'B' button will prevent it from generating a "Back" event + public static function consumeGamepadButtons(consume:Bool) + { + #if android + var setConsumeGamepadButtons = JNI.createStaticMethod( + "org/haxe/nme/GameActivity", + "setConsumeGamepadButtons", + "(Z)V" ); + setConsumeGamepadButtons(consume); + #end + } + #if android // Called from android handler @keep function onInputDeviceAdded(device:Int) @@ -148,8 +170,12 @@ class GameInput extends EventDispatcher static function getGamepadName(index:Int) : String { + #if android + return getDeviceName(index); + #else // TODO return "name"+index; + #end } private static function __getDevice(index:Int):GameInputDevice diff --git a/src/nme/ui/GameInputDevice.hx b/src/nme/ui/GameInputDevice.hx index 7452be936..70f218d07 100644 --- a/src/nme/ui/GameInputDevice.hx +++ b/src/nme/ui/GameInputDevice.hx @@ -40,7 +40,7 @@ class GameInputDevice nmeControls.push(control); } - for (i in 0...15) + for (i in 0...GamepadButton.COUNT) { control = new GameInputControl(this, "BUTTON_" + i, 0, 1); nmeButton.set(i, control); @@ -50,7 +50,7 @@ class GameInputDevice public function toString() return 'GameInputDevice($id:$name)'; - public function getButtonAt(i:Int) return i>=0 && i<15 ? nmeControls[i+6] : null; + public function getButtonAt(i:Int) return i>=0 && i=0 && i<6 ? nmeControls[i] : null; @@ -58,7 +58,7 @@ class GameInputDevice public function isButtonDown(buttonId:Int) { - if (buttonId<0 || buttonId>=15) + if (buttonId<0 || buttonId>=GamepadButton.COUNT) return false; return nmeControls[buttonId+6].value>0; } diff --git a/src/nme/ui/GamepadButton.hx b/src/nme/ui/GamepadButton.hx index f653d8e50..66654a59a 100644 --- a/src/nme/ui/GamepadButton.hx +++ b/src/nme/ui/GamepadButton.hx @@ -8,15 +8,7 @@ class GamepadButton public static inline var B:Int = 1; public static inline var X:Int = 2; public static inline var Y:Int = 3; -#if openfl_legacy - public static inline var LEFT_SHOULDER:Int = 4; - public static inline var RIGHT_SHOULDER:Int = 5; - public static inline var BACK:Int = 6; - public static inline var START:Int = 7; - public static inline var LEFT_STICK:Int = 8; - public static inline var RIGHT_STICK:Int = 9; - public static inline var GUIDE:Int = 10; -#else + public static inline var BACK:Int = 4; public static inline var GUIDE:Int = 5; public static inline var START:Int = 6; @@ -24,12 +16,18 @@ class GamepadButton public static inline var RIGHT_STICK:Int = 8; public static inline var LEFT_SHOULDER:Int = 9; public static inline var RIGHT_SHOULDER:Int = 10; -#end + public static inline var DPAD_UP:Int = 11; public static inline var DPAD_DOWN:Int = 12; public static inline var DPAD_LEFT:Int = 13; public static inline var DPAD_RIGHT:Int = 14; + public static inline var LEFT_SHOULDER2:Int = 15; + public static inline var RIGHT_SHOULDER2:Int = 16; + public static inline var SELECT:Int = 17; + + public static inline var COUNT:Int = 18; + public static function toString(id:Int) : String { switch(id) @@ -49,6 +47,9 @@ class GamepadButton case GamepadButton.DPAD_DOWN: return "GamepadButton.DPAD_DOWN"; case GamepadButton.DPAD_LEFT: return "GamepadButton.DPAD_LEFT"; case GamepadButton.DPAD_RIGHT: return "GamepadButton.DPAD_RIGHT"; + case GamepadButton.LEFT_SHOULDER2: return "GamepadButton.LEFT_SHOULDER2"; + case GamepadButton.RIGHT_SHOULDER2: return "GamepadButton.RIGHT_SHOULDER2"; + case GamepadButton.SELECT: return "GamepadButton.SELECT"; default: return "BUTTON UNKNOWN[id:"+id+"]"; } } diff --git a/templates/android/extension-api/src/org/haxe/nme/NME.java b/templates/android/extension-api/src/org/haxe/nme/NME.java index 7483e4268..36859c6ea 100644 --- a/templates/android/extension-api/src/org/haxe/nme/NME.java +++ b/templates/android/extension-api/src/org/haxe/nme/NME.java @@ -25,6 +25,7 @@ public class NME { public static native int onContextLost(); public static native int onTrackball(float x,float y); public static native int onJoyChange(int inDeviceID, int inCode, boolean inIsDown); + public static native int onJoyMotion(int inDeviceID, int inAxis, boolean isGamepad, float inX, float inY); public static native int onKeyChange(int inKeyCode, int inCharCode, boolean inIsDown, boolean isChar); public static native int onText(String inNewText, int inReplacePos, int inReplaceLength); public static native int onTextSelect( int inReplacePos, int inReplaceLength); diff --git a/templates/android/java/org/haxe/nme/GameActivity.java b/templates/android/java/org/haxe/nme/GameActivity.java index eda1aec3e..c73c7050d 100644 --- a/templates/android/java/org/haxe/nme/GameActivity.java +++ b/templates/android/java/org/haxe/nme/GameActivity.java @@ -67,6 +67,7 @@ import java.io.PrintWriter; import android.hardware.input.InputManager; import android.view.MotionEvent; +import android.view.InputDevice; import androidx.core.content.ContextCompat; import android.content.pm.PackageManager; @@ -114,7 +115,7 @@ public class GameActivity extends ::GAME_ACTIVITY_BASE:: static HashMap mLoadedClasses = new HashMap(); static SensorManager sensorManager; static android.text.ClipboardManager mClipboard; - static InputManager inputManager; + public static InputManager inputManager; private static List extensions; ::if NME_FIREBASE:: @@ -147,6 +148,7 @@ class NmeText extends EditText //Log.v(TAG,"NME Forward MotionEvent" + event); return activity.mView.onGenericMotionEvent(event); } + } ArrayList mOnDestroyListeners; @@ -169,6 +171,7 @@ class NmeText extends EditText public boolean mTextUpdateLockout = false; public boolean mIncrementalText = true; boolean ignoreTextReset = false; + static boolean consumeGamepadButtons = false; public void onCreate(Bundle state) { @@ -214,6 +217,7 @@ public void onCreate(Bundle state) Extension.packageName = getApplicationContext().getPackageName(); mClipboard = (android.text.ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE); + inputManager = (InputManager)activity.mContext.getSystemService(Context.INPUT_SERVICE); // Pre-load these, so the C++ knows where to find them @@ -384,29 +388,56 @@ public static int billingClientCode() } ::end:: + static int[] filterArray(int[] array, java.util.function.IntPredicate predicate) { + return java.util.Arrays.stream(array) + .filter(predicate) + .toArray(); + } + + static boolean isGameDevice(int deviceId) + { + InputDevice device = inputManager.getInputDevice(deviceId); + int source = device.getSources(); + boolean isJoystick = (source & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK; + boolean isGamepad = (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD; + boolean isGame = isJoystick || isGamepad; + if (device.isVirtual()) + isGame = false; + Log.e(TAG, "Check InputDevice " + device.toString() + " joystick=" + isJoystick + " game=" + isGamepad); + return isGame; + } + + static String getDeviceName(int deviceId) + { + InputDevice device = inputManager.getInputDevice(deviceId); + return device.getName(); + } + public static int[] setInputManagerCallback(final HaxeObject inCallback) { final HaxeObject callback = inCallback; - inputManager = (InputManager)activity.mContext.getSystemService(Context.INPUT_SERVICE); inputManager.registerInputDeviceListener( new InputManager.InputDeviceListener() { @Override public void onInputDeviceAdded(final int deviceId) { - sendHaxe( new Runnable() { - @Override public void run() { - callback.call1("onInputDeviceAdded", deviceId); - } }); } + if (isGameDevice(deviceId)) + sendHaxe( new Runnable() { + @Override public void run() { + callback.call1("onInputDeviceAdded", deviceId ); + } }); } @Override public void onInputDeviceChanged(final int deviceId) { - sendHaxe( new Runnable() { - @Override public void run() { - callback.call1("onInputDeviceChanged", deviceId); - } }); } + if (isGameDevice(deviceId)) + sendHaxe( new Runnable() { + @Override public void run() { + callback.call1("onInputDeviceChanged", deviceId); + } }); } @Override public void onInputDeviceRemoved(final int deviceId) { - sendHaxe( new Runnable() { - @Override public void run() { - callback.call1("onInputDeviceRemoved", deviceId); - } }); } + if (isGameDevice(deviceId)) + sendHaxe( new Runnable() { + @Override public void run() { + callback.call1("onInputDeviceRemoved", deviceId); + } }); } }, activity.mHandler); - return inputManager.getInputDeviceIds(); + return filterArray(inputManager.getInputDeviceIds(),GameActivity::isGameDevice); } @@ -1579,6 +1610,15 @@ public void run() { } //} } + if (mView!=null) + { + if (mView.sendGamepadKey(keyCode, event)) + { + if (consumeGamepadButtons) + return true; + } + } + return false; } }); @@ -1603,8 +1643,12 @@ public void onSpanChanged(final Spannable text, final Object what,final int osta */ } + public static void setConsumeGamepadButtons(boolean consume) + { + consumeGamepadButtons = consume; + } + - public static void vibrate(int period, int duration) { diff --git a/templates/android/java/org/haxe/nme/MainView.java b/templates/android/java/org/haxe/nme/MainView.java index 6d267d772..1b7f8281e 100644 --- a/templates/android/java/org/haxe/nme/MainView.java +++ b/templates/android/java/org/haxe/nme/MainView.java @@ -36,6 +36,8 @@ import javax.microedition.khronos.opengles.GL10; import java.util.TimerTask; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.Semaphore; /** @@ -70,8 +72,33 @@ class MainView extends GLSurfaceView { Semaphore pendingTimerSemaphore; boolean renderPending = false; + class StickState + { + public float[] x; + public float[] y; + + public StickState() + { + x = new float[]{0,0,0,0}; + y = new float[]{0,0,0,0}; + } + + public void sendChange(MainView view, MotionEvent event, boolean gamepad, int slot, int axX, int axY) + { + float xVal = event.getAxisValue(axX); + float yVal = event.getAxisValue(axY); + if (xVal!=x[slot] || yVal!=y[slot]) + { + x[slot] = xVal; + y[slot] = yVal; + view.HandleResult(NME.onJoyMotion(event.getDeviceId(),slot*2,gamepad, xVal, yVal) ); + } + } + } + + static Map deviceMap = new HashMap<>(); + - //private InputDevice device; public MainView(Context context,GameActivity inActivity, boolean inTranslucent) { @@ -322,35 +349,40 @@ static public void renderNow() } @Override - public boolean onGenericMotionEvent(MotionEvent event) + public boolean onGenericMotionEvent(final MotionEvent event) { //Log.e("NME VIEW", "Joystick " + event ); final MainView me = this; - if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) + final int source = event.getSource(); + final boolean joystick = (source & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK; + final boolean gamepad = (source & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD; + // Should we send ACTION_MOVE events anyhow? + //if (joystick || gamepad) { if (event.getAction() == MotionEvent.ACTION_MOVE) { final int deviceId = event.getDeviceId(); + final InputDevice device = GameActivity.inputManager.getInputDevice(deviceId); + String devName = device.getDescriptor(); + if (!deviceMap.containsKey(devName)) + deviceMap.put(devName, new StickState() ); + final StickState state = deviceMap.get(devName); - //Log.e("VIEW", "Joystick " + deviceId ); - queueEvent(new Runnable() { - // This method will be called on the rendering thread: - public void run() { - float [] axisValues = { - event.getAxisValue(MotionEvent.AXIS_X), - event.getAxisValue(MotionEvent.AXIS_Y), - event.getAxisValue(MotionEvent.AXIS_HAT_X), - event.getAxisValue(MotionEvent.AXIS_HAT_Y) - }; - - //Log.e("VIEW", "Joystick axis ->" + axisValues ); - - me.HandleResult(NME.onJoyChange(deviceId,0,false)); - }}); + if (device!=null) + { + queueEvent(new Runnable() { + public void run() { + state.sendChange(me, event, gamepad, 0, MotionEvent.AXIS_X, MotionEvent.AXIS_Y); + state.sendChange(me, event, gamepad, 1, MotionEvent.AXIS_Z, MotionEvent.AXIS_RZ); + state.sendChange(me, event, gamepad, 2, MotionEvent.AXIS_LTRIGGER, MotionEvent.AXIS_RTRIGGER); + //state.sendChange(me, event, gamepad, 2, MotionEvent.AXIS_BRAKE, MotionEvent.AXIS_GAS); + state.sendChange(me, event, gamepad, 3, MotionEvent.AXIS_HAT_X, MotionEvent.AXIS_HAT_Y); + }}); + } return true; } } - if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) + if ((source & InputDevice.SOURCE_CLASS_POINTER) == InputDevice.SOURCE_CLASS_POINTER) { switch (event.getAction()) { @@ -490,21 +522,76 @@ public static int translateKey(int inCode, KeyEvent event,boolean inTranslateUni return 0; } + public static int translateGampadButton(int inCode) + { + switch(inCode) + { + case KeyEvent.KEYCODE_BUTTON_A: return 0; + case KeyEvent.KEYCODE_DPAD_CENTER: return 0; // Map to 'A' + + case KeyEvent.KEYCODE_BUTTON_B: return 1; + case KeyEvent.KEYCODE_BUTTON_X: return 2; + case KeyEvent.KEYCODE_BUTTON_Y: return 3; + + //case KeyEvent.KEYCODE_BACK: return 4; + case KeyEvent.KEYCODE_BUTTON_C: return 4; // Back + case KeyEvent.KEYCODE_GUIDE: return 5; + case KeyEvent.KEYCODE_BUTTON_START: return 6; + + case KeyEvent.KEYCODE_BUTTON_THUMBL: return 7; + case KeyEvent.KEYCODE_BUTTON_THUMBR: return 8; + + case KeyEvent.KEYCODE_BUTTON_L1: return 9; + case KeyEvent.KEYCODE_BUTTON_R1: return 10; + + case KeyEvent.KEYCODE_DPAD_UP: return 11; + case KeyEvent.KEYCODE_DPAD_DOWN: return 12; + case KeyEvent.KEYCODE_DPAD_LEFT: return 13; + case KeyEvent.KEYCODE_DPAD_RIGHT: return 14; + + case KeyEvent.KEYCODE_BUTTON_L2: return 15; + case KeyEvent.KEYCODE_BUTTON_R2: return 16; + case KeyEvent.KEYCODE_BUTTON_SELECT: return 17; + } + + return -1; + } + + + public boolean sendGamepadKey(int keyCode, KeyEvent event) + { + final int key = translateGampadButton(keyCode); + if (key>=0) + { + final int deviceId = event.getDeviceId(); + final boolean isDown = event.getAction() == KeyEvent.ACTION_DOWN; + if (keyCode!=0) { + final MainView me = this; + queueEvent(new Runnable() { + // This method will be called on the rendering thread: + public void run() { + me.HandleResult(NME.onJoyChange(deviceId,key,isDown)); + }}); + return true; + } + } + return false; + } + + // This will only get called if the view is not part of the GameActivity @Override public boolean onKeyDown(final int inKeyCode, KeyEvent event) { // Log.e("VIEW","onKeyDown " + inKeyCode); - Log.v("VIEW", "device of event is " + event.getDeviceId()); final MainView me = this; final int keyCode = translateKey(inKeyCode,event,true); - // Log.v("VIEW","onKeyDown " + inKeyCode + "->" + keyCode); final int deviceId = event.getDeviceId(); if (keyCode!=0) { queueEvent(new Runnable() { // This method will be called on the rendering thread: public void run() { me.HandleResult(NME.onKeyChange(keyCode,keyCode,true,true)); - me.HandleResult(NME.onJoyChange(deviceId,keyCode,true)); + //me.HandleResult(NME.onJoyChange(deviceId,keyCode,true)); }}); return true; } @@ -512,11 +599,11 @@ public void run() { } + // This will only get called if the view is not part of the GameActivity @Override public boolean onKeyUp(final int inKeyCode, KeyEvent event) { //Log.v("VIEW","onKeyUp " + inKeyCode); - Log.v("VIEW", "device of event is " + event.getDeviceId()); final MainView me = this; final int keyCode = translateKey(inKeyCode,event,true); // Log.v("VIEW","onKeyUp " + inKeyCode + "->" + keyCode); @@ -527,7 +614,7 @@ public boolean onKeyUp(final int inKeyCode, KeyEvent event) // This method will be called on the rendering thread: public void run() { me.HandleResult(NME.onKeyChange(keyCode,keyCode,false,false)); - me.HandleResult(NME.onJoyChange(deviceId,keyCode,false)); + //me.HandleResult(NME.onJoyChange(deviceId,keyCode,false)); }}); return true; }