1 /******************************************************************************* 2 * Copyright 2011 See AUTHORS file. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 ******************************************************************************/ 16 17 package com.badlogic.gdx.controllers.gwt.support; 18 19 import com.badlogic.gdx.utils.IntMap; 20 import com.google.gwt.animation.client.AnimationScheduler; 21 import com.google.gwt.core.client.JavaScriptObject; 22 import com.google.gwt.core.client.JsArray; 23 24 public class GamepadSupport { 25 26 private static Ticker ticker = new Ticker(); 27 28 private static GamepadSupportListener listener; 29 30 private static IntMap<Gamepad> gamepads = new IntMap<Gamepad>(); 31 private static IntMap<Gamepad> gamepadsTemp = new IntMap<Gamepad>(); 32 33 public static void init(GamepadSupportListener listener) { 34 GamepadSupport.listener = listener; 35 nativeInit(); 36 } 37 38 public static void startPolling() { 39 consoleLog("startPolling"); 40 ticker.start(); 41 } 42 43 public static void stopPolling() { 44 ticker.stop(); 45 } 46 47 public static void pollGamepads() { 48 JsArray<Gamepad> currentGamepads = nativePollGamepads(); 49 if (currentGamepads != null) { 50 gamepadsTemp.clear(); 51 gamepadsTemp.putAll(gamepads); 52 for (int i = 0, j = currentGamepads.length(); i < j; i++) { 53 Gamepad gamepad = currentGamepads.get(i); 54 if (gamepad != null) { 55 if (!gamepadsTemp.containsKey(gamepad.getIndex())) { 56 onGamepadConnect(gamepad); 57 } 58 gamepadsTemp.remove(gamepad.getIndex()); 59 } 60 } 61 for (Gamepad gamepad : gamepadsTemp.values()) { 62 onGamepadDisconnect(gamepad); 63 } 64 } 65 } 66 67 public static void pollGamepadsStatus() { 68 for (Gamepad gamepad : gamepads.values()) { 69 if (gamepad.getPreviousTimestamp() != gamepad.getTimestamp()) { 70 fireGamepadUpdated(gamepad.getIndex()); 71 } 72 gamepad.setPreviousTimestamp(gamepad.getTimestamp()); 73 } 74 } 75 76 public static Gamepad getGamepad(int index) { 77 return gamepads.get(index); 78 } 79 80 private static void onGamepadConnect(Gamepad gamepad) { 81 consoleLog("onGamepadConnect: " + gamepad.getId()); 82 gamepads.put(gamepad.getIndex(), gamepad); 83 fireGamepadConnected(gamepad.getIndex()); 84 } 85 86 private static void onGamepadDisconnect(Gamepad gamepad) { 87 consoleLog("onGamepadDisconnect: " + gamepad.getId()); 88 gamepads.remove(gamepad.getIndex()); 89 fireGamepadDisconnected(gamepad.getIndex()); 90 } 91 92 private static void fireGamepadConnected(int index) { 93 if (listener != null) { 94 listener.onGamepadConnected(index); 95 } 96 } 97 98 private static void fireGamepadDisconnected(int index) { 99 if (listener != null) { 100 listener.onGamepadDisconnected(index); 101 } 102 } 103 104 private static void fireGamepadUpdated(int index) { 105 if (listener != null) { 106 listener.onGamepadUpdated(index); 107 } 108 } 109 110 private static void handleGamepadConnect(GamepadEvent event) { 111 onGamepadConnect(event.getGamepad()); 112 } 113 private static void handleGamepadDisconnect(GamepadEvent event) { 114 onGamepadDisconnect(event.getGamepad()); 115 } 116 117 private static native void nativeInit() /*-{ 118 var gamepadSupportAvailable = !! navigator.getGamepads || !! navigator.webkitGetGamepads || !! navigator.webkitGamepads || (navigator.userAgent.indexOf('Firefox/') != -1); 119 if (gamepadSupportAvailable) { 120 $wnd.addEventListener('MozGamepadConnected', @com.badlogic.gdx.controllers.gwt.support.GamepadSupport::handleGamepadConnect(Lcom/badlogic/gdx/controllers/gwt/support/GamepadSupport$GamepadEvent;), false); 121 $wnd.addEventListener('MozGamepadDisconnected', @com.badlogic.gdx.controllers.gwt.support.GamepadSupport::handleGamepadDisconnect(Lcom/badlogic/gdx/controllers/gwt/support/GamepadSupport$GamepadEvent;), false); 122 if ( !! navigator.getGamepads || !! navigator.webkitGamepads || !! navigator.webkitGetGamepads) { 123 @com.badlogic.gdx.controllers.gwt.support.GamepadSupport::startPolling()(); 124 } 125 } 126 }-*/; 127 128 private static native JsArray<Gamepad> nativePollGamepads() /*-{ 129 return rawGamepads = (navigator.webkitGetGamepads && navigator.webkitGetGamepads()) || navigator.webkitGamepads; 130 }-*/; 131 132 public static native void consoleLog(String message) /*-{ 133 $wnd.console.log(message); 134 }-*/; 135 136 private static class Ticker implements AnimationScheduler.AnimationCallback { 137 138 private boolean ticking = false; 139 140 public void start() { 141 if (!ticking) { 142 ticking = true; 143 AnimationScheduler.get().requestAnimationFrame(this); 144 } 145 } 146 147 public void stop() { 148 ticking = false; 149 } 150 151 @Override 152 public void execute(double timestamp) { 153 if (ticking) { 154 GamepadSupport.pollGamepads(); 155 GamepadSupport.pollGamepadsStatus(); 156 AnimationScheduler.get().requestAnimationFrame(this); 157 } 158 } 159 } 160 161 private static final class GamepadEvent extends JavaScriptObject { 162 protected GamepadEvent() { 163 // Required by GWT 164 } 165 166 public native Gamepad getGamepad() /*-{ 167 return this.gamepad; 168 }-*/; 169 } 170 }