1 /*******************************************************************************
\r
2 * Copyright 2011 See AUTHORS file.
\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
8 * http://www.apache.org/licenses/LICENSE-2.0
\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 ******************************************************************************/
\r
16 package com.badlogic.gdx.backends.ios;
\r
18 import cli.MonoTouch.Foundation.NSObject;
\r
19 import cli.MonoTouch.Foundation.NSSet;
\r
20 import cli.MonoTouch.Foundation.NSSetEnumerator;
\r
21 import cli.MonoTouch.UIKit.UIAcceleration;
\r
22 import cli.MonoTouch.UIKit.UIAccelerometer;
\r
23 import cli.MonoTouch.UIKit.UIAccelerometerDelegate;
\r
24 import cli.MonoTouch.UIKit.UIAlertView;
\r
25 import cli.MonoTouch.UIKit.UIAlertViewDelegate;
\r
26 import cli.MonoTouch.UIKit.UIAlertViewStyle;
\r
27 import cli.MonoTouch.UIKit.UIEvent;
\r
28 import cli.MonoTouch.UIKit.UITextField;
\r
29 import cli.MonoTouch.UIKit.UITouch;
\r
30 import cli.MonoTouch.UIKit.UITouchPhase;
\r
31 import cli.MonoTouch.UIKit.UIView;
\r
32 import cli.System.Drawing.PointF;
\r
34 import com.badlogic.gdx.Input;
\r
35 import com.badlogic.gdx.InputProcessor;
\r
36 import com.badlogic.gdx.utils.Array;
\r
37 import com.badlogic.gdx.utils.GdxRuntimeException;
\r
38 import com.badlogic.gdx.utils.Pool;
\r
40 public class IOSInput implements Input {
\r
41 static final int MAX_TOUCHES = 20;
\r
44 IOSApplicationConfiguration config;
\r
45 int[] deltaX = new int[MAX_TOUCHES];
\r
46 int[] deltaY = new int[MAX_TOUCHES];
\r
47 int[] touchX = new int[MAX_TOUCHES];
\r
48 int[] touchY = new int[MAX_TOUCHES];
\r
49 // we store the pointer to the UITouch struct here, or 0
\r
50 int[] touchDown = new int[MAX_TOUCHES];
\r
52 boolean justTouched = false;
\r
53 Pool<TouchEvent> touchEventPool = new Pool<TouchEvent>() {
\r
55 protected TouchEvent newObject() {
\r
56 return new TouchEvent();
\r
59 Array<TouchEvent> touchEvents = new Array<TouchEvent>();
\r
60 TouchEvent currentEvent = null;
\r
61 float[] acceleration = new float[3];
\r
62 InputProcessor inputProcessor = null;
\r
64 public IOSInput(IOSApplication app) {
\r
66 this.config = app.config;
\r
69 void setupPeripherals() {
\r
70 setupAccelerometer();
\r
73 private void setupAccelerometer() {
\r
74 if(config.useAccelerometer) {
\r
75 UIAccelerometer.get_SharedAccelerometer().set_Delegate(new UIAccelerometerDelegate() {
\r
78 public void DidAccelerate(UIAccelerometer accelerometer, UIAcceleration values) {
\r
79 //super.DidAccelerate(accelerometer, values);
\r
80 // FIXME take orientation into account, these values here get flipped by iOS...
\r
81 acceleration[0] = (float)values.get_X() * 10;
\r
82 acceleration[1] = (float)values.get_Y() * 10;
\r
83 acceleration[2] = (float)values.get_Z() * 10;
\r
86 UIAccelerometer.get_SharedAccelerometer().set_UpdateInterval(config.accelerometerUpdate);
\r
91 public float getAccelerometerX() {
\r
92 return acceleration[0];
\r
96 public float getAccelerometerY() {
\r
97 return acceleration[1];
\r
101 public float getAccelerometerZ() {
\r
102 return acceleration[2];
\r
106 public float getAzimuth() {
\r
107 // FIXME implement this
\r
112 public float getPitch() {
\r
113 // FIXME implement this
\r
118 public float getRoll() {
\r
119 // FIXME implement this
\r
124 public void getRotationMatrix(float[] matrix) {
\r
125 // FIXME implement this
\r
129 public int getX() {
\r
134 public int getX(int pointer) {
\r
135 return touchX[pointer];
\r
139 public int getDeltaX() {
\r
144 public int getDeltaX(int pointer) {
\r
145 return deltaX[pointer];
\r
149 public int getY() {
\r
154 public int getY(int pointer) {
\r
155 return touchY[pointer];
\r
159 public int getDeltaY() {
\r
164 public int getDeltaY(int pointer) {
\r
165 return deltaY[pointer];
\r
169 public boolean isTouched() {
\r
170 return touchDown[0] != 0;
\r
174 public boolean justTouched() {
\r
175 return justTouched;
\r
179 public boolean isTouched(int pointer) {
\r
180 return touchDown[pointer] != 0;
\r
184 public boolean isButtonPressed(int button) {
\r
185 return button == Buttons.LEFT && numTouched > 0;
\r
189 public boolean isKeyPressed(int key) {
\r
194 public void getTextInput(TextInputListener listener, String title, String text) {
\r
195 final UIAlertView uiAlertView = buildUIAlertView(listener, title, text);
\r
196 app.uiViewController.Add(uiAlertView);
\r
197 uiAlertView.Show();
\r
200 /** Builds an {@link UIAlertView} with an added {@link UITextField} for inputting text.
\r
201 * @param listener Text input listener
\r
202 * @param title Dialog title
\r
203 * @param text Text for text field
\r
204 * @return UiAlertView */
\r
205 private UIAlertView buildUIAlertView (final TextInputListener listener, String title, String text) {
\r
206 UIAlertViewDelegate delegate = new UIAlertViewDelegate() {
\r
208 public void Clicked (UIAlertView view, int clicked) {
\r
209 if (clicked == 0) {
\r
210 // user clicked "Cancel" button
\r
211 listener.canceled();
\r
212 } else if (clicked == 1) {
\r
213 // user clicked "Ok" button
\r
214 UIView[] views = view.get_Subviews();
\r
215 for (UIView uiView : views) {
\r
216 // find text field from sub views
\r
217 if (uiView != null && uiView instanceof UITextField) {
\r
218 UITextField tf = (UITextField)uiView;
\r
219 listener.input(tf.get_Text());
\r
223 view.Dispose(); // is this necessary?
\r
227 public void Canceled (UIAlertView view) {
\r
228 listener.canceled();
\r
229 view.Dispose(); // is this necessary?
\r
234 final UIAlertView uiAlertView = new UIAlertView();
\r
235 uiAlertView.set_Title(title);
\r
236 uiAlertView.AddButton("Cancel");
\r
237 uiAlertView.AddButton("Ok");
\r
238 uiAlertView.set_AlertViewStyle(UIAlertViewStyle.wrap(UIAlertViewStyle.PlainTextInput));
\r
239 uiAlertView.set_Delegate(delegate);
\r
241 for (UIView uiView : uiAlertView.get_Subviews()) {
\r
242 // find text field from sub views and add default text
\r
243 if (uiView != null && uiView instanceof UITextField) {
\r
244 UITextField tf = (UITextField)uiView;
\r
249 return uiAlertView;
\r
253 public void getPlaceholderTextInput(TextInputListener listener, String title, String placeholder) {
\r
254 // FIXME implement this
\r
258 public void setOnscreenKeyboardVisible(boolean visible) {
\r
262 public void vibrate(int milliseconds) {
\r
263 // FIXME implement this
\r
267 public void vibrate(long[] pattern, int repeat) {
\r
268 // FIXME implement this
\r
272 public void cancelVibrate() {
\r
273 // FIXME implement this
\r
277 public long getCurrentEventTime() {
\r
278 return currentEvent.timestamp;
\r
282 public void setCatchBackKey(boolean catchBack) {
\r
286 public void setCatchMenuKey(boolean catchMenu) {
\r
290 public void setInputProcessor(InputProcessor processor) {
\r
291 this.inputProcessor = processor;
\r
295 public InputProcessor getInputProcessor() {
\r
296 return inputProcessor;
\r
300 public boolean isPeripheralAvailable(Peripheral peripheral) {
\r
301 if(peripheral == Peripheral.Accelerometer && config.useAccelerometer) return true;
\r
302 if(peripheral == Peripheral.MultitouchScreen) return true;
\r
303 // FIXME implement this (not sure if possible)
\r
304 // if(peripheral == Peripheral.OnscreenKeyboard) return true;
\r
305 // FIXME implement this
\r
306 // if(peripheral == Peripheral.Compass) return true;
\r
312 public int getRotation() {
\r
313 // FIXME implement this
\r
318 public Orientation getNativeOrientation() {
\r
319 // FIXME implement this
\r
324 public void setCursorCatched(boolean catched) {
\r
328 public boolean isCursorCatched() {
\r
333 public void setCursorPosition(int x, int y) {
\r
336 public void touchDown(NSSet touches, UIEvent event) {
\r
337 toTouchEvents(touches, event);
\r
340 public void touchUp(NSSet touches, UIEvent event) {
\r
341 toTouchEvents(touches, event);
\r
344 public void touchMoved(NSSet touches, UIEvent event) {
\r
345 toTouchEvents(touches, event);
\r
348 void processEvents() {
\r
349 synchronized(touchEvents) {
\r
350 justTouched = false;
\r
351 for(TouchEvent event: touchEvents) {
\r
352 currentEvent = event;
\r
353 switch(event.phase) {
\r
354 case UITouchPhase.Began:
\r
355 if(inputProcessor != null) inputProcessor.touchDown(event.x, event.y, event.pointer, Buttons.LEFT);
\r
356 if(numTouched == 1)
\r
357 justTouched = true;
\r
359 case UITouchPhase.Cancelled:
\r
360 case UITouchPhase.Ended:
\r
361 if(inputProcessor != null) inputProcessor.touchUp(event.x, event.y, event.pointer, Buttons.LEFT);
\r
363 case UITouchPhase.Moved:
\r
364 case UITouchPhase.Stationary:
\r
365 if(inputProcessor != null) inputProcessor.touchDragged(event.x, event.y, event.pointer);
\r
369 touchEventPool.freeAll(touchEvents);
\r
370 touchEvents.clear();
\r
374 NSSetEnumerator touchEnumerator = new NSSetEnumerator(new NSSetEnumerator.Method() {
\r
375 public void Invoke(NSObject obj, boolean[] stop) {
\r
376 UITouch touch = (UITouch) obj;
\r
377 PointF loc = touch.LocationInView(touch.get_View());
\r
378 synchronized(touchEvents) {
\r
379 TouchEvent event = touchEventPool.obtain();
\r
380 event.x = (int)(loc.get_X() * app.displayScaleFactor);
\r
381 event.y = (int)(loc.get_Y() * app.displayScaleFactor);
\r
382 event.phase = touch.get_Phase().Value;
\r
383 event.timestamp = (long)(touch.get_Timestamp() * 1000000000);
\r
384 touchEvents.add(event);
\r
386 if(touch.get_Phase().Value == UITouchPhase.Began) {
\r
387 event.pointer = getFreePointer();
\r
388 touchDown[event.pointer] = touch.get_Handle().ToInt32();
\r
389 touchX[event.pointer] = event.x;
\r
390 touchY[event.pointer] = event.y;
\r
391 deltaX[event.pointer] = 0;
\r
392 deltaY[event.pointer] = 0;
\r
396 if(touch.get_Phase().Value == UITouchPhase.Moved ||
\r
397 touch.get_Phase().Value == UITouchPhase.Stationary) {
\r
398 event.pointer = findPointer(touch);
\r
399 deltaX[event.pointer] = event.x - touchX[event.pointer];
\r
400 deltaY[event.pointer] = event.y - touchY[event.pointer];
\r
401 touchX[event.pointer] = event.x;
\r
402 touchY[event.pointer] = event.y;
\r
405 if(touch.get_Phase().Value == UITouchPhase.Cancelled ||
\r
406 touch.get_Phase().Value == UITouchPhase.Ended) {
\r
407 event.pointer = findPointer(touch);
\r
408 touchDown[event.pointer] = 0;
\r
409 touchX[event.pointer] = event.x;
\r
410 touchY[event.pointer] = event.y;
\r
411 deltaX[event.pointer] = 0;
\r
412 deltaY[event.pointer] = 0;
\r
420 int getFreePointer() {
\r
421 for(int i = 0; i < touchDown.length; i++) {
\r
422 if(touchDown[i] == 0) return i;
\r
424 throw new GdxRuntimeException("Couldn't find free pointer id!");
\r
427 int findPointer(UITouch touch) {
\r
428 int ptr = touch.get_Handle().ToInt32();
\r
429 for(int i = 0; i < touchDown.length; i++) {
\r
430 if(touchDown[i] == ptr) return i;
\r
432 throw new GdxRuntimeException("Couldn't find pointer id for touch event!");
\r
435 private void toTouchEvents(NSSet touches, UIEvent event) {
\r
436 touches.Enumerate(touchEnumerator);
\r
439 static class TouchEvent {
\r