Skip to content

Commit

Permalink
Merge pull request #3590 from Darkyenus/fix-ios-touch
Browse files Browse the repository at this point in the history
Fix iOS touch mapping
  • Loading branch information
badlogic committed Jan 5, 2016
2 parents 9f318fa + 0f78c4a commit cedcfbc
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 97 deletions.
Expand Up @@ -18,7 +18,7 @@

import java.io.File;

import org.robovm.apple.coregraphics.CGSize;
import org.robovm.apple.coregraphics.CGRect;
import org.robovm.apple.foundation.Foundation;
import org.robovm.apple.foundation.NSMutableDictionary;
import org.robovm.apple.foundation.NSObject;
Expand Down Expand Up @@ -102,6 +102,8 @@ public void willTerminate (UIApplication application) {
/** The display scale factor (1.0f for normal; 2.0f to use retina coordinates/dimensions). */
float displayScaleFactor;

private CGRect lastScreenBounds = null;

Array<Runnable> runnables = new Array<Runnable>();
Array<Runnable> executedRunnables = new Array<Runnable>();
Array<LifecycleListener> lifecycleListeners = new Array<LifecycleListener>();
Expand Down Expand Up @@ -152,7 +154,7 @@ final boolean didFinishLaunching (UIApplication uiApp, UIApplicationLaunchOption

// setup libgdx
this.input = new IOSInput(this);
this.graphics = new IOSGraphics(getBounds(null), scale, this, config, input, gl20);
this.graphics = new IOSGraphics(scale, this, config, input, gl20);
this.files = new IOSFiles();
this.audio = new IOSAudio(config);
this.net = new IOSNet(this);
Expand Down Expand Up @@ -190,57 +192,55 @@ public UIWindow getUIWindow () {
return uiWindow;
}

/** Returns our real display dimension based on screen orientation.
/** GL View spans whole screen, that is, even under the status bar. iOS can also rotate the screen, which is not handled
* consistently over iOS versions. This method returns, in pixels, rectangle in which libGDX draws.
*
* @param viewController The view controller.
* @return Or real display dimension. */
CGSize getBounds (UIViewController viewController) {
// or screen size (always portrait)
CGSize bounds = UIScreen.getMainScreen().getApplicationFrame().getSize();

// determine orientation and resulting width + height
UIInterfaceOrientation orientation;
if (viewController != null) {
orientation = viewController.getInterfaceOrientation();
} else if (config.orientationLandscape == config.orientationPortrait) {
/*
* if the app has orientation in any side then we can only check status bar orientation
*/
orientation = uiApp.getStatusBarOrientation();
} else if (config.orientationLandscape) {// is landscape true and portrait false
orientation = UIInterfaceOrientation.LandscapeRight;
} else {// is portrait true and landscape false
orientation = UIInterfaceOrientation.Portrait;
}
int width;
int height;
switch (orientation) {
* @return dimensions of space we draw to, adjusted for device orientation */
protected CGRect getBounds () {
final CGRect screenBounds = UIScreen.getMainScreen().getBounds();
final CGRect statusBarFrame = uiApp.getStatusBarFrame();
final UIInterfaceOrientation statusBarOrientation = uiApp.getStatusBarOrientation();

double statusBarHeight = Math.min(statusBarFrame.getWidth(), statusBarFrame.getHeight());

double screenWidth = screenBounds.getWidth();
double screenHeight = screenBounds.getHeight();

// Make sure that the orientation is consistent with ratios. Should be, but may not be on older iOS versions
switch (statusBarOrientation) {
case LandscapeLeft:
case LandscapeRight:
height = (int)bounds.getWidth();
width = (int)bounds.getHeight();
if (width < height) {
width = (int)bounds.getWidth();
height = (int)bounds.getHeight();
if (screenHeight > screenWidth) {
debug("IOSApplication", "Switching reported width and height (w=" + screenWidth + " h=" + screenHeight + ")");
double tmp = screenHeight;
// noinspection SuspiciousNameCombination
screenHeight = screenWidth;
screenWidth = tmp;
}
break;
default:
// assume portrait
width = (int)bounds.getWidth();
height = (int)bounds.getHeight();
}

Gdx.app.debug("IOSApplication", "Unscaled View: " + orientation.toString() + " " + width + "x" + height);

// update width/height depending on display scaling selected
width *= displayScaleFactor;
height *= displayScaleFactor;
screenWidth *= displayScaleFactor;
screenHeight *= displayScaleFactor;

// log screen dimensions
Gdx.app.debug("IOSApplication", "View: " + orientation.toString() + " " + width + "x" + height);
if (statusBarHeight != 0.0) {
debug("IOSApplication", "Status bar is visible (height = " + statusBarHeight + ")");
statusBarHeight *= displayScaleFactor;
screenHeight -= statusBarHeight;
} else {
debug("IOSApplication", "Status bar is not visible");
}

debug("IOSApplication", "Total computed bounds are w=" + screenWidth + " h=" + screenHeight);

return lastScreenBounds = new CGRect(0.0, statusBarHeight, screenWidth, screenHeight);
}

// return resulting view size (based on orientation)
return new CGSize(width, height);
protected CGRect getCachedBounds () {
if (lastScreenBounds == null)
return getBounds();
else
return lastScreenBounds;
}

final void didBecomeActive (UIApplication uiApp) {
Expand Down
Expand Up @@ -16,9 +16,7 @@

package com.badlogic.gdx.backends.iosrobovm;

import org.robovm.apple.coregraphics.CGPoint;
import org.robovm.apple.coregraphics.CGRect;
import org.robovm.apple.coregraphics.CGSize;
import org.robovm.apple.foundation.NSObject;
import org.robovm.apple.glkit.GLKView;
import org.robovm.apple.glkit.GLKViewController;
Expand Down Expand Up @@ -77,21 +75,6 @@ public void viewDidAppear (boolean animated) {
if (app.viewControllerListener != null) app.viewControllerListener.viewDidAppear(animated);
}

@Override
public void didRotate (UIInterfaceOrientation orientation) {
super.didRotate(orientation);
// get the view size and update graphics
// FIXME: supporting BOTH (landscape+portrait at same time) is
// currently not working correctly (needs fix)
// FIXME screen orientation needs to be stored for
// Input#getNativeOrientation
CGSize bounds = app.getBounds(this);
graphics.width = (int)bounds.getWidth();
graphics.height = (int)bounds.getHeight();
graphics.makeCurrent();
app.listener.resize(graphics.width, graphics.height);
}

@Override
public UIInterfaceOrientationMask getSupportedInterfaceOrientations () {
long mask = 0;
Expand Down Expand Up @@ -121,6 +104,17 @@ public boolean shouldAutorotateToInterfaceOrientation (UIInterfaceOrientation or
}
}

@Override
public void viewDidLayoutSubviews () {
super.viewDidLayoutSubviews();
// get the view size and update graphics
CGRect bounds = app.getBounds();
graphics.width = (int)bounds.getWidth();
graphics.height = (int)bounds.getHeight();
graphics.makeCurrent();
app.listener.resize(graphics.width, graphics.height);
}

@Callback
@BindSelector("shouldAutorotateToInterfaceOrientation:")
private static boolean shouldAutorotateToInterfaceOrientation (IOSUIViewController self, Selector sel,
Expand Down Expand Up @@ -165,36 +159,36 @@ public IOSUIView (CGRect frame, EAGLContext context) {
GLKView view;
IOSUIViewController viewController;

public IOSGraphics (CGSize bounds, float scale, IOSApplication app, IOSApplicationConfiguration config, IOSInput input,
GL20 gl20) {
public IOSGraphics (float scale, IOSApplication app, IOSApplicationConfiguration config, IOSInput input, GL20 gl20) {
this.config = config;

final CGRect bounds = app.getBounds();
// setup view and OpenGL
width = (int)bounds.getWidth();
height = (int)bounds.getHeight();
app.debug(tag, bounds.getWidth() + "x" + bounds.getHeight() + ", " + scale);
this.gl20 = gl20;

context = new EAGLContext(EAGLRenderingAPI.OpenGLES2);

view = new GLKView(new CGRect(new CGPoint(0, 0), bounds), context) {
view = new GLKView(new CGRect(0, 0, bounds.getWidth(), bounds.getHeight()), context) {
@Method(selector = "touchesBegan:withEvent:")
public void touchesBegan (@Pointer long touches, UIEvent event) {
IOSGraphics.this.input.touchDown(touches, event);
IOSGraphics.this.input.onTouch(touches);
}

@Method(selector = "touchesCancelled:withEvent:")
public void touchesCancelled (@Pointer long touches, UIEvent event) {
IOSGraphics.this.input.touchUp(touches, event);
IOSGraphics.this.input.onTouch(touches);
}

@Method(selector = "touchesEnded:withEvent:")
public void touchesEnded (@Pointer long touches, UIEvent event) {
IOSGraphics.this.input.touchUp(touches, event);
IOSGraphics.this.input.onTouch(touches);
}

@Method(selector = "touchesMoved:withEvent:")
public void touchesMoved (@Pointer long touches, UIEvent event) {
IOSGraphics.this.input.touchMoved(touches, event);
IOSGraphics.this.input.onTouch(touches);
}

@Override
Expand Down
Expand Up @@ -26,10 +26,7 @@
import org.robovm.apple.uikit.UIAlertViewDelegate;
import org.robovm.apple.uikit.UIAlertViewDelegateAdapter;
import org.robovm.apple.uikit.UIAlertViewStyle;
import org.robovm.apple.uikit.UIApplication;
import org.robovm.apple.uikit.UIDevice;
import org.robovm.apple.uikit.UIEvent;
import org.robovm.apple.uikit.UIInterfaceOrientation;
import org.robovm.apple.uikit.UIKeyboardType;
import org.robovm.apple.uikit.UIReturnKeyType;
import org.robovm.apple.uikit.UITextAutocapitalizationType;
Expand All @@ -53,7 +50,6 @@
import com.badlogic.gdx.backends.iosrobovm.custom.UIAccelerometer;
import com.badlogic.gdx.backends.iosrobovm.custom.UIAccelerometerDelegate;
import com.badlogic.gdx.backends.iosrobovm.custom.UIAccelerometerDelegateAdapter;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.Pool;
Expand Down Expand Up @@ -563,19 +559,29 @@ public boolean isPeripheralAvailable (Peripheral peripheral) {

@Override
public int getRotation () {
UIInterfaceOrientation orientation = app.graphics.viewController != null ? app.graphics.viewController
.getInterfaceOrientation() : UIApplication.getSharedApplication().getStatusBarOrientation();
// we measure orientation counter clockwise, just like on Android
if (orientation == UIInterfaceOrientation.Portrait) return 0;
if (orientation == UIInterfaceOrientation.LandscapeLeft) return 270;
if (orientation == UIInterfaceOrientation.PortraitUpsideDown) return 180;
if (orientation == UIInterfaceOrientation.LandscapeRight) return 90;
return 0;
switch (app.uiApp.getStatusBarOrientation()) {
case LandscapeLeft:
return 270;
case PortraitUpsideDown:
return 180;
case LandscapeRight:
return 90;
case Portrait:
default:
return 0;
}
}

@Override
public Orientation getNativeOrientation () {
return Orientation.Portrait;
switch (app.uiApp.getStatusBarOrientation()) {
case LandscapeLeft:
case LandscapeRight:
return Orientation.Landscape;
default:
return Orientation.Portrait;
}
}

@Override
Expand All @@ -591,18 +597,8 @@ public boolean isCursorCatched () {
public void setCursorPosition (int x, int y) {
}

public void touchDown (long touches, UIEvent event) {
toTouchEvents(touches, event);
Gdx.graphics.requestRendering();
}

public void touchUp (long touches, UIEvent event) {
toTouchEvents(touches, event);
Gdx.graphics.requestRendering();
}

public void touchMoved (long touches, UIEvent event) {
toTouchEvents(touches, event);
protected void onTouch (long touches) {
toTouchEvents(touches);
Gdx.graphics.requestRendering();
}

Expand Down Expand Up @@ -659,18 +655,27 @@ private static class NSArrayExtensions extends NSExtensions {
public static native @MachineSizedUInt long count (@Pointer long thiz);
}

private void toTouchEvents (long touches, UIEvent uiEvent) {
private void toTouchEvents (long touches) {
long array = NSSetExtensions.allObjects(touches);
int length = (int)NSArrayExtensions.count(array);
for (int i = 0; i < length; i++) {
long touchHandle = NSArrayExtensions.objectAtIndex$(array, i);
UITouch touch = UI_TOUCH_WRAPPER.wrap(touchHandle);
CGPoint loc = touch.getLocationInView(touch.getView());
final int locX, locY;
// Get and map the location to our drawing space
{
CGPoint loc = touch.getLocationInView(touch.getWindow());
final CGRect bounds = app.getCachedBounds();
locX = (int)(loc.getX() * app.displayScaleFactor - bounds.getMinX());
locY = (int)(loc.getY() * app.displayScaleFactor - bounds.getMinY());
// app.debug("IOSInput","pos= "+loc+" bounds= "+bounds+" x= "+locX+" locY= "+locY);
}

synchronized (touchEvents) {
UITouchPhase phase = touch.getPhase();
TouchEvent event = touchEventPool.obtain();
event.x = (int)(loc.getX() * app.displayScaleFactor);
event.y = (int)(loc.getY() * app.displayScaleFactor);
event.x = locX;
event.y = locY;
event.phase = phase;
event.timestamp = (long)(touch.getTimestamp() * 1000000000);
touchEvents.add(event);
Expand Down

0 comments on commit cedcfbc

Please sign in to comment.