Implement HTML5 gamepad support (thanks @bmfs, resolves #624)
This commit is contained in:
@@ -7,19 +7,27 @@ import lime.app.Application;
|
||||
import lime.app.Config;
|
||||
import lime.audio.AudioManager;
|
||||
import lime.graphics.Renderer;
|
||||
import lime.ui.GamepadAxis;
|
||||
import lime.ui.KeyCode;
|
||||
import lime.ui.KeyModifier;
|
||||
import lime.ui.Gamepad;
|
||||
import lime.ui.GamepadButton;
|
||||
import lime.ui.Joystick;
|
||||
import lime.ui.Window;
|
||||
|
||||
@:access(lime._backend.html5.HTML5Window)
|
||||
@:access(lime.app.Application)
|
||||
@:access(lime.graphics.Renderer)
|
||||
@:access(lime.ui.Gamepad)
|
||||
@:access(lime.ui.Joystick)
|
||||
@:access(lime.ui.Window)
|
||||
|
||||
|
||||
class HTML5Application {
|
||||
|
||||
|
||||
private var gameDeviceCache = new Map<Int, GameDeviceData> ();
|
||||
|
||||
private var currentUpdate:Float;
|
||||
private var deltaTime:Float;
|
||||
private var framePeriod:Float;
|
||||
@@ -190,6 +198,8 @@ class HTML5Application {
|
||||
|
||||
private function handleApplicationEvent (?__):Void {
|
||||
|
||||
updateGameDevices ();
|
||||
|
||||
currentUpdate = Date.now ().getTime ();
|
||||
|
||||
if (currentUpdate >= nextUpdate) {
|
||||
@@ -331,4 +341,187 @@ class HTML5Application {
|
||||
}
|
||||
|
||||
|
||||
private function updateGameDevices ():Void {
|
||||
|
||||
var devices = Joystick.__getDeviceData ();
|
||||
if (devices == null) return;
|
||||
|
||||
var id, gamepad, joystick, data:Dynamic, cache;
|
||||
|
||||
for (i in 0...devices.length) {
|
||||
|
||||
id = i;
|
||||
data = devices[id];
|
||||
|
||||
if (data == null) continue;
|
||||
|
||||
if (!gameDeviceCache.exists (id)) {
|
||||
|
||||
cache = new GameDeviceData ();
|
||||
cache.id = id;
|
||||
cache.connected = data.connected;
|
||||
|
||||
for (i in 0...data.buttons.length) {
|
||||
|
||||
cache.buttons.push (data.buttons[i].value);
|
||||
|
||||
}
|
||||
|
||||
for (i in 0...data.axes.length) {
|
||||
|
||||
cache.axes.push (data.axes[i]);
|
||||
|
||||
}
|
||||
|
||||
if (data.mapping == "standard") {
|
||||
|
||||
cache.isGamepad = true;
|
||||
|
||||
}
|
||||
|
||||
gameDeviceCache.set (id, cache);
|
||||
|
||||
if (data.connected) {
|
||||
|
||||
Joystick.__connect (id);
|
||||
|
||||
if (cache.isGamepad) {
|
||||
|
||||
Gamepad.__connect (id);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cache = gameDeviceCache.get (id);
|
||||
|
||||
joystick = Joystick.devices.get (id);
|
||||
gamepad = Gamepad.devices.get (id);
|
||||
|
||||
if (data.connected) {
|
||||
|
||||
var button:GamepadButton;
|
||||
var value:Float;
|
||||
|
||||
for (i in 0...data.buttons.length) {
|
||||
|
||||
value = data.buttons[i].value;
|
||||
|
||||
if (value != cache.buttons[i]) {
|
||||
|
||||
if (i == 6) {
|
||||
|
||||
joystick.onAxisMove.dispatch (data.axes.length, value);
|
||||
if (gamepad != null) gamepad.onAxisMove.dispatch (GamepadAxis.TRIGGER_LEFT, value);
|
||||
|
||||
} else if (i == 7) {
|
||||
|
||||
joystick.onAxisMove.dispatch (data.axes.length + 1, value);
|
||||
if (gamepad != null) gamepad.onAxisMove.dispatch (GamepadAxis.TRIGGER_RIGHT, value);
|
||||
|
||||
} else {
|
||||
|
||||
if (value > 0) {
|
||||
|
||||
joystick.onButtonDown.dispatch (i);
|
||||
|
||||
} else {
|
||||
|
||||
joystick.onButtonUp.dispatch (i);
|
||||
|
||||
}
|
||||
|
||||
if (gamepad != null) {
|
||||
|
||||
button = switch (i) {
|
||||
|
||||
case 0: GamepadButton.A;
|
||||
case 1: GamepadButton.B;
|
||||
case 2: GamepadButton.X;
|
||||
case 3: GamepadButton.Y;
|
||||
case 4: GamepadButton.LEFT_SHOULDER;
|
||||
case 5: GamepadButton.RIGHT_SHOULDER;
|
||||
case 8: GamepadButton.BACK;
|
||||
case 9: GamepadButton.START;
|
||||
case 10: GamepadButton.LEFT_STICK;
|
||||
case 11: GamepadButton.RIGHT_STICK;
|
||||
case 12: GamepadButton.DPAD_UP;
|
||||
case 13: GamepadButton.DPAD_DOWN;
|
||||
case 14: GamepadButton.DPAD_LEFT;
|
||||
case 15: GamepadButton.DPAD_RIGHT;
|
||||
case 16: GamepadButton.GUIDE;
|
||||
default: continue;
|
||||
|
||||
}
|
||||
|
||||
if (value > 0) {
|
||||
|
||||
gamepad.onButtonDown.dispatch (button);
|
||||
|
||||
} else {
|
||||
|
||||
gamepad.onButtonUp.dispatch (button);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cache.buttons[i] = value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (i in 0...data.axes.length) {
|
||||
|
||||
if (data.axes[i] != cache.axes[i]) {
|
||||
|
||||
joystick.onAxisMove.dispatch (i, data.axes[i]);
|
||||
if (gamepad != null) gamepad.onAxisMove.dispatch (i, data.axes[i]);
|
||||
cache.axes[i] = data.axes[i];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if (cache.connected) {
|
||||
|
||||
cache.connected = false;
|
||||
|
||||
Joystick.__disconnect (id);
|
||||
Gamepad.__disconnect (id);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
class GameDeviceData {
|
||||
|
||||
|
||||
public var connected:Bool;
|
||||
public var id:Int;
|
||||
public var isGamepad:Bool;
|
||||
public var buttons:Array<Float>;
|
||||
public var axes:Array<Float>;
|
||||
|
||||
|
||||
public function new () {
|
||||
|
||||
connected = true;
|
||||
buttons = [];
|
||||
axes = [];
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -19,6 +19,8 @@ import lime.app.Application;
|
||||
import lime.graphics.Image;
|
||||
import lime.system.Display;
|
||||
import lime.system.System;
|
||||
import lime.ui.Gamepad;
|
||||
import lime.ui.Joystick;
|
||||
import lime.ui.Touch;
|
||||
import lime.ui.Window;
|
||||
|
||||
@@ -29,6 +31,8 @@ typedef InputEvent = js.html.Event;
|
||||
#end
|
||||
|
||||
@:access(lime.app.Application)
|
||||
@:access(lime.ui.Gamepad)
|
||||
@:access(lime.ui.Joystick)
|
||||
@:access(lime.ui.Window)
|
||||
|
||||
|
||||
@@ -201,6 +205,9 @@ class HTML5Window {
|
||||
element.addEventListener ("touchmove", handleTouchEvent, true);
|
||||
element.addEventListener ("touchend", handleTouchEvent, true);
|
||||
|
||||
element.addEventListener ("gamepadconnected", handleGamepadEvent, true);
|
||||
element.addEventListener ("gamepaddisconnected", handleGamepadEvent, true);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -238,6 +245,34 @@ class HTML5Window {
|
||||
}
|
||||
|
||||
|
||||
private function handleGamepadEvent (event:Dynamic):Void {
|
||||
|
||||
switch (event.type) {
|
||||
|
||||
case "gamepadconnected":
|
||||
|
||||
trace ("GAMEPAD CONNECTED");
|
||||
|
||||
Joystick.__connect (event.gamepad.index);
|
||||
|
||||
if (event.gamepad.mapping == "standard") {
|
||||
|
||||
Gamepad.__connect (event.gamepad.index);
|
||||
|
||||
}
|
||||
|
||||
case "gamepaddisconnected":
|
||||
|
||||
Joystick.__disconnect (event.gamepad.index);
|
||||
Gamepad.__disconnect (event.gamepad.index);
|
||||
|
||||
default:
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private function handleInputEvent (event:InputEvent):Void {
|
||||
|
||||
if (textInput.value != "") {
|
||||
|
||||
@@ -190,20 +190,11 @@ class NativeApplication {
|
||||
|
||||
case CONNECT:
|
||||
|
||||
if (!Gamepad.devices.exists (gamepadEventInfo.id)) {
|
||||
|
||||
var gamepad = new Gamepad (gamepadEventInfo.id);
|
||||
Gamepad.devices.set (gamepadEventInfo.id, gamepad);
|
||||
Gamepad.onConnect.dispatch (gamepad);
|
||||
|
||||
}
|
||||
Gamepad.__connect (gamepadEventInfo.id);
|
||||
|
||||
case DISCONNECT:
|
||||
|
||||
var gamepad = Gamepad.devices.get (gamepadEventInfo.id);
|
||||
if (gamepad != null) gamepad.connected = false;
|
||||
Gamepad.devices.remove (gamepadEventInfo.id);
|
||||
if (gamepad != null) gamepad.onDisconnect.dispatch ();
|
||||
Gamepad.__disconnect (gamepadEventInfo.id);
|
||||
|
||||
}
|
||||
|
||||
@@ -241,20 +232,11 @@ class NativeApplication {
|
||||
|
||||
case CONNECT:
|
||||
|
||||
if (!Joystick.devices.exists (joystickEventInfo.id)) {
|
||||
|
||||
var joystick = new Joystick (joystickEventInfo.id);
|
||||
Joystick.devices.set (joystickEventInfo.id, joystick);
|
||||
Joystick.onConnect.dispatch (joystick);
|
||||
|
||||
}
|
||||
Joystick.__connect (joystickEventInfo.id);
|
||||
|
||||
case DISCONNECT:
|
||||
|
||||
var joystick = Joystick.devices.get (joystickEventInfo.id);
|
||||
if (joystick != null) joystick.connected = false;
|
||||
Joystick.devices.remove (joystickEventInfo.id);
|
||||
if (joystick != null) joystick.onDisconnect.dispatch ();
|
||||
Joystick.__disconnect (joystickEventInfo.id);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -64,8 +64,8 @@ class Application extends Module {
|
||||
onExit.add (onModuleExit);
|
||||
onUpdate.add (update);
|
||||
|
||||
Gamepad.onConnect.add (onGamepadConnect);
|
||||
Joystick.onConnect.add (onJoystickConnect);
|
||||
Gamepad.onConnect.add (__onGamepadConnect);
|
||||
Joystick.onConnect.add (__onJoystickConnect);
|
||||
Touch.onStart.add (onTouchStart);
|
||||
Touch.onMove.add (onTouchMove);
|
||||
Touch.onEnd.add (onTouchEnd);
|
||||
@@ -264,11 +264,6 @@ class Application extends Module {
|
||||
|
||||
}
|
||||
|
||||
gamepad.onAxisMove.add (onGamepadAxisMove.bind (gamepad));
|
||||
gamepad.onButtonDown.add (onGamepadButtonDown.bind (gamepad));
|
||||
gamepad.onButtonUp.add (onGamepadButtonUp.bind (gamepad));
|
||||
gamepad.onDisconnect.add (onGamepadDisconnect.bind (gamepad));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -324,13 +319,6 @@ class Application extends Module {
|
||||
|
||||
}
|
||||
|
||||
joystick.onAxisMove.add (onJoystickAxisMove.bind (joystick));
|
||||
joystick.onButtonDown.add (onJoystickButtonDown.bind (joystick));
|
||||
joystick.onButtonUp.add (onJoystickButtonUp.bind (joystick));
|
||||
joystick.onDisconnect.add (onJoystickDisconnect.bind (joystick));
|
||||
joystick.onHatMove.add (onJoystickHatMove.bind (joystick));
|
||||
joystick.onTrackballMove.add (onJoystickTrackballMove.bind (joystick));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -802,6 +790,32 @@ class Application extends Module {
|
||||
}
|
||||
|
||||
|
||||
@:noCompletion private function __onGamepadConnect (gamepad:Gamepad):Void {
|
||||
|
||||
onGamepadConnect (gamepad);
|
||||
|
||||
gamepad.onAxisMove.add (onGamepadAxisMove.bind (gamepad));
|
||||
gamepad.onButtonDown.add (onGamepadButtonDown.bind (gamepad));
|
||||
gamepad.onButtonUp.add (onGamepadButtonUp.bind (gamepad));
|
||||
gamepad.onDisconnect.add (onGamepadDisconnect.bind (gamepad));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@:noCompletion private function __onJoystickConnect (joystick:Joystick):Void {
|
||||
|
||||
onJoystickConnect (joystick);
|
||||
|
||||
joystick.onAxisMove.add (onJoystickAxisMove.bind (joystick));
|
||||
joystick.onButtonDown.add (onJoystickButtonDown.bind (joystick));
|
||||
joystick.onButtonUp.add (onJoystickButtonUp.bind (joystick));
|
||||
joystick.onDisconnect.add (onJoystickDisconnect.bind (joystick));
|
||||
joystick.onHatMove.add (onJoystickHatMove.bind (joystick));
|
||||
joystick.onTrackballMove.add (onJoystickTrackballMove.bind (joystick));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Get & Set Methods
|
||||
|
||||
@@ -59,7 +59,11 @@ class Module implements IModule {
|
||||
* Called when a gamepad is connected
|
||||
* @param gamepad The gamepad that was connected
|
||||
*/
|
||||
public function onGamepadConnect (gamepad:Gamepad):Void { }
|
||||
public function onGamepadConnect (gamepad:Gamepad):Void {
|
||||
|
||||
trace ("onGamepadConnect (module)");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,8 @@ import lime.app.Event;
|
||||
@:build(lime.system.CFFI.build())
|
||||
#end
|
||||
|
||||
@:access(lime.ui.Joystick)
|
||||
|
||||
|
||||
class Gamepad {
|
||||
|
||||
@@ -41,6 +43,29 @@ class Gamepad {
|
||||
}
|
||||
|
||||
|
||||
@:noCompletion private static function __connect (id:Int):Void {
|
||||
|
||||
if (!devices.exists (id)) {
|
||||
|
||||
var gamepad = new Gamepad (id);
|
||||
devices.set (id, gamepad);
|
||||
onConnect.dispatch (gamepad);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@:noCompletion private static function __disconnect (id:Int):Void {
|
||||
|
||||
var gamepad = devices.get (id);
|
||||
if (gamepad != null) gamepad.connected = false;
|
||||
devices.remove (id);
|
||||
if (gamepad != null) gamepad.onDisconnect.dispatch ();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Get & Set Methods
|
||||
@@ -52,6 +77,9 @@ class Gamepad {
|
||||
|
||||
#if ((cpp || neko || nodejs) && !macro)
|
||||
return lime_gamepad_get_device_guid (this.id);
|
||||
#elseif (js && html5)
|
||||
var devices = Joystick.__getDeviceData ();
|
||||
return devices[this.id].id;
|
||||
#else
|
||||
return null;
|
||||
#end
|
||||
@@ -63,6 +91,9 @@ class Gamepad {
|
||||
|
||||
#if ((cpp || neko || nodejs) && !macro)
|
||||
return lime_gamepad_get_device_name (this.id);
|
||||
#elseif (js && html5)
|
||||
var devices = Joystick.__getDeviceData ();
|
||||
return devices[this.id].id;
|
||||
#else
|
||||
return null;
|
||||
#end
|
||||
|
||||
@@ -38,6 +38,38 @@ class Joystick {
|
||||
}
|
||||
|
||||
|
||||
@:noCompletion private static function __connect (id:Int):Void {
|
||||
|
||||
if (!devices.exists (id)) {
|
||||
|
||||
var joystick = new Joystick (id);
|
||||
devices.set (id, joystick);
|
||||
onConnect.dispatch (joystick);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@:noCompletion private static function __disconnect (id:Int):Void {
|
||||
|
||||
var joystick = devices.get (id);
|
||||
if (joystick != null) joystick.connected = false;
|
||||
devices.remove (id);
|
||||
if (joystick != null) joystick.onDisconnect.dispatch ();
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if (js && html5)
|
||||
@:noCompletion private static function __getDeviceData ():Array<Dynamic> {
|
||||
|
||||
return (untyped navigator.getGamepads) ? untyped navigator.getGamepads () : (untyped navigator.webkitGetGamepads) ? untyped navigator.webkitGetGamepads () : null;
|
||||
|
||||
}
|
||||
#end
|
||||
|
||||
|
||||
|
||||
|
||||
// Get & Set Methods
|
||||
@@ -49,6 +81,9 @@ class Joystick {
|
||||
|
||||
#if ((cpp || neko || nodejs) && !macro)
|
||||
return lime_joystick_get_device_guid (this.id);
|
||||
#elseif (js && html5)
|
||||
var devices = __getDeviceData ();
|
||||
return devices[this.id].id;
|
||||
#else
|
||||
return null;
|
||||
#end
|
||||
@@ -60,6 +95,9 @@ class Joystick {
|
||||
|
||||
#if ((cpp || neko || nodejs) && !macro)
|
||||
return lime_joystick_get_device_name (this.id);
|
||||
#elseif (js && html5)
|
||||
var devices = __getDeviceData ();
|
||||
return devices[this.id].id;
|
||||
#else
|
||||
return null;
|
||||
#end
|
||||
@@ -71,6 +109,9 @@ class Joystick {
|
||||
|
||||
#if ((cpp || neko || nodejs) && !macro)
|
||||
return lime_joystick_get_num_axes (this.id);
|
||||
#elseif (js && html5)
|
||||
var devices = __getDeviceData ();
|
||||
return devices[this.id].axes.length;
|
||||
#else
|
||||
return 0;
|
||||
#end
|
||||
@@ -82,6 +123,9 @@ class Joystick {
|
||||
|
||||
#if ((cpp || neko || nodejs) && !macro)
|
||||
return lime_joystick_get_num_buttons (this.id);
|
||||
#elseif (js && html5)
|
||||
var devices = __getDeviceData ();
|
||||
return devices[this.id].buttons.length;
|
||||
#else
|
||||
return 0;
|
||||
#end
|
||||
|
||||
Reference in New Issue
Block a user