v3.0.0: added proper support for touches cancelled by system gestures

This commit is contained in:
Evan Debenham
2025-01-22 16:49:55 -05:00
parent 38d2731fde
commit 0a602a9fb1
5 changed files with 30 additions and 31 deletions
@@ -133,11 +133,13 @@ public class InputHandler extends InputAdapter {
@Override @Override
public boolean touchCancelled(int screenX, int screenY, int pointer, int button) { public boolean touchCancelled(int screenX, int screenY, int pointer, int button) {
//currently emulating functionality from libGDX 1.11.0, do we keep this?
//in particular this is probably a more graceful way to handle things like system swipes on iOS if (button >= 3 && KeyBindings.isKeyBound( button + 1000 )) {
//whereas previously they generated garbage inputs sometimes KeyEvent.addKeyEvent( new KeyEvent( button + 1000, false ) );
//which were then fixed in v2.2.2 } else if (button < 3) {
return touchUp(screenX, screenY, pointer, button); PointerEvent.addPointerEvent(new PointerEvent(screenX, screenY, pointer, PointerEvent.Type.CANCEL, button));
}
return true;
} }
@Override @Override
@@ -35,6 +35,7 @@ public class PointerEvent {
public enum Type { public enum Type {
DOWN, DOWN,
UP, UP,
CANCEL,
HOVER HOVER
} }
@@ -82,6 +83,11 @@ public class PointerEvent {
return this; return this;
} }
public PointerEvent cancel() {
if (type == Type.DOWN) type = Type.CANCEL;
return this;
}
public PointerEvent handle(){ public PointerEvent handle(){
handled = true; handled = true;
return this; return this;
@@ -162,9 +168,12 @@ public class PointerEvent {
pointerSignal.dispatch( null ); pointerSignal.dispatch( null );
} else if (p.type == Type.DOWN) { } else if (p.type == Type.DOWN) {
pointerSignal.dispatch( existing ); pointerSignal.dispatch( existing );
} else { } else if (p.type == Type.UP){
activePointers.remove(existing.id); activePointers.remove(existing.id);
pointerSignal.dispatch(existing.up()); pointerSignal.dispatch(existing.up());
} else if (p.type == Type.CANCEL){
activePointers.remove(existing.id);
pointerSignal.dispatch(existing.cancel());
} }
} else { } else {
if (p.type == Type.DOWN) { if (p.type == Type.DOWN) {
@@ -185,12 +194,4 @@ public class PointerEvent {
} }
} }
public static synchronized void clearPointerEvents(){
pointerEvents.clear();
for (PointerEvent p : activePointers.values()){
p.current = p.start = new PointF(-1, -1);
pointerSignal.dispatch(p.up());
}
activePointers.clear();
}
} }
@@ -33,7 +33,6 @@ import com.watabou.glwrap.Blending;
import com.watabou.glwrap.Vertexbuffer; import com.watabou.glwrap.Vertexbuffer;
import com.watabou.input.ControllerHandler; import com.watabou.input.ControllerHandler;
import com.watabou.input.InputHandler; import com.watabou.input.InputHandler;
import com.watabou.input.PointerEvent;
import com.watabou.noosa.audio.Music; import com.watabou.noosa.audio.Music;
import com.watabou.noosa.audio.Sample; import com.watabou.noosa.audio.Sample;
import com.watabou.utils.Callback; import com.watabou.utils.Callback;
@@ -146,10 +145,7 @@ public class Game implements ApplicationListener {
} }
} }
///justResumed is used for two purposes: //justResumed is a bit of a hack to improve start time metrics on Android,
//firstly, to clear pointer events when the game is resumed,
// this helps with input errors caused by system gestures on iOS/Android
//secondly, as a bit of a hack to improve start time metrics on Android,
// as texture refreshing leads to slow warm starts. TODO would be nice to fix this properly // as texture refreshing leads to slow warm starts. TODO would be nice to fix this properly
private boolean justResumed = true; private boolean justResumed = true;
@@ -162,7 +158,6 @@ public class Game implements ApplicationListener {
} }
if (justResumed){ if (justResumed){
PointerEvent.clearPointerEvents();
justResumed = false; justResumed = false;
if (DeviceCompat.isAndroid()) return; if (DeviceCompat.isAndroid()) return;
} }
@@ -180,8 +175,6 @@ public class Game implements ApplicationListener {
@Override @Override
public void pause() { public void pause() {
PointerEvent.clearPointerEvents();
if (scene != null) { if (scene != null) {
scene.onPause(); scene.onPause();
} }
@@ -82,6 +82,15 @@ public class PointerArea extends Visual implements Signal.Listener<PointerEvent>
onClick( event ); onClick( event );
} }
//similar to up, but no click
} else if (event.type == PointerEvent.Type.CANCEL) {
onPointerUp( event );
if (curEvent == event) {
curEvent = null;
}
} else if (event.type == PointerEvent.Type.HOVER) { } else if (event.type == PointerEvent.Type.HOVER) {
if (event.handled && hovered){ if (event.handled && hovered){
hovered = false; hovered = false;
@@ -100,7 +109,8 @@ public class PointerArea extends Visual implements Signal.Listener<PointerEvent>
if (event == null && curEvent != null) { if (event == null && curEvent != null) {
onDrag(curEvent); onDrag(curEvent);
} else if (curEvent != null && event.type == PointerEvent.Type.UP) { } else if (curEvent != null &&
(event.type == PointerEvent.Type.UP || event.type == PointerEvent.Type.CANCEL)) {
onPointerUp( event ); onPointerUp( event );
curEvent = null; curEvent = null;
@@ -45,7 +45,6 @@ import org.robovm.apple.foundation.NSString;
import org.robovm.apple.glkit.GLKViewDrawableColorFormat; import org.robovm.apple.glkit.GLKViewDrawableColorFormat;
import org.robovm.apple.glkit.GLKViewDrawableDepthFormat; import org.robovm.apple.glkit.GLKViewDrawableDepthFormat;
import org.robovm.apple.uikit.UIApplication; import org.robovm.apple.uikit.UIApplication;
import org.robovm.apple.uikit.UIRectEdge;
import java.io.File; import java.io.File;
@@ -102,12 +101,6 @@ public class IOSLauncher extends IOSApplication.Delegate {
config.hideHomeIndicator = SPDSettings.fullscreen(); config.hideHomeIndicator = SPDSettings.fullscreen();
config.overrideRingerSwitch = SPDSettings.ignoreSilentMode(); config.overrideRingerSwitch = SPDSettings.ignoreSilentMode();
//game has to ignore input from system gestures itself, otherwise there is lag on
//every button press on the corner of the screen. Currently this is accomplished via
//clearing all pointer events on the first frame after the game is resumed.
//TODO this may not be needed anymore with libgdx 1.12.1
config.screenEdgesDeferringSystemGestures = UIRectEdge.All;
CGRect statusBarFrame = UIApplication.getSharedApplication().getStatusBarFrame(); CGRect statusBarFrame = UIApplication.getSharedApplication().getStatusBarFrame();
double statusBarHeight = Math.min(statusBarFrame.getWidth(), statusBarFrame.getHeight()); double statusBarHeight = Math.min(statusBarFrame.getWidth(), statusBarFrame.getHeight());