OSDN Git Service

f421de1b9e2037b1c8cb1fc737a13780d4db702d
[mikumikustudio/libgdx-mikumikustudio.git] / extensions / gdx-controllers / gdx-controllers-android / src / com / badlogic / gdx / controllers / android / AndroidControllers.java
1 /*******************************************************************************\r
2  * Copyright 2011 See AUTHORS file.\r
3  * \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  * \r
8  *   http://www.apache.org/licenses/LICENSE-2.0\r
9  * \r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  ******************************************************************************/
16
17 package com.badlogic.gdx.controllers.android;\r
18 \r
19 import android.view.InputDevice;\r
20 import android.view.KeyEvent;\r
21 import android.view.MotionEvent;\r
22 import android.view.View;\r
23 import android.view.View.OnGenericMotionListener;\r
24 import android.view.View.OnKeyListener;\r
25 \r
26 import com.badlogic.gdx.Gdx;\r
27 import com.badlogic.gdx.LifecycleListener;\r
28 import com.badlogic.gdx.backends.android.AndroidInput;\r
29 import com.badlogic.gdx.backends.android.AndroidInputThreePlus;\r
30 import com.badlogic.gdx.controllers.Controller;\r
31 import com.badlogic.gdx.controllers.ControllerListener;\r
32 import com.badlogic.gdx.controllers.ControllerManager;\r
33 import com.badlogic.gdx.utils.Array;\r
34 import com.badlogic.gdx.utils.IntMap;\r
35 import com.badlogic.gdx.utils.IntMap.Entry;\r
36 import com.badlogic.gdx.utils.Pool;\r
37 \r
38 public class AndroidControllers implements LifecycleListener, ControllerManager, OnKeyListener, OnGenericMotionListener {\r
39         private final static String TAG = "AndroidControllers";\r
40         private final IntMap<AndroidController> controllerMap = new IntMap<AndroidController>();\r
41         private final Array<Controller> controllers = new Array<Controller>();\r
42         private final Array<ControllerListener> listeners = new Array<ControllerListener>();\r
43         private final Array<AndroidControllerEvent> eventQueue = new Array<AndroidControllerEvent>();\r
44         private final Pool<AndroidControllerEvent> eventPool = new Pool<AndroidControllerEvent>() {\r
45                 @Override\r
46                 protected AndroidControllerEvent newObject () {\r
47                         return new AndroidControllerEvent();\r
48                 }\r
49         };\r
50         \r
51         public AndroidControllers() {\r
52                 Gdx.app.addLifecycleListener(this);\r
53                 gatherControllers(false);\r
54                 setupEventQueue();\r
55                 ((AndroidInput)Gdx.input).addKeyListener(this);\r
56                 ((AndroidInputThreePlus)Gdx.input).addGenericMotionListener(this);\r
57                 \r
58                 // use InputManager on Android +4.1 to receive (dis-)connect events\r
59                 if(Gdx.app.getVersion() >= 16) {\r
60                         try {\r
61                                 String className = "com.badlogic.gdx.controllers.android.ControllerLifeCycleListener";\r
62                                 Class.forName(className).getConstructor(AndroidControllers.class).newInstance(this);\r
63                         } catch(Exception e) {\r
64                                 Gdx.app.log(TAG, "Couldn't register controller life-cycle listener");\r
65                         }\r
66                 }\r
67         }\r
68         \r
69         private void setupEventQueue() {\r
70                 new Runnable() {\r
71                         @SuppressWarnings("synthetic-access")\r
72                         @Override\r
73                         public void run () {\r
74                                 synchronized(eventQueue) {\r
75                                         for(AndroidControllerEvent event: eventQueue) {\r
76                                                 switch(event.type) {\r
77                                                         case AndroidControllerEvent.CONNECTED:\r
78                                                                 controllers.add(event.controller);\r
79                                                                 for(ControllerListener listener: listeners) {\r
80                                                                         listener.connected(event.controller);\r
81                                                                 }\r
82                                                                 break;\r
83                                                         case AndroidControllerEvent.DISCONNECTED:\r
84                                                                 controllers.removeValue(event.controller, true);\r
85                                                                 for(ControllerListener listener: listeners) {\r
86                                                                         listener.disconnected(event.controller);\r
87                                                                 }\r
88                                                                 for(ControllerListener listener: event.controller.getListeners()) {\r
89                                                                         listener.disconnected(event.controller);\r
90                                                                 }\r
91                                                                 break;\r
92                                                         case AndroidControllerEvent.BUTTON_DOWN:\r
93                                                                 event.controller.buttons.put(event.code, event.code);\r
94                                                                 for(ControllerListener listener: listeners) {\r
95                                                                         if(listener.buttonDown(event.controller, event.code)) break;\r
96                                                                 }\r
97                                                                 for(ControllerListener listener: event.controller.getListeners()) {\r
98                                                                         if(listener.buttonDown(event.controller, event.code)) break;\r
99                                                                 }\r
100                                                                 break;\r
101                                                         case AndroidControllerEvent.BUTTON_UP:\r
102                                                                 event.controller.buttons.remove(event.code, 0);\r
103                                                                 for(ControllerListener listener: listeners) {\r
104                                                                         if(listener.buttonUp(event.controller, event.code)) break;\r
105                                                                 }\r
106                                                                 for(ControllerListener listener: event.controller.getListeners()) {\r
107                                                                         if(listener.buttonUp(event.controller, event.code)) break;\r
108                                                                 }\r
109                                                                 break;\r
110                                                         case AndroidControllerEvent.AXIS:\r
111                                                                 event.controller.axes[event.code] = event.axisValue;\r
112                                                                 for(ControllerListener listener: listeners) {\r
113                                                                         if(listener.axisMoved(event.controller, event.code, event.axisValue)) break;\r
114                                                                 }\r
115                                                                 for(ControllerListener listener: event.controller.getListeners()) {\r
116                                                                         if(listener.axisMoved(event.controller, event.code, event.axisValue)) break;\r
117                                                                 }\r
118                                                                 break;\r
119                                                         default:\r
120                                                 }\r
121                                         }\r
122                                         eventPool.freeAll(eventQueue);\r
123                                         eventQueue.clear();\r
124                                 }\r
125                                 Gdx.app.postRunnable(this);\r
126                         }\r
127                 }.run();\r
128         }\r
129         \r
130         @Override\r
131         public boolean onGenericMotion (View view, MotionEvent motionEvent) {\r
132                 if((motionEvent.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0) return false;\r
133                 AndroidController controller = controllerMap.get(motionEvent.getDeviceId());\r
134                 if(controller != null) {\r
135                         synchronized(eventQueue) {\r
136                                 final int historySize = motionEvent.getHistorySize();\r
137                                 int axisIndex = 0;\r
138             for (int axisId: controller.axesIds) {\r
139                 float axisValue = motionEvent.getAxisValue(axisId);\r
140                 if(controller.getAxis(axisIndex) == axisValue) {\r
141                         axisIndex++;\r
142                         continue;\r
143                 }\r
144                 AndroidControllerEvent event = eventPool.obtain();\r
145                                 event.type = AndroidControllerEvent.AXIS;\r
146                                 event.controller = controller;\r
147                                 event.code = axisIndex;\r
148                                 event.axisValue = axisValue;\r
149                                 eventQueue.add(event);\r
150                                 axisIndex++;\r
151             }\r
152                         }\r
153                         return true;\r
154                 }\r
155                 return false;\r
156         }\r
157 \r
158         @Override\r
159         public boolean onKey (View view, int keyCode, KeyEvent keyEvent) {\r
160                 AndroidController controller = controllerMap.get(keyEvent.getDeviceId());\r
161                 if(controller != null) {\r
162                         if(controller.getButton(keyCode) && keyEvent.getAction() == KeyEvent.ACTION_DOWN) {\r
163                                 return true;\r
164                         }\r
165                         synchronized(eventQueue) {\r
166                                 AndroidControllerEvent event = eventPool.obtain();\r
167                                 event.controller = controller;\r
168                                 if(keyEvent.getAction() == KeyEvent.ACTION_DOWN) {\r
169                                         event.type = AndroidControllerEvent.BUTTON_DOWN;\r
170                                 } else {\r
171                                         event.type = AndroidControllerEvent.BUTTON_UP;\r
172                                 }\r
173                                 event.code = keyCode;\r
174                                 eventQueue.add(event);\r
175                         }\r
176                         return true;\r
177                 } else {\r
178                         return false;\r
179                 }\r
180         }\r
181         \r
182         private void gatherControllers(boolean sendEvent) {\r
183                 // gather all joysticks and gamepads, remove any disconnected ones\r
184                 IntMap<AndroidController> removedControllers = new IntMap<AndroidController>();\r
185                 removedControllers.putAll(controllerMap);\r
186                 \r
187                 for(int deviceId: InputDevice.getDeviceIds()) {\r
188                         InputDevice device = InputDevice.getDevice(deviceId);\r
189                         AndroidController controller = controllerMap.get(deviceId);\r
190                         if(controller != null) {\r
191                                 removedControllers.remove(deviceId);\r
192                         } else {\r
193                                 addController(deviceId, sendEvent);\r
194                         }\r
195                 }\r
196                 \r
197                 for(Entry<AndroidController> entry: removedControllers.entries()) {\r
198                         removeController(entry.key);\r
199                 }\r
200         }\r
201         \r
202         protected void addController(int deviceId, boolean sendEvent) {\r
203                 InputDevice device = InputDevice.getDevice(deviceId);\r
204                 if(!isController(device)) return;\r
205                 String name = device.getName();\r
206                 AndroidController controller = new AndroidController(deviceId, name);\r
207                 controllerMap.put(deviceId, controller);\r
208                 if(sendEvent) {\r
209                         synchronized(eventQueue) {\r
210                                 AndroidControllerEvent event = eventPool.obtain();\r
211                                 event.type = AndroidControllerEvent.CONNECTED;\r
212                                 event.controller = controller;\r
213                                 eventQueue.add(event);\r
214                         }\r
215                 } else {\r
216                         controllers.add(controller);\r
217                 }\r
218                 Gdx.app.log(TAG, "added controller '" + name + "'");\r
219         }\r
220         \r
221         protected void removeController(int deviceId) {\r
222                 AndroidController controller = controllerMap.remove(deviceId);\r
223                 if(controller != null) {\r
224                         synchronized(eventQueue) {\r
225                                 AndroidControllerEvent event = eventPool.obtain();\r
226                                 event.type = AndroidControllerEvent.DISCONNECTED;\r
227                                 event.controller = controller;\r
228                                 eventQueue.add(event);\r
229                         }\r
230                         Gdx.app.log(TAG, "removed controller '" + controller.getName() + "'");\r
231                 }\r
232         }\r
233         \r
234         private boolean isController(InputDevice device) {\r
235                 return (device.getSources() & InputDevice.SOURCE_JOYSTICK) != 0;\r
236         }\r
237 \r
238         @Override\r
239         public Array<Controller> getControllers () {\r
240                 return controllers;\r
241         }\r
242 \r
243         @Override\r
244         public void addListener (ControllerListener listener) {\r
245                 synchronized(eventQueue) {\r
246                         listeners.add(listener);\r
247                 }\r
248         }\r
249 \r
250         @Override\r
251         public void removeListener (ControllerListener listener) {\r
252                 synchronized(eventQueue) {\r
253                         listeners.removeValue(listener, true);\r
254                 }\r
255         }\r
256 \r
257         @Override\r
258         public void pause () {\r
259                 Gdx.app.log(TAG, "controllers paused");\r
260         }\r
261 \r
262         @Override\r
263         public void resume () {\r
264                 gatherControllers(true);\r
265                 Gdx.app.log(TAG, "controllers resumed");                \r
266         }\r
267 \r
268         @Override\r
269         public void dispose () {\r
270         }\r
271 }