Home | History | Annotate | Download | only in desktop
      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