package com.badlogic.gdx.automation.recorder; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.Input.Orientation; import com.badlogic.gdx.Input.Peripheral; import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.automation.recorder.InputProperty.AsyncProperty.PlaceholderText; import com.badlogic.gdx.automation.recorder.InputProperty.AsyncProperty.Text; import com.badlogic.gdx.automation.recorder.InputProperty.SyncProperty.Accelerometer; import com.badlogic.gdx.automation.recorder.InputProperty.SyncProperty.Button; import com.badlogic.gdx.automation.recorder.InputProperty.SyncProperty.KeyEvent; import com.badlogic.gdx.automation.recorder.InputProperty.SyncProperty.KeyPressed; import com.badlogic.gdx.automation.recorder.InputProperty.SyncProperty.Pointer; import com.badlogic.gdx.automation.recorder.InputProperty.SyncProperty.PointerEvent; /** * Parent class of all (groups of) properties that make up an {@link InputState} * . Since all properties are merely aggregations of primitives (you would call * them "structs" in C) they are not declared in their own files but as inner * classes of this class. * * @author Lukas Böhm */ public abstract class InputProperty { private InputProperty() { } /** * Base class of all input values that are directly passed to the program. * This includes input events that are usually received using * {@link InputProcessor}, since the processing of them also happens in the * main thread. * * @author Lukas Böhm * */ public static abstract class SyncProperty { /** * Enum helping to create the selection flags used by some methods like * {@link InputState#set(InputState, int)}. By providing a * {@link Type#key key} that needs to be OR'ed together only the * corresponding {@link SyncProperty}s will be considered in such a * process. * * @author Lukas Böhm * */ public enum Type { POINTERS(1), BUTTONS(2), POINTER_EVENTS(4), KEY_EVENTS(8), KEYS_PRESSED( 16), ORIENTATION(32); /** * binary flag unique for each {@link Type} to be able to specify * any combination of Types without having to specify an array and * without the overhead to search in it. Just "&" the key to an int. */ int key; private Type(int key) { this.key = key; } } /** * Method to accept {@link SyncPropertyVisitor}s, so that concrete child * classes of {@link SyncProperty} can execute child-specific code of * the concrete visitor implementation. This is great to omit * <code>instancof</code> or <code>getClass()</code> by having the jvm * doing the dispatching * * @param visitor */ public abstract void accept(SyncPropertyVisitor visitor); /** * Milliseconds passed since the last {@link InputProperty} changed */ public long timeDelta; /** * A struct to store the three axis values of the accelerometer in. * * @author Lukas Böhm * */ public static class Accelerometer extends SyncProperty { public float accelerometerX; public float accelerometerY; public float accelerometerZ; @Override public void accept(SyncPropertyVisitor visitor) { visitor.visitAccelerometer(this); } } /** * A struct storing all information there is regarding a device's * orientation. This includes the three gyroscope values as well as the * screen orientation and the orientation matrix. * * @author Lukas Böhm * */ public static class Orientation extends SyncProperty { public float roll; public float pitch; public float azimuth; public int orientation; public float[] rotationMatrix = new float[16]; @Override public void accept(SyncPropertyVisitor visitor) { visitor.visitOrientation(this); } } /** * A class indicating that a key was either pressed or has stopped being * pressed. * * @author Lukas Böhm * */ public static class KeyPressed extends SyncProperty { /** * Describes whether a key press has begun or finished. * * @author Lukas Böhm * */ public enum Type { PRESS, RELEASE } public Type type; public int keyCode; @Override public void accept(SyncPropertyVisitor visitor) { visitor.visitKeyPressed(this); } } /** * Similar to {@link KeyPressed}, but closer to the high-level key * events of the platforms libGdx targets. * * @author Lukas Böhm * */ public static class KeyEvent extends SyncProperty { /** * Description of the exact KeyEvent type, as libGdx' target * platform events use them. * * @author Lukas Böhm * */ public enum Type { KEY_DOWN, KEY_UP, KEY_TYPED; static Type mapAndroid(int i) { switch (i) { case 0: return KEY_DOWN; case 1: return KEY_UP; case 2: return KEY_TYPED; default: throw new IllegalArgumentException(i + " out of sensible KeyState range"); } } static Type mapDesktop(int i) { // luckily they have the same implementation return mapAndroid(i); } } public Type type; public int keyCode; public char keyChar; public KeyEvent() { } KeyEvent( com.badlogic.gdx.automation.recorder.EventBufferAccessHelper.KeyEvent event) { type = event.type; keyCode = event.keyCode; keyChar = event.keyChar; } @Override public void accept(SyncPropertyVisitor visitor) { visitor.visitKeyEvent(this); } } /** * Event whose implementation closely resembles the platform specific * mouse events of libGdx' target platforms. * * @author Lukas Böhm * */ public static class PointerEvent extends SyncProperty { /** * Superset of all types of pointer events (called "touch" in * libGdx) that the different target platforms involve. * * @author Lukas Böhm * */ public enum Type { TOUCH_DOWN, TOUCH_UP, TOUCH_DRAGGED, TOUCH_SCROLLED, TOUCH_MOVED; static Type mapAndroid(int i) { switch (i) { case 0: return TOUCH_DOWN; case 1: return TOUCH_UP; case 2: return TOUCH_DRAGGED; default: throw new IllegalArgumentException(i + " out of Android's sensible TouchState range"); } } static Type mapDesktop(int i) { switch (i) { case 0: return TOUCH_DOWN; case 1: return TOUCH_UP; case 2: return TOUCH_DRAGGED; case 3: return TOUCH_SCROLLED; case 4: return TOUCH_MOVED; default: throw new IllegalArgumentException(i + " out of Desktop's sensible TouchState range"); } } } public Type type; public float x; public float y; public int scrollAmount; public int button; public int pointer; public PointerEvent() { } PointerEvent( com.badlogic.gdx.automation.recorder.EventBufferAccessHelper.PointerEvent event) { type = event.type; x = event.x; y = event.y; scrollAmount = event.scrollAmount; button = event.button; pointer = event.pointer; } @Override public void accept(SyncPropertyVisitor visitor) { visitor.visitPointerEvent(this); } } /** * A class to aggregate all position information that is emitted by the * use of a single touch pointer or mouse, not considering buttons or * touch states. * * @author Lukas Böhm * */ public static class Pointer extends SyncProperty { public int pointer; public float x; public float y; public float deltaX; public float deltaY; @Override public void accept(SyncPropertyVisitor visitor) { visitor.visitPointer(this); } } /** * Class to store the state of the three possible buttons of a mouse. * * @author Lukas Böhm * */ public static class Button extends SyncProperty { public boolean button0; public boolean button1; public boolean button2; @Override public void accept(SyncPropertyVisitor visitor) { visitor.visitButton(this); } } } /** * An interface to enable the visitor pattern on {@link SyncProperty}s. This * means, it helps to have the JVM do the dispatching of the concrete * underlying {@link SyncProperty} type of an instance. Using this interface * also adds compiler support for adding new types, since extending the * interface automatically breaks concrete implementations that are not * adapted for the newly added types. * */ public static interface SyncPropertyVisitor { void visitAccelerometer(Accelerometer accelerometer); void visitKeyPressed(KeyPressed keyPressed); void visitPointerEvent(PointerEvent pointerEvent); void visitKeyEvent(KeyEvent keyEvent); void visitOrientation( com.badlogic.gdx.automation.recorder.InputProperty.SyncProperty.Orientation orientation); void visitPointer(Pointer pointer); void visitButton(Button button); } /** * Abstract class parenting all classes of input, which can not be read * directly from {@link Input Gdx.input} but instead are supplied to the * program using specified callbacks. * * @author Lukas Böhm * */ public static abstract class AsyncProperty { /** * Method to accept {@link AsyncPropertyVisitor}s, so that concrete * child classes of {@link AsyncProperty} can execute child-specific * code of the concrete visitor implementation. This is great to omit * <code>instancof</code> or <code>getClass()</code> by having the jvm * doing the dispatching * * @param visitor */ public abstract void accept(AsyncPropertyVisitor visitor); /** * Description of the outcome of a * {@link Input#getTextInput(com.badlogic.gdx.Input.TextInputListener, String, String) * getText} request. If the outcome is null it means that the request * was canceled. * * @author Lukas Böhm * */ public static class Text extends AsyncProperty { public Text(String text) { input = text; } public Text() { } public String input; @Override public void accept(AsyncPropertyVisitor visitor) { visitor.visitText(this); } } /** * Description of the outcome of a * {@link Input#getPlaceholderTextInput(com.badlogic.gdx.Input.TextInputListener, String, String) * getPlaceholderText} request. If the outcome is null it means that the * request was canceled. * * @author Lukas Böhm * */ public static class PlaceholderText extends AsyncProperty { public PlaceholderText(String text) { input = text; } public PlaceholderText() { } public String input; @Override public void accept(AsyncPropertyVisitor visitor) { visitor.visitPlaceholderText(this); } } } /** * An interface to enable the visitor pattern on {@link AsyncProperty}s. * This means, it helps to have the JVM do the dispatching of the concrete * underlying {@link AsyncProperty} type of an instance. Using this * interface also adds compiler support for adding new types, since * extending the interface automatically breaks concrete implementations * that are not adapted for the newly added types. * */ public static interface AsyncPropertyVisitor { void visitText(Text text); void visitPlaceholderText(PlaceholderText text); } /** * A struct to aggregate all properties that a libGdx environment can * exhibit. * * @author Lukas Böhm * */ public static class StaticProperties extends InputProperty { public boolean accelerometerAvailable; public boolean compassAvailable; public boolean keyboardAvailable; public boolean onscreenKeyboard; public boolean vibrator; public boolean hasMultitouch; public Orientation nativeOrientation; public void set(StaticProperties other) { accelerometerAvailable = other.accelerometerAvailable; compassAvailable = other.compassAvailable; keyboardAvailable = other.keyboardAvailable; onscreenKeyboard = other.onscreenKeyboard; vibrator = other.vibrator; hasMultitouch = other.hasMultitouch; nativeOrientation = other.nativeOrientation; } } /** * Copies the {@link StaticProperties} from the current {@link Gdx libGdx} * environment. * * @return the {@link StaticProperties} of the current environment */ public static StaticProperties getCurrentStaticValues() { StaticProperties result = new StaticProperties(); result.accelerometerAvailable = Gdx.input .isPeripheralAvailable(Peripheral.Accelerometer); result.compassAvailable = Gdx.input .isPeripheralAvailable(Peripheral.Compass); result.keyboardAvailable = Gdx.input .isPeripheralAvailable(Peripheral.HardwareKeyboard); result.onscreenKeyboard = Gdx.input .isPeripheralAvailable(Peripheral.OnscreenKeyboard); result.vibrator = Gdx.input.isPeripheralAvailable(Peripheral.Vibrator); result.hasMultitouch = Gdx.input .isPeripheralAvailable(Peripheral.MultitouchScreen); result.nativeOrientation = Gdx.input.getNativeOrientation(); return result; } }