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.desktop; 18 19 import com.badlogic.gdx.Gdx; 20 import com.badlogic.gdx.Graphics.GraphicsType; 21 import com.badlogic.gdx.controllers.ControlType; 22 import com.badlogic.gdx.controllers.Controller; 23 import com.badlogic.gdx.controllers.ControllerListener; 24 import com.badlogic.gdx.controllers.PovDirection; 25 import com.badlogic.gdx.controllers.desktop.ois.Ois; 26 import com.badlogic.gdx.controllers.desktop.ois.OisJoystick; 27 import com.badlogic.gdx.controllers.desktop.ois.OisJoystick.OisPov; 28 import com.badlogic.gdx.controllers.desktop.ois.OisListener; 29 import com.badlogic.gdx.math.Vector3; 30 import com.badlogic.gdx.utils.Array; 31 import com.badlogic.gdx.utils.GdxRuntimeException; 32 33 import java.awt.Component; 34 import java.lang.reflect.Field; 35 import java.lang.reflect.Method; 36 import java.util.ArrayList; 37 38 import javax.swing.SwingUtilities; 39 40 /** @author Nathan Sweet */ 41 public class OisControllers { 42 final DesktopControllerManager manager; 43 long hwnd = getWindowHandle(); 44 Ois ois = new Ois(hwnd); 45 OisController[] controllers; 46 47 private static final boolean IS_MAC = System.getProperty("os.name").toLowerCase().contains("mac"); 48 private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("windows"); 49 private static final long CHECK_FOR_LOST_WINDOW_HANDLE_INTERVAL = 1000000000L; // in nanoseconds. 1000000000 == 1 second 50 51 public OisControllers (final DesktopControllerManager manager) { 52 this.manager = manager; 53 ArrayList<OisJoystick> joysticks = ois.getJoysticks(); 54 controllers = new OisController[joysticks.size()]; 55 for (int i = 0, n = joysticks.size(); i < n; i++) { 56 OisJoystick joystick = joysticks.get(i); 57 controllers[i] = new OisController(joystick); 58 manager.controllers.add(controllers[i]); 59 } 60 61 new Runnable() { 62 63 private long lastCheckForLostWindowHandleTime; 64 65 public void run () { 66 // we won't do the rather heavy check for a lost window handle each and every frame, but rather each second only 67 long now = System.nanoTime(); 68 if (now - lastCheckForLostWindowHandleTime > CHECK_FOR_LOST_WINDOW_HANDLE_INTERVAL) { 69 lastCheckForLostWindowHandleTime = now; 70 71 long newWindowHandle = getWindowHandle(); 72 if (hwnd != newWindowHandle) { 73 hwnd = newWindowHandle; 74 ois = new Ois(newWindowHandle); 75 76 ArrayList<OisJoystick> joysticks = ois.getJoysticks(); 77 controllers = new OisController[joysticks.size()]; 78 manager.controllers.clear(); 79 for (int i = 0, n = joysticks.size(); i < n; i++) { 80 OisJoystick joystick = joysticks.get(i); 81 controllers[i] = new OisController(joystick); 82 manager.controllers.add(controllers[i]); 83 } 84 } 85 } 86 ois.update(); 87 Gdx.app.postRunnable(this); 88 } 89 }.run(); 90 } 91 92 /** @author Nathan Sweet */ 93 class OisController implements Controller { 94 private final OisJoystick joystick; 95 final Array<ControllerListener> listeners = new Array(); 96 97 public OisController (OisJoystick joystick) { 98 this.joystick = joystick; 99 joystick.setListener(new OisListener() { 100 public void buttonReleased (OisJoystick joystick, int buttonIndex) { 101 Array<ControllerListener> allListeners = manager.listeners; 102 for (int ii = 0, nn = allListeners.size; ii < nn; ii++) 103 allListeners.get(ii).buttonUp(OisController.this, buttonIndex); 104 for (int ii = 0, nn = listeners.size; ii < nn; ii++) 105 listeners.get(ii).buttonUp(OisController.this, buttonIndex); 106 } 107 108 public void buttonPressed (OisJoystick joystick, int buttonIndex) { 109 Array<ControllerListener> allListeners = manager.listeners; 110 for (int ii = 0, nn = allListeners.size; ii < nn; ii++) 111 allListeners.get(ii).buttonDown(OisController.this, buttonIndex); 112 for (int ii = 0, nn = listeners.size; ii < nn; ii++) 113 listeners.get(ii).buttonDown(OisController.this, buttonIndex); 114 } 115 116 public void axisMoved (OisJoystick joystick, int axisIndex, float value) { 117 Array<ControllerListener> allListeners = manager.listeners; 118 for (int ii = 0, nn = allListeners.size; ii < nn; ii++) 119 allListeners.get(ii).axisMoved(OisController.this, axisIndex, value); 120 for (int ii = 0, nn = listeners.size; ii < nn; ii++) 121 listeners.get(ii).axisMoved(OisController.this, axisIndex, value); 122 } 123 124 public void povMoved (OisJoystick joystick, int povIndex, OisPov ignored) { 125 PovDirection value = getPov(povIndex); 126 Array<ControllerListener> allListeners = manager.listeners; 127 for (int ii = 0, nn = allListeners.size; ii < nn; ii++) 128 allListeners.get(ii).povMoved(OisController.this, povIndex, value); 129 for (int ii = 0, nn = listeners.size; ii < nn; ii++) 130 listeners.get(ii).povMoved(OisController.this, povIndex, value); 131 } 132 133 public void xSliderMoved (OisJoystick joystick, int sliderIndex, boolean value) { 134 Array<ControllerListener> allListeners = manager.listeners; 135 for (int ii = 0, nn = allListeners.size; ii < nn; ii++) 136 allListeners.get(ii).xSliderMoved(OisController.this, sliderIndex, value); 137 for (int ii = 0, nn = listeners.size; ii < nn; ii++) 138 listeners.get(ii).xSliderMoved(OisController.this, sliderIndex, value); 139 } 140 141 public void ySliderMoved (OisJoystick joystick, int sliderIndex, boolean value) { 142 Array<ControllerListener> allListeners = manager.listeners; 143 for (int ii = 0, nn = allListeners.size; ii < nn; ii++) 144 allListeners.get(ii).ySliderMoved(OisController.this, sliderIndex, value); 145 for (int ii = 0, nn = listeners.size; ii < nn; ii++) 146 listeners.get(ii).ySliderMoved(OisController.this, sliderIndex, value); 147 } 148 }); 149 } 150 151 public boolean getButton (int buttonIndex) { 152 return joystick.isButtonPressed(buttonIndex); 153 } 154 155 public float getAxis (int axisIndex) { 156 return joystick.getAxis(axisIndex); 157 } 158 159 public PovDirection getPov (int povIndex) { 160 OisPov pov = joystick.getPov(povIndex); 161 switch (pov) { 162 case Centered: 163 return PovDirection.center; 164 case East: 165 return PovDirection.east; 166 case North: 167 return PovDirection.north; 168 case NorthEast: 169 return PovDirection.northEast; 170 case NorthWest: 171 return PovDirection.northWest; 172 case South: 173 return PovDirection.south; 174 case SouthEast: 175 return PovDirection.southEast; 176 case SouthWest: 177 return PovDirection.southWest; 178 case West: 179 return PovDirection.west; 180 } 181 return null; // Impossible. 182 } 183 184 public boolean getSliderX (int sliderIndex) { 185 return joystick.getSliderX(sliderIndex); 186 } 187 188 public boolean getSliderY (int sliderIndex) { 189 return joystick.getSliderY(sliderIndex); 190 } 191 192 public Vector3 getAccelerometer (int accelerometerIndex) { 193 throw new GdxRuntimeException("Invalid accelerometer index: " + accelerometerIndex); 194 } 195 196 public void setAccelerometerSensitivity (float sensitivity) { 197 } 198 199 public int getControlCount (ControlType type) { 200 switch (type) { 201 case button: 202 return joystick.getButtonCount(); 203 case axis: 204 return joystick.getAxisCount(); 205 case slider: 206 return joystick.getSliderCount(); 207 case pov: 208 return joystick.getPovCount(); 209 } 210 return 0; 211 } 212 213 public void addListener (ControllerListener listener) { 214 listeners.add(listener); 215 } 216 217 public void removeListener (ControllerListener listener) { 218 listeners.removeValue(listener, true); 219 } 220 221 public String getName () { 222 return joystick.getName(); 223 } 224 225 public String toString () { 226 return joystick.getName(); 227 } 228 } 229 230 /** Returns the window handle from LWJGL needed by OIS. */ 231 static public long getWindowHandle () { 232 // don't need a window handle for Mac OS X 233 if (IS_MAC) { 234 return 0; 235 } 236 237 try { 238 if (Gdx.graphics.getType() == GraphicsType.JGLFW) 239 return (Long)Gdx.graphics.getClass().getDeclaredMethod("getWindow").invoke(null); 240 241 if (Gdx.graphics.getType() == GraphicsType.LWJGL) { 242 if (Gdx.app.getClass().getName().equals("com.badlogic.gdx.backends.lwjgl.LwjglCanvas")) { 243 Class canvasClass = Class.forName("com.badlogic.gdx.backends.lwjgl.LwjglCanvas"); 244 Object canvas = canvasClass.getDeclaredMethod("getCanvas").invoke(Gdx.app); 245 return (Long)invokeMethod(invokeMethod(SwingUtilities.windowForComponent((Component)canvas), "getPeer"), "getHWnd"); 246 } 247 248 Class displayClass = Class.forName("org.lwjgl.opengl.Display"); 249 Method getImplementation = displayClass.getDeclaredMethod("getImplementation", new Class[0]); 250 getImplementation.setAccessible(true); 251 Object display = getImplementation.invoke(null, (Object[])null); 252 Field field = display.getClass().getDeclaredField(IS_WINDOWS ? "hwnd" : "parent_window"); 253 field.setAccessible(true); 254 return (Long)field.get(display); 255 } 256 } catch (Exception ex) { 257 throw new RuntimeException("Unable to get window handle.", ex); 258 } 259 260 return 0; 261 } 262 263 static private Object invokeMethod (Object object, String methodName) throws Exception { 264 for (Method m : object.getClass().getMethods()) 265 if (m.getName().equals(methodName)) return m.invoke(object); 266 throw new RuntimeException("Could not find method '" + methodName + "' on class: " + object.getClass()); 267 } 268 269 } 270