diff --git a/jme3-core/src/main/java/com/jme3/input/ActionInvoker.java b/jme3-core/src/main/java/com/jme3/input/ActionInvoker.java new file mode 100644 index 0000000000..f6d88e627c --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/ActionInvoker.java @@ -0,0 +1,207 @@ +package com.jme3.input; + +import java.util.List; + +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.InputListener; +import com.jme3.input.controls.TouchListener; +import com.jme3.input.controls.TouchTrigger; +import com.jme3.input.event.TouchEvent; +import com.jme3.input.util.IReadInputSettings; +import com.jme3.input.util.IReadTimer; +import com.jme3.math.FastMath; +import com.jme3.util.IntMap; +import com.jme3.util.IntMap.Entry; + +public class ActionInvoker { + + private IReadInputSettings settings; + private IReadBindings bindings; + private IReadTimer timer; + private final IntMap pressedButtons = new IntMap(); + private IntMap axisValues = new IntMap(); + + public ActionInvoker(IReadInputSettings settings, IReadBindings bindings, IReadTimer timer) + { + this.settings = settings; + this.bindings = bindings; + this.timer = timer; + } + + public void invokeActions(int hash, boolean pressed) { + List maps = bindings.getMappings(hash); + if (maps == null) { + return; + } + + int size = maps.size(); + for (int i = size - 1; i >= 0; i--) { + Mapping mapping = maps.get(i); + List listeners = mapping.listeners; + int listenerSize = listeners.size(); + for (int j = listenerSize - 1; j >= 0; j--) { + InputListener listener = listeners.get(j); + if (listener instanceof ActionListener) { + ((ActionListener) listener).onAction(mapping.name, pressed, settings.getFrameTPF()); + } + } + } + } + + private float computeAnalogValue(long timeDelta) { + if (settings.safeModeEnabled() || timer.getFrameDelta() == 0) { + return 1f; + } else { + return FastMath.clamp((float) timeDelta / (float) timer.getFrameDelta(), 0, 1); + } + } + + public void invokeTimedActions(int hash, long time, boolean pressed) { + if (!bindings.contains(hash)) { + return; + } + + if (pressed) { + pressedButtons.put(hash, time); + } else { + Long pressTimeObj = pressedButtons.remove(hash); + if (pressTimeObj == null) { + return; // under certain circumstances it can be null, ignore + } // the event then. + + long pressTime = pressTimeObj; + long releaseTime = time; + long timeDelta = releaseTime - Math.max(pressTime, timer.getLastUpdateTime()); + + if (timeDelta > 0) { + invokeAnalogs(hash, computeAnalogValue(timeDelta), false); + } + } + } + + public void invokeUpdateActions() { + for (Entry pressedButton : pressedButtons) { + int hash = pressedButton.getKey(); + long pressTime = pressedButton.getValue(); + + long timeDelta = timer.getLastUpdateTime() - Math.max(timer.getLastLastUpdateTime(), pressTime); + + if (timeDelta > 0) { + invokeAnalogs(hash, computeAnalogValue(timeDelta), false); + } + } + + for (Entry axisValue : axisValues) { + int hash = axisValue.getKey(); + float value = axisValue.getValue(); + invokeAnalogs(hash, value * settings.getFrameTPF(), true); + } + } + + public void invokeTouchActions(TouchEvent evt) + { + List maps = bindings.getMappings(TouchTrigger.touchHash(evt.getKeyCode())); + if (maps == null) { + return; + } + + int size = maps.size(); + for (int i = size - 1; i >= 0; i--) { + Mapping mapping = maps.get(i); + List listeners = mapping.listeners; + int listenerSize = listeners.size(); + for (int j = listenerSize - 1; j >= 0; j--) { + InputListener listener = listeners.get(j); + if (listener instanceof TouchListener) { + ((TouchListener) listener).onTouch(mapping.name, evt, settings.getFrameTPF()); + } + } + } + } + + public void invokeAnalogs(int hash, float value, boolean isAxis) { + List maps = bindings.getMappings(hash); + if (maps == null) { + return; + } + + if (!isAxis) { + value *= settings.getFrameTPF(); + } + + int size = maps.size(); + for (int i = size - 1; i >= 0; i--) { + Mapping mapping = maps.get(i); + List listeners = mapping.listeners; + int listenerSize = listeners.size(); + for (int j = listenerSize - 1; j >= 0; j--) { + InputListener listener = listeners.get(j); + if (listener instanceof AnalogListener) { + // NOTE: multiply by TPF for any button bindings + ((AnalogListener) listener).onAnalog(mapping.name, value, settings.getFrameTPF()); + } + } + } + } + + public void invokeAnalogsAndActions(int hash, float value, + float effectiveDeadZone, boolean applyTpf) { + + if (value < effectiveDeadZone) { + invokeAnalogs(hash, value, !applyTpf); + return; + } + + List maps = bindings.getMappings(hash); + if (maps == null) { + return; + } + + boolean valueChanged = !axisValues.containsKey(hash); + + if (applyTpf) { + value *= settings.getFrameTPF(); + } + + int size = maps.size(); + for (int i = size - 1; i >= 0; i--) { + Mapping mapping = maps.get(i); + List listeners = mapping.listeners; + int listenerSize = listeners.size(); + for (int j = listenerSize - 1; j >= 0; j--) { + InputListener listener = listeners.get(j); + + if (listener instanceof ActionListener && valueChanged) { + ((ActionListener) listener).onAction(mapping.name, true, settings.getFrameTPF()); + } + + if (listener instanceof AnalogListener) { + ((AnalogListener) listener).onAnalog(mapping.name, value, settings.getFrameTPF()); + } + + } + } + } + + public void invokeAnalogsAndActions(int hash, float value, + float effectiveDeadZone, boolean applyTpf, IntMap newerAxisValues) { + + axisValues = newerAxisValues; + invokeAnalogsAndActions(hash, value, effectiveDeadZone, applyTpf); + } + + public IReadInputSettings getSettings() { + return settings; + } + + /** + * Do not use. + * Called to reset pressed keys or buttons when focus is restored. + */ + public void reset() { + pressedButtons.clear(); + axisValues.clear(); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/input/BaseListenerHandler.java b/jme3-core/src/main/java/com/jme3/input/BaseListenerHandler.java new file mode 100644 index 0000000000..766e5edd67 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/BaseListenerHandler.java @@ -0,0 +1,107 @@ +package com.jme3.input; + +import java.util.List; + +import com.jme3.input.event.*; +import com.jme3.util.SafeArrayList; +import com.jme3.input.inputListener.BaseInputListener; + +public class BaseListenerHandler implements IBaseListenerRegistration, IBaseListenerEmitter { + + + private final SafeArrayList baseInputListeners = new SafeArrayList(BaseInputListener.class); + + //contains rawinputlistener for not breaking code + private final SafeArrayList rawInputListeners = new SafeArrayList(RawInputListener.class); + + /* (non-Javadoc) + * @see com.jme3.input.IBaseListenerHandler#addRawInputListener(com.jme3.input.inputListener.BaseInputListener) + */ + @Override + public void addRawInputListener(RawInputListener listener) { + rawInputListeners.add(listener); + } + + /* (non-Javadoc) + * @see com.jme3.input.IBaseListenerHandler#removeRawInputListener(com.jme3.input.RawInputListener) + */ + @Override + public void removeRawInputListener(RawInputListener listener) { + rawInputListeners.remove(listener); + } + + public void addRawInputListener(BaseInputListener listener) { + baseInputListeners.add(listener); + } + + public void removeRawInputListener(BaseInputListener listener) { + baseInputListeners.remove(listener); + } + + /* (non-Javadoc) + * @see com.jme3.input.IBaseListenerHandler#clearRawInputListeners() + */ + @Override + public void clearRawInputListeners() { + rawInputListeners.clear(); + baseInputListeners.clear(); + } + + + /* (non-Javadoc) + * @see com.jme3.input.IBaseListenerEmitter#emit(java.util.List) + */ + @Override + public void emit(List inputQueue) + { + int queueSize = inputQueue.size(); + + for (BaseInputListener listener : baseInputListeners) { + listener.beginInput(); + + for (int j = 0; j < queueSize; j++) { + InputEvent event = inputQueue.get(j); + if (event.isConsumed()) { + continue; + } + + listener.onEvent(event); + } + + listener.endInput(); + } + + RawInputListener[] array = rawInputListeners.getArray(); + + for (RawInputListener listener : array) { + listener.beginInput(); + + for (int j = 0; j < queueSize; j++) { + InputEvent event = inputQueue.get(j); + if (event.isConsumed()) { + continue; + } + + if (event instanceof MouseMotionEvent) { + listener.onMouseMotionEvent((MouseMotionEvent) event); + } else if (event instanceof KeyInputEvent) { + listener.onKeyEvent((KeyInputEvent) event); + } else if (event instanceof MouseButtonEvent) { + listener.onMouseButtonEvent((MouseButtonEvent) event); + } else if (event instanceof JoyAxisEvent) { + listener.onJoyAxisEvent((JoyAxisEvent) event); + } else if (event instanceof JoyButtonEvent) { + listener.onJoyButtonEvent((JoyButtonEvent) event); + } else if (event instanceof TouchEvent) { + listener.onTouchEvent((TouchEvent) event); + } else { + assert false; + } + } + + listener.endInput(); + } + + + } +} diff --git a/jme3-core/src/main/java/com/jme3/input/CursorManager.java b/jme3-core/src/main/java/com/jme3/input/CursorManager.java new file mode 100644 index 0000000000..b9c7d444ee --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/CursorManager.java @@ -0,0 +1,132 @@ +package com.jme3.input; + +import com.jme3.cursors.plugins.JmeCursor; +import com.jme3.math.Vector2f; + +public class CursorManager implements ICursorPos{ + + private final Vector2f cursorPos = new Vector2f(); + private boolean mouseVisible = true; + private final MouseInput mouse; + private final TouchInput touch; + + + public CursorManager(MouseInput mouse, TouchInput touch) + { + this.mouse = mouse; + this.touch = touch; + } + + /** + * Sets the mouse cursor image or animation. + * Set cursor to null to show default system cursor. + * To hide the cursor completely, use {@link #setCursorVisible(boolean) }. + * + * @param jmeCursor The cursor to set, or null to reset to system cursor. + * + * @see JmeCursor + */ + public void setMouseCursor(JmeCursor jmeCursor) { + mouse.setNativeCursor(jmeCursor); + } + + /** + * Returns whether the mouse cursor is visible or not. + * + *

By default the cursor is visible. + * + * @return whether the mouse cursor is visible or not. + * + * @see InputManager#setCursorVisible(boolean) + */ + public boolean isCursorVisible() { + return mouseVisible; + } + + + /** + * Set whether the mouse cursor should be visible or not. + * + * @param visible whether the mouse cursor should be visible or not. + */ + public void setCursorVisible(boolean visible) { + if (mouseVisible != visible) { + mouseVisible = visible; + mouse.setCursorVisible(mouseVisible); + } + } + + /** + * Returns the current cursor position. The position is relative to the + * bottom-left of the screen and is in pixels. + * + * @return the current cursor position + */ + public Vector2f getCursorPosition() { + return cursorPos; + } + + + /** + * Enable simulation of mouse events. Used for touchscreen input only. + * + * @param value True to enable simulation of mouse events + */ + public void setSimulateMouse(boolean value) { + if (touch != null) { + touch.setSimulateMouse(value); + } + } + /** + * @deprecated Use isSimulateMouse + * Returns state of simulation of mouse events. Used for touchscreen input only. + * + */ + public boolean getSimulateMouse() { + if (touch != null) { + return touch.isSimulateMouse(); + } else { + return false; + } + } + + /** + * Returns state of simulation of mouse events. Used for touchscreen input only. + * + */ + public boolean isSimulateMouse() { + if (touch != null) { + return touch.isSimulateMouse(); + } else { + return false; + } + } + + /** + * Enable simulation of keyboard events. Used for touchscreen input only. + * + * @param value True to enable simulation of keyboard events + */ + public void setSimulateKeyboard(boolean value) { + if (touch != null) { + touch.setSimulateKeyboard(value); + } + } + + /** + * Returns state of simulation of key events. Used for touchscreen input only. + * + */ + public boolean isSimulateKeyboard() { + if (touch != null) { + return touch.isSimulateKeyboard(); + } else { + return false; + } + } + + @Override + public void setCursorPosition(float x, float y) { + cursorPos.set(x,y); + } +} diff --git a/jme3-core/src/main/java/com/jme3/input/IBaseListenerEmitter.java b/jme3-core/src/main/java/com/jme3/input/IBaseListenerEmitter.java new file mode 100644 index 0000000000..b2e30e41f3 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/IBaseListenerEmitter.java @@ -0,0 +1,11 @@ +package com.jme3.input; + +import java.util.List; + +import com.jme3.input.event.InputEvent; + +public interface IBaseListenerEmitter { + + void emit(List inputQueue); + +} \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/input/IBaseListenerRegistration.java b/jme3-core/src/main/java/com/jme3/input/IBaseListenerRegistration.java new file mode 100644 index 0000000000..ba44f90472 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/IBaseListenerRegistration.java @@ -0,0 +1,45 @@ +package com.jme3.input; + +import com.jme3.input.event.InputEvent; +import com.jme3.input.inputListener.BaseInputListener; + +public interface IBaseListenerRegistration { + + /** + * Adds a {@link RawInputListener} to receive raw input events. + * + *

+ * Any raw input listeners registered to this BaseListenerResgistration + * will receive raw input events first, before they get handled + * by the EventProcessors itself. The listeners are + * each processed in the order they were added, e.g. FIFO. + *

+ * If a raw input listener has handled the event and does not wish + * other listeners down the list to process the event, it may set the + * {@link InputEvent#setConsumed() consumed flag} to indicate the + * event was consumed and shouldn't be processed any further. + * The listener may do this either at each of the event callbacks + * or at the {@link RawInputListener#endInput() } method. + * + * @param listener A listener to receive raw input events. + * + * @see RawInputListener + */ + void addRawInputListener(RawInputListener listener); + + /** + * Removes a {@link RawInputListener} so that it no longer + * receives raw input events. + * + * @param listener The listener to cease receiving raw input events. + + */ + void removeRawInputListener(RawInputListener listener); + + /** + * Clears all {@link RawInputListener}s. + * + */ + void clearRawInputListeners(); + +} \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/input/ICursorPos.java b/jme3-core/src/main/java/com/jme3/input/ICursorPos.java new file mode 100644 index 0000000000..59ed548478 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/ICursorPos.java @@ -0,0 +1,6 @@ +package com.jme3.input; + +public interface ICursorPos { + + public void setCursorPosition(float x, float y); +} diff --git a/jme3-core/src/main/java/com/jme3/input/IJoyStickSettings.java b/jme3-core/src/main/java/com/jme3/input/IJoyStickSettings.java new file mode 100644 index 0000000000..6562f79212 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/IJoyStickSettings.java @@ -0,0 +1,30 @@ +package com.jme3.input; + +public interface IJoyStickSettings { + + /** + * Set the deadzone for joystick axes. + * + *

{@link ActionListener#onAction(java.lang.String, boolean, float) } + * events will only be raised if the joystick axis value is greater than + * the deadZone. + * + * @param deadZone the deadzone for joystick axes. + */ + public void setAxisDeadZone(float deadZone); + + /** + * Returns the deadzone for joystick axes. + * + * @return the deadzone for joystick axes. + */ + public float getAxisDeadZone(); + + /** + * Returns an array of all joysticks installed on the system. + * + * @return an array of all joysticks installed on the system. + */ + public Joystick[] getJoysticks(); + +} diff --git a/jme3-core/src/main/java/com/jme3/input/IListenerManager.java b/jme3-core/src/main/java/com/jme3/input/IListenerManager.java new file mode 100644 index 0000000000..24cab262e9 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/IListenerManager.java @@ -0,0 +1,41 @@ +package com.jme3.input; + +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.AnalogListener; +import com.jme3.input.controls.InputListener; + +public interface IListenerManager { + + /** + * Adds a new listener to receive events on the given mappings. + * + *

The given InputListener will be registered to receive events + * on the specified mapping names. When a mapping raises an event, the + * listener will have its appropriate method invoked, either + * {@link ActionListener#onAction(java.lang.String, boolean, float) } + * or {@link AnalogListener#onAnalog(java.lang.String, float, float) } + * depending on which interface the listener implements. + * If the listener implements both interfaces, then it will receive the + * appropriate event for each method. + * + * @param listener The listener to register to receive input events. + * @param mappingNames The mapping names which the listener will receive + * events from. + * + * @see InputManager#removeListener(com.jme3.input.controls.InputListener) + */ + void addListener(InputListener listener, String... mappingNames); + + /** + * Removes a listener from receiving events. + * + *

This will unregister the listener from any mappings that it + * was previously registered. + * + * @param listener The listener to unregister. + * + * @see InputManager#addListener(com.jme3.input.controls.InputListener, java.lang.String[]) + */ + void removeListener(InputListener listener); + +} \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/input/IMapper.java b/jme3-core/src/main/java/com/jme3/input/IMapper.java new file mode 100644 index 0000000000..b15c54d075 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/IMapper.java @@ -0,0 +1,62 @@ +package com.jme3.input; + +import com.jme3.input.controls.Trigger; + +public interface IMapper { + + /** + * Create a new mapping to the given triggers. + * + *

+ * The given mapping will be assigned to the given triggers, when + * any of the triggers given raise an event, the listeners + * registered to the mappings will receive appropriate events. + * + * @param mappingName The mapping name to assign. + * @param triggers The triggers to which the mapping is to be registered. + * + */ + void addMapping(String mappingName, Trigger... triggers); + + /** + * Deletes a mapping from receiving trigger events. + * + *

+ * The given mapping will no longer be assigned to receive trigger + * events. + * + * @param mappingName The mapping name to unregister. + * + */ + void deleteMapping(String mappingName); + + /** + * Returns true if this InputManager has a mapping registered + * for the given mappingName. + * + * @param mappingName The mapping name to check. + * + */ + boolean hasMapping(String mappingName); + + /** + * Deletes a specific trigger registered to a mapping. + * + *

+ * The given mapping will no longer receive events raised by the + * trigger. + * + * @param mappingName The mapping name to cease receiving events from the + * trigger. + * @param trigger The trigger to no longer invoke events on the mapping. + */ + void deleteTrigger(String mappingName, Trigger trigger); + + /** + * Clears all the input mappings from this InputManager. + * Consequently, also clears all of the + * InputListeners as well. + */ + void clearMappings(); + +} \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/input/IReadBindings.java b/jme3-core/src/main/java/com/jme3/input/IReadBindings.java new file mode 100644 index 0000000000..9cd6f9dd12 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/IReadBindings.java @@ -0,0 +1,13 @@ +package com.jme3.input; + +import java.util.List; + +import com.jme3.input.Mapping; + +public interface IReadBindings { + + public List getMappings(int hash); + + public boolean contains(int hash); + +} \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/input/InputManager.java b/jme3-core/src/main/java/com/jme3/input/InputManager.java index b21d225bbc..c1ba8755f3 100644 --- a/jme3-core/src/main/java/com/jme3/input/InputManager.java +++ b/jme3-core/src/main/java/com/jme3/input/InputManager.java @@ -1,949 +1,432 @@ -/* - * Copyright (c) 2009-2012 jMonkeyEngine - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of 'jMonkeyEngine' nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package com.jme3.input; - -import com.jme3.app.Application; -import com.jme3.cursors.plugins.JmeCursor; -import com.jme3.input.controls.*; -import com.jme3.input.event.*; -import com.jme3.math.FastMath; -import com.jme3.math.Vector2f; -import com.jme3.util.IntMap; -import com.jme3.util.IntMap.Entry; -import com.jme3.util.SafeArrayList; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * The InputManager is responsible for converting input events - * received from the Key, Mouse and Joy Input implementations into an - * abstract, input device independent representation that user code can use. - *

- * By default an InputManager is included with every Application instance for use - * in user code to query input, unless the Application is created as headless - * or with input explicitly disabled. - *

- * The input manager has two concepts, a {@link Trigger} and a mapping. - * A trigger represents a specific input trigger, such as a key button, - * or a mouse axis. A mapping represents a link onto one or several triggers, - * when the appropriate trigger is activated (e.g. a key is pressed), the - * mapping will be invoked. Any listeners registered to receive an event - * from the mapping will have an event raised. - *

- * There are two types of events that {@link InputListener input listeners} - * can receive, one is {@link ActionListener#onAction(java.lang.String, boolean, float) action} - * events and another is {@link AnalogListener#onAnalog(java.lang.String, float, float) analog} - * events. - *

- * onAction events are raised when the specific input - * activates or deactivates. For a digital input such as key press, the onAction() - * event will be raised with the isPressed argument equal to true, - * when the key is released, onAction is called again but this time - * with the isPressed argument set to false. - * For analog inputs, the onAction method will be called any time - * the input is non-zero, however an exception to this is for joystick axis inputs, - * which are only called when the input is above the {@link InputManager#setAxisDeadZone(float) dead zone}. - *

- * onAnalog events are raised every frame while the input is activated. - * For digital inputs, every frame that the input is active will cause the - * onAnalog method to be called, the argument value - * argument will equal to the frame's time per frame (TPF) value but only - * for digital inputs. For analog inputs however, the value argument - * will equal the actual analog value. - */ -public class InputManager implements RawInputListener { - - private static final Logger logger = Logger.getLogger(InputManager.class.getName()); - private final KeyInput keys; - private final MouseInput mouse; - private final JoyInput joystick; - private final TouchInput touch; - private float frameTPF; - private long lastLastUpdateTime = 0; - private long lastUpdateTime = 0; - private long frameDelta = 0; - private long firstTime = 0; - private boolean eventsPermitted = false; - private boolean mouseVisible = true; - private boolean safeMode = false; - private float globalAxisDeadZone = 0.05f; - private final Vector2f cursorPos = new Vector2f(); - private Joystick[] joysticks; - private final IntMap> bindings = new IntMap>(); - private final HashMap mappings = new HashMap(); - private final IntMap pressedButtons = new IntMap(); - private final IntMap axisValues = new IntMap(); - private final SafeArrayList rawListeners = new SafeArrayList(RawInputListener.class); - private final ArrayList inputQueue = new ArrayList(); - - private static class Mapping { - - private final String name; - private final ArrayList triggers = new ArrayList(); - private final ArrayList listeners = new ArrayList(); - - public Mapping(String name) { - this.name = name; - } - } - - /** - * Initializes the InputManager. - * - *

This should only be called internally in {@link Application}. - * - * @param mouse - * @param keys - * @param joystick - * @param touch - * @throws IllegalArgumentException If either mouseInput or keyInput are null. - */ - public InputManager(MouseInput mouse, KeyInput keys, JoyInput joystick, TouchInput touch) { - if (keys == null || mouse == null) { - throw new IllegalArgumentException("Mouse or keyboard cannot be null"); - } - - this.keys = keys; - this.mouse = mouse; - this.joystick = joystick; - this.touch = touch; - - keys.setInputListener(this); - mouse.setInputListener(this); - if (joystick != null) { - joystick.setInputListener(this); - joysticks = joystick.loadJoysticks(this); - } - if (touch != null) { - touch.setInputListener(this); - } - - firstTime = keys.getInputTimeNanos(); - } - - private void invokeActions(int hash, boolean pressed) { - ArrayList maps = bindings.get(hash); - if (maps == null) { - return; - } - - int size = maps.size(); - for (int i = size - 1; i >= 0; i--) { - Mapping mapping = maps.get(i); - ArrayList listeners = mapping.listeners; - int listenerSize = listeners.size(); - for (int j = listenerSize - 1; j >= 0; j--) { - InputListener listener = listeners.get(j); - if (listener instanceof ActionListener) { - ((ActionListener) listener).onAction(mapping.name, pressed, frameTPF); - } - } - } - } - - private float computeAnalogValue(long timeDelta) { - if (safeMode || frameDelta == 0) { - return 1f; - } else { - return FastMath.clamp((float) timeDelta / (float) frameDelta, 0, 1); - } - } - - private void invokeTimedActions(int hash, long time, boolean pressed) { - if (!bindings.containsKey(hash)) { - return; - } - - if (pressed) { - pressedButtons.put(hash, time); - } else { - Long pressTimeObj = pressedButtons.remove(hash); - if (pressTimeObj == null) { - return; // under certain circumstances it can be null, ignore - } // the event then. - - long pressTime = pressTimeObj; - long lastUpdate = lastLastUpdateTime; - long releaseTime = time; - long timeDelta = releaseTime - Math.max(pressTime, lastUpdate); - - if (timeDelta > 0) { - invokeAnalogs(hash, computeAnalogValue(timeDelta), false); - } - } - } - - private void invokeUpdateActions() { - for (Entry pressedButton : pressedButtons) { - int hash = pressedButton.getKey(); - - long pressTime = pressedButton.getValue(); - long timeDelta = lastUpdateTime - Math.max(lastLastUpdateTime, pressTime); - - if (timeDelta > 0) { - invokeAnalogs(hash, computeAnalogValue(timeDelta), false); - } - } - - for (Entry axisValue : axisValues) { - int hash = axisValue.getKey(); - float value = axisValue.getValue(); - invokeAnalogs(hash, value * frameTPF, true); - } - } - - private void invokeAnalogs(int hash, float value, boolean isAxis) { - ArrayList maps = bindings.get(hash); - if (maps == null) { - return; - } - - if (!isAxis) { - value *= frameTPF; - } - - int size = maps.size(); - for (int i = size - 1; i >= 0; i--) { - Mapping mapping = maps.get(i); - ArrayList listeners = mapping.listeners; - int listenerSize = listeners.size(); - for (int j = listenerSize - 1; j >= 0; j--) { - InputListener listener = listeners.get(j); - if (listener instanceof AnalogListener) { - // NOTE: multiply by TPF for any button bindings - ((AnalogListener) listener).onAnalog(mapping.name, value, frameTPF); - } - } - } - } - - private void invokeAnalogsAndActions(int hash, float value, float effectiveDeadZone, boolean applyTpf) { - if (value < effectiveDeadZone) { - invokeAnalogs(hash, value, !applyTpf); - return; - } - - ArrayList maps = bindings.get(hash); - if (maps == null) { - return; - } - - boolean valueChanged = !axisValues.containsKey(hash); - if (applyTpf) { - value *= frameTPF; - } - - int size = maps.size(); - for (int i = size - 1; i >= 0; i--) { - Mapping mapping = maps.get(i); - ArrayList listeners = mapping.listeners; - int listenerSize = listeners.size(); - for (int j = listenerSize - 1; j >= 0; j--) { - InputListener listener = listeners.get(j); - - if (listener instanceof ActionListener && valueChanged) { - ((ActionListener) listener).onAction(mapping.name, true, frameTPF); - } - - if (listener instanceof AnalogListener) { - ((AnalogListener) listener).onAnalog(mapping.name, value, frameTPF); - } - - } - } - } - - /** - * Callback from RawInputListener. Do not use. - */ - @Override - public void beginInput() { - } - - /** - * Callback from RawInputListener. Do not use. - */ - @Override - public void endInput() { - } - - private void onJoyAxisEventQueued(JoyAxisEvent evt) { -// for (int i = 0; i < rawListeners.size(); i++){ -// rawListeners.get(i).onJoyAxisEvent(evt); -// } - - int joyId = evt.getJoyIndex(); - int axis = evt.getAxisIndex(); - float value = evt.getValue(); - float effectiveDeadZone = Math.max(globalAxisDeadZone, evt.getAxis().getDeadZone()); - if (value < effectiveDeadZone && value > -effectiveDeadZone) { - int hash1 = JoyAxisTrigger.joyAxisHash(joyId, axis, true); - int hash2 = JoyAxisTrigger.joyAxisHash(joyId, axis, false); - - Float val1 = axisValues.get(hash1); - Float val2 = axisValues.get(hash2); - - if (val1 != null && val1 > effectiveDeadZone) { - invokeActions(hash1, false); - } - if (val2 != null && val2 > effectiveDeadZone) { - invokeActions(hash2, false); - } - - axisValues.remove(hash1); - axisValues.remove(hash2); - - } else if (value < 0) { - int hash = JoyAxisTrigger.joyAxisHash(joyId, axis, true); - int otherHash = JoyAxisTrigger.joyAxisHash(joyId, axis, false); - - // Clear the reverse direction's actions in case we - // crossed center too quickly - Float otherVal = axisValues.get(otherHash); - if (otherVal != null && otherVal > effectiveDeadZone) { - invokeActions(otherHash, false); - } - - invokeAnalogsAndActions(hash, -value, effectiveDeadZone, true); - axisValues.put(hash, -value); - axisValues.remove(otherHash); - } else { - int hash = JoyAxisTrigger.joyAxisHash(joyId, axis, false); - int otherHash = JoyAxisTrigger.joyAxisHash(joyId, axis, true); - - // Clear the reverse direction's actions in case we - // crossed center too quickly - Float otherVal = axisValues.get(otherHash); - if (otherVal != null && otherVal > effectiveDeadZone) { - invokeActions(otherHash, false); - } - - invokeAnalogsAndActions(hash, value, effectiveDeadZone, true); - axisValues.put(hash, value); - axisValues.remove(otherHash); - } - } - - /** - * Callback from RawInputListener. Do not use. - */ - @Override - public void onJoyAxisEvent(JoyAxisEvent evt) { - if (!eventsPermitted) { - throw new UnsupportedOperationException("JoyInput has raised an event at an illegal time."); - } - - inputQueue.add(evt); - } - - private void onJoyButtonEventQueued(JoyButtonEvent evt) { -// for (int i = 0; i < rawListeners.size(); i++){ -// rawListeners.get(i).onJoyButtonEvent(evt); -// } - - int hash = JoyButtonTrigger.joyButtonHash(evt.getJoyIndex(), evt.getButtonIndex()); - invokeActions(hash, evt.isPressed()); - invokeTimedActions(hash, evt.getTime(), evt.isPressed()); - } - - /** - * Callback from RawInputListener. Do not use. - */ - @Override - public void onJoyButtonEvent(JoyButtonEvent evt) { - if (!eventsPermitted) { - throw new UnsupportedOperationException("JoyInput has raised an event at an illegal time."); - } - - inputQueue.add(evt); - } - - private void onMouseMotionEventQueued(MouseMotionEvent evt) { -// for (int i = 0; i < rawListeners.size(); i++){ -// rawListeners.get(i).onMouseMotionEvent(evt); -// } - - if (evt.getDX() != 0) { - float val = Math.abs(evt.getDX()) / 1024f; - invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_X, evt.getDX() < 0), val, globalAxisDeadZone, false); - } - if (evt.getDY() != 0) { - float val = Math.abs(evt.getDY()) / 1024f; - invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_Y, evt.getDY() < 0), val, globalAxisDeadZone, false); - } - if (evt.getDeltaWheel() != 0) { - float val = Math.abs(evt.getDeltaWheel()) / 100f; - invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_WHEEL, evt.getDeltaWheel() < 0), val, globalAxisDeadZone, false); - } - } - - /** - * Sets the mouse cursor image or animation. - * Set cursor to null to show default system cursor. - * To hide the cursor completely, use {@link #setCursorVisible(boolean) }. - * - * @param jmeCursor The cursor to set, or null to reset to system cursor. - * - * @see JmeCursor - */ - public void setMouseCursor(JmeCursor jmeCursor) { - mouse.setNativeCursor(jmeCursor); - } - - /** - * Callback from RawInputListener. Do not use. - */ - @Override - public void onMouseMotionEvent(MouseMotionEvent evt) { - if (!eventsPermitted) { - throw new UnsupportedOperationException("MouseInput has raised an event at an illegal time."); - } - - cursorPos.set(evt.getX(), evt.getY()); - inputQueue.add(evt); - } - - private void onMouseButtonEventQueued(MouseButtonEvent evt) { - int hash = MouseButtonTrigger.mouseButtonHash(evt.getButtonIndex()); - invokeActions(hash, evt.isPressed()); - invokeTimedActions(hash, evt.getTime(), evt.isPressed()); - } - - /** - * Callback from RawInputListener. Do not use. - */ - @Override - public void onMouseButtonEvent(MouseButtonEvent evt) { - if (!eventsPermitted) { - throw new UnsupportedOperationException("MouseInput has raised an event at an illegal time."); - } - //updating cursor pos on click, so that non android touch events can properly update cursor position. - cursorPos.set(evt.getX(), evt.getY()); - inputQueue.add(evt); - } - - private void onKeyEventQueued(KeyInputEvent evt) { - if (evt.isRepeating()) { - return; // repeat events not used for bindings - } - - int hash = KeyTrigger.keyHash(evt.getKeyCode()); - invokeActions(hash, evt.isPressed()); - invokeTimedActions(hash, evt.getTime(), evt.isPressed()); - } - - /** - * Callback from RawInputListener. Do not use. - */ - @Override - public void onKeyEvent(KeyInputEvent evt) { - if (!eventsPermitted) { - throw new UnsupportedOperationException("KeyInput has raised an event at an illegal time."); - } - - inputQueue.add(evt); - } - - /** - * Set the deadzone for joystick axes. - * - *

{@link ActionListener#onAction(java.lang.String, boolean, float) } - * events will only be raised if the joystick axis value is greater than - * the deadZone. - * - * @param deadZone the deadzone for joystick axes. - */ - public void setAxisDeadZone(float deadZone) { - this.globalAxisDeadZone = deadZone; - } - - /** - * Returns the deadzone for joystick axes. - * - * @return the deadzone for joystick axes. - */ - public float getAxisDeadZone() { - return globalAxisDeadZone; - } - - /** - * Adds a new listener to receive events on the given mappings. - * - *

The given InputListener will be registered to receive events - * on the specified mapping names. When a mapping raises an event, the - * listener will have its appropriate method invoked, either - * {@link ActionListener#onAction(java.lang.String, boolean, float) } - * or {@link AnalogListener#onAnalog(java.lang.String, float, float) } - * depending on which interface the listener implements. - * If the listener implements both interfaces, then it will receive the - * appropriate event for each method. - * - * @param listener The listener to register to receive input events. - * @param mappingNames The mapping names which the listener will receive - * events from. - * - * @see InputManager#removeListener(com.jme3.input.controls.InputListener) - */ - public void addListener(InputListener listener, String... mappingNames) { - for (String mappingName : mappingNames) { - Mapping mapping = mappings.get(mappingName); - if (mapping == null) { - mapping = new Mapping(mappingName); - mappings.put(mappingName, mapping); - } - if (!mapping.listeners.contains(listener)) { - mapping.listeners.add(listener); - } - } - } - - /** - * Removes a listener from receiving events. - * - *

This will unregister the listener from any mappings that it - * was previously registered with via - * {@link InputManager#addListener(com.jme3.input.controls.InputListener, java.lang.String[]) }. - * - * @param listener The listener to unregister. - * - * @see InputManager#addListener(com.jme3.input.controls.InputListener, java.lang.String[]) - */ - public void removeListener(InputListener listener) { - for (Mapping mapping : mappings.values()) { - mapping.listeners.remove(listener); - } - } - - /** - * Create a new mapping to the given triggers. - * - *

- * The given mapping will be assigned to the given triggers, when - * any of the triggers given raise an event, the listeners - * registered to the mappings will receive appropriate events. - * - * @param mappingName The mapping name to assign. - * @param triggers The triggers to which the mapping is to be registered. - * - * @see InputManager#deleteMapping(java.lang.String) - */ - public void addMapping(String mappingName, Trigger... triggers) { - Mapping mapping = mappings.get(mappingName); - if (mapping == null) { - mapping = new Mapping(mappingName); - mappings.put(mappingName, mapping); - } - - for (Trigger trigger : triggers) { - int hash = trigger.triggerHashCode(); - ArrayList names = bindings.get(hash); - if (names == null) { - names = new ArrayList(); - bindings.put(hash, names); - } - if (!names.contains(mapping)) { - names.add(mapping); - mapping.triggers.add(hash); - } else { - logger.log(Level.WARNING, "Attempted to add mapping \"{0}\" twice to trigger.", mappingName); - } - } - } - - /** - * Returns true if this InputManager has a mapping registered - * for the given mappingName. - * - * @param mappingName The mapping name to check. - * - * @see InputManager#addMapping(java.lang.String, com.jme3.input.controls.Trigger[]) - * @see InputManager#deleteMapping(java.lang.String) - */ - public boolean hasMapping(String mappingName) { - return mappings.containsKey(mappingName); - } - - /** - * Deletes a mapping from receiving trigger events. - * - *

- * The given mapping will no longer be assigned to receive trigger - * events. - * - * @param mappingName The mapping name to unregister. - * - * @see InputManager#addMapping(java.lang.String, com.jme3.input.controls.Trigger[]) - */ - public void deleteMapping(String mappingName) { - Mapping mapping = mappings.remove(mappingName); - if (mapping == null) { - //throw new IllegalArgumentException("Cannot find mapping: " + mappingName); - logger.log(Level.WARNING, "Cannot find mapping to be removed, skipping: {0}", mappingName); - return; - } - - ArrayList triggers = mapping.triggers; - for (int i = triggers.size() - 1; i >= 0; i--) { - int hash = triggers.get(i); - ArrayList maps = bindings.get(hash); - maps.remove(mapping); - } - } - - /** - * Deletes a specific trigger registered to a mapping. - * - *

- * The given mapping will no longer receive events raised by the - * trigger. - * - * @param mappingName The mapping name to cease receiving events from the - * trigger. - * @param trigger The trigger to no longer invoke events on the mapping. - */ - public void deleteTrigger(String mappingName, Trigger trigger) { - Mapping mapping = mappings.get(mappingName); - if (mapping == null) { - throw new IllegalArgumentException("Cannot find mapping: " + mappingName); - } - - ArrayList maps = bindings.get(trigger.triggerHashCode()); - maps.remove(mapping); - - } - - /** - * Clears all the input mappings from this InputManager. - * Consequently, also clears all of the - * InputListeners as well. - */ - public void clearMappings() { - mappings.clear(); - bindings.clear(); - reset(); - } - - /** - * Do not use. - * Called to reset pressed keys or buttons when focus is restored. - */ - public void reset() { - pressedButtons.clear(); - axisValues.clear(); - } - - /** - * Returns whether the mouse cursor is visible or not. - * - *

By default the cursor is visible. - * - * @return whether the mouse cursor is visible or not. - * - * @see InputManager#setCursorVisible(boolean) - */ - public boolean isCursorVisible() { - return mouseVisible; - } - - /** - * Set whether the mouse cursor should be visible or not. - * - * @param visible whether the mouse cursor should be visible or not. - */ - public void setCursorVisible(boolean visible) { - if (mouseVisible != visible) { - mouseVisible = visible; - mouse.setCursorVisible(mouseVisible); - } - } - - /** - * Returns the current cursor position. The position is relative to the - * bottom-left of the screen and is in pixels. - * - * @return the current cursor position - */ - public Vector2f getCursorPosition() { - return cursorPos; - } - - /** - * Returns an array of all joysticks installed on the system. - * - * @return an array of all joysticks installed on the system. - */ - public Joystick[] getJoysticks() { - return joysticks; - } - - /** - * Adds a {@link RawInputListener} to receive raw input events. - * - *

- * Any raw input listeners registered to this InputManager - * will receive raw input events first, before they get handled - * by the InputManager itself. The listeners are - * each processed in the order they were added, e.g. FIFO. - *

- * If a raw input listener has handled the event and does not wish - * other listeners down the list to process the event, it may set the - * {@link InputEvent#setConsumed() consumed flag} to indicate the - * event was consumed and shouldn't be processed any further. - * The listener may do this either at each of the event callbacks - * or at the {@link RawInputListener#endInput() } method. - * - * @param listener A listener to receive raw input events. - * - * @see RawInputListener - */ - public void addRawInputListener(RawInputListener listener) { - rawListeners.add(listener); - } - - /** - * Removes a {@link RawInputListener} so that it no longer - * receives raw input events. - * - * @param listener The listener to cease receiving raw input events. - * - * @see InputManager#addRawInputListener(com.jme3.input.RawInputListener) - */ - public void removeRawInputListener(RawInputListener listener) { - rawListeners.remove(listener); - } - - /** - * Clears all {@link RawInputListener}s. - * - * @see InputManager#addRawInputListener(com.jme3.input.RawInputListener) - */ - public void clearRawInputListeners() { - rawListeners.clear(); - } - - /** - * Enable simulation of mouse events. Used for touchscreen input only. - * - * @param value True to enable simulation of mouse events - */ - public void setSimulateMouse(boolean value) { - if (touch != null) { - touch.setSimulateMouse(value); - } - } - /** - * @deprecated Use isSimulateMouse - * Returns state of simulation of mouse events. Used for touchscreen input only. - * - */ - public boolean getSimulateMouse() { - if (touch != null) { - return touch.isSimulateMouse(); - } else { - return false; - } - } - - /** - * Returns state of simulation of mouse events. Used for touchscreen input only. - * - */ - public boolean isSimulateMouse() { - if (touch != null) { - return touch.isSimulateMouse(); - } else { - return false; - } - } - - /** - * Enable simulation of keyboard events. Used for touchscreen input only. - * - * @param value True to enable simulation of keyboard events - */ - public void setSimulateKeyboard(boolean value) { - if (touch != null) { - touch.setSimulateKeyboard(value); - } - } - - /** - * Returns state of simulation of key events. Used for touchscreen input only. - * - */ - public boolean isSimulateKeyboard() { - if (touch != null) { - return touch.isSimulateKeyboard(); - } else { - return false; - } - } - - private void processQueue() { - int queueSize = inputQueue.size(); - RawInputListener[] array = rawListeners.getArray(); - - for (RawInputListener listener : array) { - listener.beginInput(); - - for (int j = 0; j < queueSize; j++) { - InputEvent event = inputQueue.get(j); - if (event.isConsumed()) { - continue; - } - - if (event instanceof MouseMotionEvent) { - listener.onMouseMotionEvent((MouseMotionEvent) event); - } else if (event instanceof KeyInputEvent) { - listener.onKeyEvent((KeyInputEvent) event); - } else if (event instanceof MouseButtonEvent) { - listener.onMouseButtonEvent((MouseButtonEvent) event); - } else if (event instanceof JoyAxisEvent) { - listener.onJoyAxisEvent((JoyAxisEvent) event); - } else if (event instanceof JoyButtonEvent) { - listener.onJoyButtonEvent((JoyButtonEvent) event); - } else if (event instanceof TouchEvent) { - listener.onTouchEvent((TouchEvent) event); - } else { - assert false; - } - } - - listener.endInput(); - } - - for (int i = 0; i < queueSize; i++) { - InputEvent event = inputQueue.get(i); - if (event.isConsumed()) { - continue; - } - - if (event instanceof MouseMotionEvent) { - onMouseMotionEventQueued((MouseMotionEvent) event); - } else if (event instanceof KeyInputEvent) { - onKeyEventQueued((KeyInputEvent) event); - } else if (event instanceof MouseButtonEvent) { - onMouseButtonEventQueued((MouseButtonEvent) event); - } else if (event instanceof JoyAxisEvent) { - onJoyAxisEventQueued((JoyAxisEvent) event); - } else if (event instanceof JoyButtonEvent) { - onJoyButtonEventQueued((JoyButtonEvent) event); - } else if (event instanceof TouchEvent) { - onTouchEventQueued((TouchEvent) event); - } else { - assert false; - } - // larynx, 2011.06.10 - flag event as reusable because - // the android input uses a non-allocating ringbuffer which - // needs to know when the event is not anymore in inputQueue - // and therefor can be reused. - event.setConsumed(); - } - - inputQueue.clear(); - } - - /** - * Updates the InputManager. - * This will query current input devices and send - * appropriate events to registered listeners. - * - * @param tpf Time per frame value. - */ - public void update(float tpf) { - frameTPF = tpf; - - // Activate safemode if the TPF value is so small - // that rounding errors are inevitable - safeMode = tpf < 0.015f; - - long currentTime = keys.getInputTimeNanos(); - frameDelta = currentTime - lastUpdateTime; - - eventsPermitted = true; - - keys.update(); - mouse.update(); - if (joystick != null) { - joystick.update(); - } - if (touch != null) { - touch.update(); - } - - eventsPermitted = false; - - processQueue(); - invokeUpdateActions(); - - lastLastUpdateTime = lastUpdateTime; - lastUpdateTime = currentTime; - } - - /** - * Dispatches touch events to touch listeners - * @param evt The touch event to be dispatched to all onTouch listeners - */ - public void onTouchEventQueued(TouchEvent evt) { - ArrayList maps = bindings.get(TouchTrigger.touchHash(evt.getKeyCode())); - if (maps == null) { - return; - } - - int size = maps.size(); - for (int i = size - 1; i >= 0; i--) { - Mapping mapping = maps.get(i); - ArrayList listeners = mapping.listeners; - int listenerSize = listeners.size(); - for (int j = listenerSize - 1; j >= 0; j--) { - InputListener listener = listeners.get(j); - if (listener instanceof TouchListener) { - ((TouchListener) listener).onTouch(mapping.name, evt, frameTPF); - } - } - } - } - - /** - * Callback from RawInputListener. Do not use. - */ - @Override - public void onTouchEvent(TouchEvent evt) { - if (!eventsPermitted) { - throw new UnsupportedOperationException("TouchInput has raised an event at an illegal time."); - } - cursorPos.set(evt.getX(), evt.getY()); - inputQueue.add(evt); - } -} +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.input; + +import com.jme3.app.Application; +import com.jme3.cursors.plugins.JmeCursor; +import com.jme3.input.controls.*; +import com.jme3.input.event.*; +import com.jme3.input.eventprocessing.EventProcessorHandler; +import com.jme3.input.eventprocessing.JoyEventProcessor; +import com.jme3.input.eventprocessing.KeyEventProcessor; +import com.jme3.input.eventprocessing.MouseEventProcessor; +import com.jme3.input.eventprocessing.TouchEventProcessor; +import com.jme3.input.inputListener.*; +import com.jme3.input.queue.EventQueue; +import com.jme3.input.util.InputSettings; +import com.jme3.input.util.InputTimer; +import com.jme3.math.Vector2f; +import java.util.ArrayList; +import java.util.List; + +/** + * The InputManager is responsible for converting input events + * received from the Key, Mouse and Joy Input implementations into an + * abstract, input device independent representation that user code can use. + *

+ * By default an InputManager is included with every Application instance for use + * in user code to query input, unless the Application is created as headless + * or with input explicitly disabled. + *

+ * The input manager has two concepts, a {@link Trigger} and a mapping. + * A trigger represents a specific input trigger, such as a key button, + * or a mouse axis. A mapping represents a link onto one or several triggers, + * when the appropriate trigger is activated (e.g. a key is pressed), the + * mapping will be invoked. Any listeners registered to receive an event + * from the mapping will have an event raised. + *

+ * There are two types of events that {@link InputListener input listeners} + * can receive, one is {@link ActionListener#onAction(java.lang.String, boolean, float) action} + * events and another is {@link AnalogListener#onAnalog(java.lang.String, float, float) analog} + * events. + *

+ * onAction events are raised when the specific input + * activates or deactivates. For a digital input such as key press, the onAction() + * event will be raised with the isPressed argument equal to true, + * when the key is released, onAction is called again but this time + * with the isPressed argument set to false. + * For analog inputs, the onAction method will be called any time + * the input is non-zero, however an exception to this is for joystick axis inputs, + * which are only called when the input is above the {@link InputManager#setAxisDeadZone(float) dead zone}. + *

+ * onAnalog events are raised every frame while the input is activated. + * For digital inputs, every frame that the input is active will cause the + * onAnalog method to be called, the argument value + * argument will equal to the frame's time per frame (TPF) value but only + * for digital inputs. For analog inputs however, the value argument + * will equal the actual analog value. + */ +//@Deprecated +public class InputManager implements RawInputListener { + + CursorManager cursorManager; + JoystickManager joystickManager; + + InputUpdater updater; + EventQueue inputQueue; + EventProcessorHandler processor; + BaseListenerHandler listener; + + InputSettings settings; + Mapper mapper; + InputTimer timer; + ActionInvoker invoker; + + /** + * Initializes the InputManager. + * + *

This should only be called internally in {@link Application}. + * + * @param mouse + * @param keys + * @param joystick + * @param touch + * @throws IllegalArgumentException If either mouseInput or keyInput are null. + */ + public InputManager(Mapper m, CursorManager cm) { + this.mapper = m; + this.cursorManager = cm; + } + + /** + + * Initializes the InputManager. + * + *

This should only be called internally in {@link Application}. + * + * @throws IllegalArgumentException If either mouseInput or keyInput are null. + **/ + public InputManager(MouseInput mouse, KeyInput keys, JoyInput joystick, TouchInput touch) { + if (keys == null || mouse == null) { + throw new IllegalArgumentException("Mouse or keyboard cannot be null"); + } + + processor = new EventProcessorHandler(); + + listener = new BaseListenerHandler(); + List inputDevices = new ArrayList(); + + settings = new InputSettings(); + mapper = new Mapper(); + timer = new InputTimer(); + + invoker = new ActionInvoker(settings, mapper, timer); + + cursorManager = new CursorManager(mouse,touch); + joystickManager = new JoystickManager(this,joystick); + + inputQueue = new EventQueue(listener, processor); + + if(mouse != null){ + processor.add(new MouseEventProcessor(invoker)); + mouse.setInputListener(new MouseInputListener(inputQueue, cursorManager)); + inputDevices.add(mouse); + } + if(keys != null){ + processor.add(new KeyEventProcessor(invoker)); + keys.setInputListener(new KeyInputListener(inputQueue)); + inputDevices.add(keys); + } + if(joystick != null){ + processor.add(new JoyEventProcessor(invoker)); + joystick.setInputListener(new JoyInputListener(inputQueue)); + inputDevices.add(joystick); + } + if(touch != null){ + processor.add(new TouchEventProcessor(invoker)); + touch.setInputListener(new TouchInputListener(inputQueue, cursorManager)); + inputDevices.add(touch); + } + + updater = new InputUpdater(timer, invoker, inputQueue, inputDevices, settings); + } + + public void addListener(InputListener listener, String... mappingNames) { + mapper.addListener(listener, mappingNames);; + } + + public void removeListener(InputListener listener) { + mapper.removeListener(listener); + } + + /** + * Adds a {@link RawInputListener} to receive raw input events. + * + *

+ * Any raw input listeners registered to this InputManager + * will receive raw input events first, before they get handled + * by the InputManager itself. The listeners are + * each processed in the order they were added, e.g. FIFO. + *

+ * If a raw input listener has handled the event and does not wish + * other listeners down the list to process the event, it may set the + * {@link InputEvent#setConsumed() consumed flag} to indicate the + * event was consumed and shouldn't be processed any further. + * The listener may do this either at each of the event callbacks + * or at the {@link RawInputListener#endInput() } method. + * + * @param listener A listener to receive raw input events. + * + * @see RawInputListener + */ + public void addRawInputListener(RawInputListener listener) { + this.listener.addRawInputListener(listener); + } + + /** + * Removes a {@link RawInputListener} so that it no longer + * receives raw input events. + * + * @param listener The listener to cease receiving raw input events. + * + * @see InputManager#addRawInputListener(com.jme3.input.RawInputListener) + */ + public void removeRawInputListener(RawInputListener listener) { + this.listener.removeRawInputListener(listener); + } + + /** + * Clears all {@link RawInputListener}s. + * + * @see InputManager#addRawInputListener(com.jme3.input.RawInputListener) + */ + public void clearRawInputListeners() { + listener.clearRawInputListeners(); + } + + + public void addMapping(String mappingName, Trigger... triggers) { + mapper.addMapping(mappingName, triggers); + } + + /** + * Returns true if this InputManager has a mapping registered + * for the given mappingName. + * + * @param mappingName The mapping name to check. + * + * @see InputManager#addMapping(java.lang.String, com.jme3.input.controls.Trigger[]) + * @see InputManager#deleteMapping(java.lang.String) + */ + public boolean hasMapping(String mappingName) { + return mapper.hasMapping(mappingName); + } + + public void deleteMapping(String mappingName) { + mapper.deleteMapping(mappingName); + } + + + /** + * Deletes a specific trigger registered to a mapping. + * + *

+ * The given mapping will no longer receive events raised by the + * trigger. + * + * @param mappingName The mapping name to cease receiving events from the + * trigger. + * @param trigger The trigger to no longer invoke events on the mapping. + */ + public void deleteTrigger(String mappingName, Trigger trigger) { + mapper.deleteTrigger(mappingName, trigger); + } + + /** + * Clears all the input mappings from this InputManager. + * Consequently, also clears all of the + * InputListeners as well. + */ + public void clearMappings() { + mapper.clearMappings(); + } + /** + * Set the deadzone for joystick axes. + * + *

{@link ActionListener#onAction(java.lang.String, boolean, float) } + * events will only be raised if the joystick axis value is greater than + * the deadZone. + * + * @param deadZone the deadzone for joystick axes. + */ + public void setAxisDeadZone(float deadZone) { + settings.setGlobalAxisDeadZone(deadZone); + } + + /** + * Returns the deadzone for joystick axes. + * + * @return the deadzone for joystick axes. + */ + public float getAxisDeadZone() { + return settings.getGlobalAxisDeadZone(); + } + + /** + * Do not use. + * Called to reset pressed keys or buttons when focus is restored. + */ + public void reset() { + invoker.reset(); + } + + public void setMouseCursor(JmeCursor jmeCursor) { + cursorManager.setMouseCursor(jmeCursor); + } + + /** + * Returns whether the mouse cursor is visible or not. + * + *

By default the cursor is visible. + * + * @return whether the mouse cursor is visible or not. + * + * @see InputManager#setCursorVisible(boolean) + */ + public boolean isCursorVisible() { + return cursorManager.isCursorVisible(); + } + + /** + * Set whether the mouse cursor should be visible or not. + * + * @param visible whether the mouse cursor should be visible or not. + */ + public void setCursorVisible(boolean visible) { + cursorManager.setCursorVisible(visible); + } + + /** + * Returns the current cursor position. The position is relative to the + * bottom-left of the screen and is in pixels. + * + * @return the current cursor position + */ + public Vector2f getCursorPosition() { + return cursorManager.getCursorPosition(); + } + + /** + * Returns an array of all joysticks installed on the system. + * + * @return an array of all joysticks installed on the system. + */ + public Joystick[] getJoysticks() { + return joystickManager.getJoysticks(); + } + + /** + * Enable simulation of mouse events. Used for touchscreen input only. + * + * @param value True to enable simulation of mouse events + */ + public void setSimulateMouse(boolean value) { + cursorManager.setSimulateMouse(value); + } + /** + * @deprecated Use isSimulateMouse + * Returns state of simulation of mouse events. Used for touchscreen input only. + * + */ + public boolean getSimulateMouse() { + return cursorManager.isSimulateMouse(); + } + + /** + * Returns state of simulation of mouse events. Used for touchscreen input only. + * + */ + public boolean isSimulateMouse() { + return cursorManager.isSimulateMouse(); + } + + /** + * Enable simulation of keyboard events. Used for touchscreen input only. + * + * @param value True to enable simulation of keyboard events + */ + public void setSimulateKeyboard(boolean value) { + cursorManager.setSimulateKeyboard(value); + } + + /** + * Returns state of simulation of key events. Used for touchscreen input only. + * + */ + public boolean isSimulateKeyboard() { + return cursorManager.isSimulateKeyboard(); + } + + /** + * Updates the InputManager. + * This will query current input devices and send + * appropriate events to registered listeners. + * + * @param tpf Time per frame value. + */ + public void update(float tpf) { + updater.update(tpf); + } + + @Override + public void beginInput() { + } + + @Override + public void endInput() { + } + + public void onJoyAxisEvent(JoyAxisEvent evt) { + throw new UnsupportedOperationException("JoyInput has raised an event at an illegal time."); + } + + public void onJoyButtonEvent(JoyButtonEvent evt) { + throw new UnsupportedOperationException("JoyInput has raised an event at an illegal time."); + } + + public void onMouseMotionEvent(MouseMotionEvent evt) { + throw new UnsupportedOperationException("MouseInput has raised an event at an illegal time."); + } + + public void onMouseButtonEvent(MouseButtonEvent evt) { + throw new UnsupportedOperationException("MouseInput has raised an event at an illegal time."); + } + + public void onKeyEvent(KeyInputEvent evt) { + throw new UnsupportedOperationException("KeyInput has raised an event at an illegal time."); + } + + public void onTouchEvent(TouchEvent evt) { + throw new UnsupportedOperationException("TouchInput has raised an event at an illegal time."); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/input/InputUpdater.java b/jme3-core/src/main/java/com/jme3/input/InputUpdater.java new file mode 100644 index 0000000000..1bb395843e --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/InputUpdater.java @@ -0,0 +1,53 @@ +package com.jme3.input; + +import java.util.List; + +import com.jme3.input.queue.IEventQueue; +import com.jme3.input.util.ISetInputSettings; +import com.jme3.input.util.InputTimer; + +public class InputUpdater implements IInputUpdater { + + private InputTimer timer; + private ActionInvoker invoker; + private IEventQueue processor; + private List inputDevices; + private ISetInputSettings settings; + + public InputUpdater(InputTimer inputTimer, ActionInvoker actionInvoker, IEventQueue queueProcessor, List inputDevices, ISetInputSettings inputSettings) { + timer = inputTimer; + invoker = actionInvoker; + processor = queueProcessor; + this.inputDevices = inputDevices; + settings = inputSettings; + } + + /** + * Updates the whole InputSystem. + * This will query current input devices and send + * appropriate events to registered listeners. + * + * @param tpf Time per frame value. + */ + public void update(float tpf) { + settings.setFrameTPF(tpf); + + // Activate safemode if the TPF value is so small + // that rounding errors are inevitable + settings.setSafeMode(tpf < 0.015f); + + long currentTime = java.lang.System.currentTimeMillis(); + timer.setFrameDelta(currentTime - timer.getLastUpdateTime()); + + for(Input inp : inputDevices) + { + inp.update(); + } + + processor.processQueue(); + invoker.invokeUpdateActions(); + + timer.setLastLastUpdateTime(timer.getLastUpdateTime()); + timer.setLastUpdateTime(currentTime); + } +} diff --git a/jme3-core/src/main/java/com/jme3/input/JoystickManager.java b/jme3-core/src/main/java/com/jme3/input/JoystickManager.java new file mode 100644 index 0000000000..2d52e4cf95 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/JoystickManager.java @@ -0,0 +1,32 @@ +package com.jme3.input; + +public class JoystickManager implements IJoyStickSettings{ + + private float deadZone = 0.05F; + private InputManager inputManager; + private JoyInput joystick; + + + public JoystickManager(InputManager inputManager, JoyInput joystick) + { + this.inputManager = inputManager; + this.joystick = joystick; + } + + @Override + public void setAxisDeadZone(float deadZone) { + this.deadZone = deadZone; + } + + @Override + public float getAxisDeadZone() { + return deadZone; + } + + @Override + public Joystick[] getJoysticks() { + if(joystick == null) + return null; + return joystick.loadJoysticks(inputManager); + } +} diff --git a/jme3-core/src/main/java/com/jme3/input/Mapper.java b/jme3-core/src/main/java/com/jme3/input/Mapper.java new file mode 100644 index 0000000000..6688917837 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/Mapper.java @@ -0,0 +1,139 @@ +package com.jme3.input; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.jme3.input.controls.InputListener; +import com.jme3.input.controls.Trigger; +import com.jme3.util.IntMap; + +public class Mapper implements IMapper, IListenerManager, IReadBindings { + + private static final Logger logger = Logger.getLogger(InputManager.class.getName()); + private final HashMap mappings = new HashMap(); + private final IntMap> bindings = new IntMap>(); + + /* (non-Javadoc) + * @see com.jme3.input.IMapper#addMapping(java.lang.String, com.jme3.input.controls.Trigger) + */ + @Override + public void addMapping(String mappingName, Trigger... triggers) { + Mapping mapping = mappings.get(mappingName); + if (mapping == null) { + mapping = new Mapping(mappingName); + mappings.put(mappingName, mapping); + } + + for (Trigger trigger : triggers) { + int hash = trigger.triggerHashCode(); + ArrayList names = bindings.get(hash); + if (names == null) { + names = new ArrayList(); + bindings.put(hash, names); + } + if (!names.contains(mapping)) { + names.add(mapping); + mapping.triggers.add(hash); + } else { + logger.log(Level.WARNING, "Attempted to add mapping \"{0}\" twice to trigger.", mappingName); + } + } + } + + /* (non-Javadoc) + * @see com.jme3.input.IMapper#deleteMapping(java.lang.String) + */ + @Override + public void deleteMapping(String mappingName) { + Mapping mapping = mappings.remove(mappingName); + if (mapping == null) { + //throw new IllegalArgumentException("Cannot find mapping: " + mappingName); + logger.log(Level.WARNING, "Cannot find mapping to be removed, skipping: {0}", mappingName); + return; + } + + ArrayList triggers = mapping.triggers; + for (int i = triggers.size() - 1; i >= 0; i--) { + int hash = triggers.get(i); + ArrayList maps = bindings.get(hash); + maps.remove(mapping); + } + } + + /* (non-Javadoc) + * @see com.jme3.input.IMapper#hasMapping(java.lang.String) + */ + @Override + public boolean hasMapping(String mappingName) { + return mappings.containsKey(mappingName); + } + + /* (non-Javadoc) + * @see com.jme3.input.IMapper#deleteTrigger(java.lang.String, com.jme3.input.controls.Trigger) + */ + @Override + public void deleteTrigger(String mappingName, Trigger trigger) { + Mapping mapping = mappings.get(mappingName); + if (mapping == null) { + throw new IllegalArgumentException("Cannot find mapping: " + mappingName); + } + + ArrayList maps = bindings.get(trigger.triggerHashCode()); + maps.remove(mapping); + + } + + /* (non-Javadoc) + * @see com.jme3.input.IListenerManager#addListener(com.jme3.input.controls.InputListener, java.lang.String) + */ + @Override + public void addListener(InputListener listener, String... mappingNames) { + for (String mappingName : mappingNames) { + Mapping mapping = mappings.get(mappingName); + if (mapping == null) { + mapping = new Mapping(mappingName); + mappings.put(mappingName, mapping); + } + if (!mapping.listeners.contains(listener)) { + mapping.listeners.add(listener); + } + } + } + + /* (non-Javadoc) + * @see com.jme3.input.IListenerManager#removeListener(com.jme3.input.controls.InputListener) + */ + @Override + public void removeListener(InputListener listener) { + for (Mapping mapping : mappings.values()) { + mapping.listeners.remove(listener); + } + } + + public List getMappings(int hash) + { + return bindings.get(hash); + } + + public boolean contains(int hash) + { + return bindings.containsKey(hash); + } + + + /* (non-Javadoc) + * @see com.jme3.input.IMapper#clearMappings() + */ + @Override + public void clearMappings() { + mappings.clear(); + bindings.clear(); + } + + + + +} diff --git a/jme3-core/src/main/java/com/jme3/input/Mapping.java b/jme3-core/src/main/java/com/jme3/input/Mapping.java new file mode 100644 index 0000000000..1f9278e811 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/Mapping.java @@ -0,0 +1,16 @@ +package com.jme3.input; + +import java.util.ArrayList; + +import com.jme3.input.controls.InputListener; + +public class Mapping { + + public final String name; + public final ArrayList triggers = new ArrayList(); + public final ArrayList listeners = new ArrayList(); + + public Mapping(String name) { + this.name = name; + } +} diff --git a/jme3-core/src/main/java/com/jme3/input/RawInputListener.java b/jme3-core/src/main/java/com/jme3/input/RawInputListener.java index 6ba37ec2ef..12858fabc2 100644 --- a/jme3-core/src/main/java/com/jme3/input/RawInputListener.java +++ b/jme3-core/src/main/java/com/jme3/input/RawInputListener.java @@ -96,4 +96,6 @@ public interface RawInputListener { */ public void onTouchEvent(TouchEvent evt); + + } diff --git a/jme3-core/src/main/java/com/jme3/input/eventprocessing/EventProcessor.java b/jme3-core/src/main/java/com/jme3/input/eventprocessing/EventProcessor.java new file mode 100644 index 0000000000..0eece8277f --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/eventprocessing/EventProcessor.java @@ -0,0 +1,21 @@ +package com.jme3.input.eventprocessing; + +import com.jme3.input.event.InputEvent; + +public interface EventProcessor { + + /** + * Process the event, if the event is not accepted the event + * will not be processed. + * @param event + */ + public void processEvent(InputEvent event); + + /** + * Returns true if the InputEvent is accepted by this EVP. + * @param event The event to be checked + * @return True if event will be processed + */ + public boolean accepts(InputEvent event); + +} diff --git a/jme3-core/src/main/java/com/jme3/input/eventprocessing/EventProcessorHandler.java b/jme3-core/src/main/java/com/jme3/input/eventprocessing/EventProcessorHandler.java new file mode 100644 index 0000000000..c9d86909b6 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/eventprocessing/EventProcessorHandler.java @@ -0,0 +1,63 @@ +package com.jme3.input.eventprocessing; + +import java.util.List; + +import com.jme3.input.event.InputEvent; +import com.jme3.input.event.JoyAxisEvent; +import com.jme3.input.event.JoyButtonEvent; +import com.jme3.input.event.KeyInputEvent; +import com.jme3.input.event.MouseButtonEvent; +import com.jme3.input.event.MouseMotionEvent; +import com.jme3.input.event.TouchEvent; +import com.jme3.util.SafeArrayList; + +public class EventProcessorHandler implements IEventProcessor{ + + private final SafeArrayList eventProcessors = new SafeArrayList(EventProcessor.class); + + /* (non-Javadoc) + * @see com.jme3.input.IEventProcessor#add(com.jme3.input.EventProcessor) + */ + @Override + public void add(EventProcessor evp) + { + eventProcessors.add(evp); + } + + /* (non-Javadoc) + * @see com.jme3.input.IEventProcessor#remove(com.jme3.input.EventProcessor) + */ + @Override + public void remove(EventProcessor evp) + { + eventProcessors.remove(evp); + } + + /* (non-Javadoc) + * @see com.jme3.input.IEvenProcessor#emit(java.util.List) + */ + @Override + public void emit(List inputQueue) + { + int queueSize = inputQueue.size(); + + for (int i = 0; i < queueSize; i++) { + InputEvent event = inputQueue.get(i); + if (event.isConsumed()) { + continue; + } + + for(EventProcessor evp : eventProcessors) + { + evp.processEvent(event); + } + + // TODO: Check if this is true? + // larynx, 2011.06.10 - flag event as reusable because + // the android input uses a non-allocating ringbuffer which + // needs to know when the event is not anymore in inputQueue + // and therefor can be reused. + event.setConsumed(); + } + } +} diff --git a/jme3-core/src/main/java/com/jme3/input/eventprocessing/IEventProcessor.java b/jme3-core/src/main/java/com/jme3/input/eventprocessing/IEventProcessor.java new file mode 100644 index 0000000000..b3a1b3516e --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/eventprocessing/IEventProcessor.java @@ -0,0 +1,28 @@ +package com.jme3.input.eventprocessing; + +import java.util.List; + +import com.jme3.input.event.InputEvent; + +public interface IEventProcessor { + + /** + * Will emit the inputEvents to all registered EventProcessors + * @param inputQueue + */ + void emit(List inputQueue); + + /** + * Add evenProcessor to the list over EVP which will receive + * events. + * @param evp + */ + void add(EventProcessor evp); + + /** + * Removes eventProcessor from the list of Evp wich will receive events. + * @param evp + */ + void remove(EventProcessor evp); + +} \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/input/eventprocessing/JoyEventProcessor.java b/jme3-core/src/main/java/com/jme3/input/eventprocessing/JoyEventProcessor.java new file mode 100644 index 0000000000..a4070ee144 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/eventprocessing/JoyEventProcessor.java @@ -0,0 +1,105 @@ +package com.jme3.input.eventprocessing; + +import com.jme3.input.ActionInvoker; +import com.jme3.input.controls.JoyAxisTrigger; +import com.jme3.input.controls.JoyButtonTrigger; +import com.jme3.input.event.InputEvent; +import com.jme3.input.event.JoyAxisEvent; +import com.jme3.input.event.JoyButtonEvent; +import com.jme3.input.util.IReadInputSettings; +import com.jme3.util.IntMap; + +public class JoyEventProcessor implements EventProcessor { + + private final IntMap axisValues = new IntMap(); + private ActionInvoker invoker; + + public JoyEventProcessor(ActionInvoker actionInvoker) + { + invoker = actionInvoker; + } + + @Override + public void processEvent(InputEvent event) { + // TODO Auto-generated method stub + if(event instanceof JoyButtonEvent){ + onJoyButtonEventQueued((JoyButtonEvent) event); + }else if(event instanceof JoyAxisEvent){ + onJoyAxisEventQueued((JoyAxisEvent) event); + } + } + + private void onJoyAxisEventQueued(JoyAxisEvent evt) { + + int joyId = evt.getJoyIndex(); + int axis = evt.getAxisIndex(); + float value = evt.getValue(); + float effectiveDeadZone = Math.max(invoker.getSettings().getGlobalAxisDeadZone(), evt.getAxis().getDeadZone()); + if (value < effectiveDeadZone && value > -effectiveDeadZone) { + int hash1 = JoyAxisTrigger.joyAxisHash(joyId, axis, true); + int hash2 = JoyAxisTrigger.joyAxisHash(joyId, axis, false); + + Float val1 = axisValues.get(hash1); + Float val2 = axisValues.get(hash2); + + if (val1 != null && val1 > effectiveDeadZone) { + invoker.invokeActions(hash1, false); + } + if (val2 != null && val2 > effectiveDeadZone) { + invoker.invokeActions(hash2, false); + } + + axisValues.remove(hash1); + axisValues.remove(hash2); + + } else if (value < 0) { + int hash = JoyAxisTrigger.joyAxisHash(joyId, axis, true); + int otherHash = JoyAxisTrigger.joyAxisHash(joyId, axis, false); + + // Clear the reverse direction's actions in case we + // crossed center too quickly + Float otherVal = axisValues.get(otherHash); + if (otherVal != null && otherVal > effectiveDeadZone) { + invoker.invokeActions(otherHash, false); + } + + invoker.invokeAnalogsAndActions(hash, -value, effectiveDeadZone, true, axisValues); + axisValues.put(hash, -value); + axisValues.remove(otherHash); + } else { + int hash = JoyAxisTrigger.joyAxisHash(joyId, axis, false); + int otherHash = JoyAxisTrigger.joyAxisHash(joyId, axis, true); + + // Clear the reverse direction's actions in case we + // crossed center too quickly + Float otherVal = axisValues.get(otherHash); + if (otherVal != null && otherVal > effectiveDeadZone) { + invoker.invokeActions(otherHash, false); + } + + invoker.invokeAnalogsAndActions(hash, value, effectiveDeadZone, true, axisValues); + axisValues.put(hash, value); + axisValues.remove(otherHash); + } + } + + private void onJoyButtonEventQueued(JoyButtonEvent evt) { + int hash = JoyButtonTrigger.joyButtonHash(evt.getJoyIndex(), evt.getButtonIndex()); + + invoker.invokeActions(hash, evt.isPressed()); + invoker.invokeTimedActions(hash, evt.getTime(), evt.isPressed()); + } + + + @Override + public boolean accepts(InputEvent event) { + if(event instanceof JoyButtonEvent){ + return true; + }else if(event instanceof JoyAxisEvent){ + return true; + } + + return false; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/input/eventprocessing/KeyEventProcessor.java b/jme3-core/src/main/java/com/jme3/input/eventprocessing/KeyEventProcessor.java new file mode 100644 index 0000000000..84688ef548 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/eventprocessing/KeyEventProcessor.java @@ -0,0 +1,39 @@ +package com.jme3.input.eventprocessing; + +import com.jme3.input.ActionInvoker; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.event.InputEvent; +import com.jme3.input.event.KeyInputEvent; + +public class KeyEventProcessor implements EventProcessor { + + private ActionInvoker invoker; + + public KeyEventProcessor(ActionInvoker actionInvoker) + { + invoker = actionInvoker; + } + + @Override + public void processEvent(InputEvent event) { + if(event instanceof KeyInputEvent){ + onKeyEventQueued((KeyInputEvent) event); + } + } + + private void onKeyEventQueued(KeyInputEvent evt) { + if (evt.isRepeating()) { + return; // repeat events not used for bindings + } + + int hash = KeyTrigger.keyHash(evt.getKeyCode()); + invoker.invokeActions(hash, evt.isPressed()); + invoker.invokeTimedActions(hash, evt.getTime(), evt.isPressed()); + } + + @Override + public boolean accepts(InputEvent event) { + return (event instanceof KeyInputEvent); + } + +} diff --git a/jme3-core/src/main/java/com/jme3/input/eventprocessing/MouseEventProcessor.java b/jme3-core/src/main/java/com/jme3/input/eventprocessing/MouseEventProcessor.java new file mode 100644 index 0000000000..715cfba378 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/eventprocessing/MouseEventProcessor.java @@ -0,0 +1,69 @@ +package com.jme3.input.eventprocessing; + +import com.jme3.input.ActionInvoker; +import com.jme3.input.MouseInput; +import com.jme3.input.controls.MouseAxisTrigger; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.input.event.InputEvent; +import com.jme3.input.event.MouseButtonEvent; +import com.jme3.input.event.MouseMotionEvent; +import com.jme3.input.util.IReadInputSettings; + +public class MouseEventProcessor implements EventProcessor { + + private ActionInvoker invoker; + + public MouseEventProcessor(ActionInvoker actionInvoker) + { + invoker = actionInvoker; + } + + @Override + public void processEvent(InputEvent event) { + if(event instanceof MouseButtonEvent) { + onMouseButtonEventQueued((MouseButtonEvent) event); + } else if(event instanceof MouseMotionEvent) { + onMouseMotionEventQueued((MouseMotionEvent) event); + } + } + + private void onMouseButtonEventQueued(MouseButtonEvent evt) { + int hash = MouseButtonTrigger.mouseButtonHash(evt.getButtonIndex()); + invoker.invokeActions(hash, evt.isPressed()); + invoker.invokeTimedActions(hash, evt.getTime(), evt.isPressed()); + } + + + private void onMouseMotionEventQueued(MouseMotionEvent evt) { + + if (evt.getDX() != 0) { + float val = Math.abs(evt.getDX()) / 1024f; + invoker.invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_X, evt.getDX() < 0), + val, invoker.getSettings().getGlobalAxisDeadZone(), false); + } + if (evt.getDY() != 0) { + float val = Math.abs(evt.getDY()) / 1024f; + invoker.invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_Y, evt.getDY() < 0), + val, invoker.getSettings().getGlobalAxisDeadZone(), false); + } + if (evt.getDeltaWheel() != 0) { + float val = Math.abs(evt.getDeltaWheel()) / 100f; + invoker.invokeAnalogsAndActions(MouseAxisTrigger.mouseAxisHash(MouseInput.AXIS_WHEEL, evt.getDeltaWheel() < 0), + val, invoker.getSettings().getGlobalAxisDeadZone(), false); + } + } + + @Override + public boolean accepts(InputEvent event) { + // TODO Auto-generated method stub + if(event instanceof MouseMotionEvent) + { + return true; + }else if(event instanceof MouseButtonEvent){ + return true; + } + + return false; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/input/eventprocessing/TouchEventProcessor.java b/jme3-core/src/main/java/com/jme3/input/eventprocessing/TouchEventProcessor.java new file mode 100644 index 0000000000..2d8c65c9c0 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/eventprocessing/TouchEventProcessor.java @@ -0,0 +1,30 @@ +package com.jme3.input.eventprocessing; + +import com.jme3.input.ActionInvoker; +import com.jme3.input.event.InputEvent; +import com.jme3.input.event.TouchEvent; + +public class TouchEventProcessor implements EventProcessor { + + private ActionInvoker invoker; + + public TouchEventProcessor(ActionInvoker actionInvoker) + { + invoker = actionInvoker; + } + + @Override + public void processEvent(InputEvent event) { + if(event instanceof TouchEvent) + { + invoker.invokeTouchActions((TouchEvent) event); + } + + } + + @Override + public boolean accepts(InputEvent event) { + return event instanceof TouchEvent; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/input/inputListener/BaseInputListener.java b/jme3-core/src/main/java/com/jme3/input/inputListener/BaseInputListener.java new file mode 100644 index 0000000000..d01ae2262a --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/inputListener/BaseInputListener.java @@ -0,0 +1,25 @@ +package com.jme3.input.inputListener; + +import com.jme3.input.RawInputListener; +import com.jme3.input.event.InputEvent; +import com.jme3.input.queue.IEventQueue; + +public abstract class BaseInputListener implements RawInputListener{ + + public IEventQueue inputQueue; + + public BaseInputListener(IEventQueue queue) + { + this.inputQueue = queue; + } + + public abstract void onEvent(InputEvent event); + + @Override + public void beginInput() { + } + + @Override + public void endInput() { + } +} diff --git a/jme3-core/src/main/java/com/jme3/input/inputListener/JoyInputListener.java b/jme3-core/src/main/java/com/jme3/input/inputListener/JoyInputListener.java new file mode 100644 index 0000000000..1689f3fc53 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/inputListener/JoyInputListener.java @@ -0,0 +1,67 @@ +package com.jme3.input.inputListener; + +import com.jme3.input.event.InputEvent; +import com.jme3.input.event.JoyAxisEvent; +import com.jme3.input.event.JoyButtonEvent; +import com.jme3.input.event.KeyInputEvent; +import com.jme3.input.event.MouseButtonEvent; +import com.jme3.input.event.MouseMotionEvent; +import com.jme3.input.event.TouchEvent; +import com.jme3.input.queue.IEventQueue; + +public class JoyInputListener extends BaseInputListener{ + + public JoyInputListener(IEventQueue queue) { + super(queue); + // TODO Auto-generated constructor stub + } + + @Override + public void onEvent(InputEvent event) { + if(event instanceof JoyAxisEvent || event instanceof JoyButtonEvent) + { +// if (!eventsPermitted) { +// throw new UnsupportedOperationException("JoyInput has raised an event at an illegal time."); +// } + + inputQueue.add(event); + } + } + + @Override + public void onJoyAxisEvent(JoyAxisEvent evt) { + onEvent(evt); + + } + + @Override + public void onJoyButtonEvent(JoyButtonEvent evt) { + onEvent(evt); + + } + + @Override + public void onMouseMotionEvent(MouseMotionEvent evt) { + onEvent(evt); + + } + + @Override + public void onMouseButtonEvent(MouseButtonEvent evt) { + onEvent(evt); + + } + + @Override + public void onKeyEvent(KeyInputEvent evt) { + onEvent(evt); + + } + + @Override + public void onTouchEvent(TouchEvent evt) { + onEvent(evt); + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/input/inputListener/KeyInputListener.java b/jme3-core/src/main/java/com/jme3/input/inputListener/KeyInputListener.java new file mode 100644 index 0000000000..c4e89e84f3 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/inputListener/KeyInputListener.java @@ -0,0 +1,67 @@ +package com.jme3.input.inputListener; + +import com.jme3.input.event.InputEvent; +import com.jme3.input.event.JoyAxisEvent; +import com.jme3.input.event.JoyButtonEvent; +import com.jme3.input.event.KeyInputEvent; +import com.jme3.input.event.MouseButtonEvent; +import com.jme3.input.event.MouseMotionEvent; +import com.jme3.input.event.TouchEvent; +import com.jme3.input.queue.IEventQueue; + +public class KeyInputListener extends BaseInputListener { + + public KeyInputListener(IEventQueue queue) { + super(queue); + } + + @Override + public void onEvent(InputEvent event) { + if(event instanceof KeyInputEvent) + { +// if (!eventsPermitted) { +// throw new UnsupportedOperationException("KeyInput has raised an event at an illegal time."); +// } + + inputQueue.add(event); + } + } + + @Override + public void onJoyAxisEvent(JoyAxisEvent evt) { + onEvent(evt); + + } + + @Override + public void onJoyButtonEvent(JoyButtonEvent evt) { + onEvent(evt); + + } + + @Override + public void onMouseMotionEvent(MouseMotionEvent evt) { + onEvent(evt); + + } + + @Override + public void onMouseButtonEvent(MouseButtonEvent evt) { + onEvent(evt); + + } + + @Override + public void onKeyEvent(KeyInputEvent evt) { + onEvent(evt); + + } + + @Override + public void onTouchEvent(TouchEvent evt) { + onEvent(evt); + + } + + +} diff --git a/jme3-core/src/main/java/com/jme3/input/inputListener/MouseInputListener.java b/jme3-core/src/main/java/com/jme3/input/inputListener/MouseInputListener.java new file mode 100644 index 0000000000..1272f70c35 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/inputListener/MouseInputListener.java @@ -0,0 +1,79 @@ +package com.jme3.input.inputListener; + +import com.jme3.input.ICursorPos; +import com.jme3.input.event.InputEvent; +import com.jme3.input.event.JoyAxisEvent; +import com.jme3.input.event.JoyButtonEvent; +import com.jme3.input.event.KeyInputEvent; +import com.jme3.input.event.MouseButtonEvent; +import com.jme3.input.event.MouseMotionEvent; +import com.jme3.input.event.TouchEvent; +import com.jme3.input.queue.IEventQueue; + +public class MouseInputListener extends BaseInputListener { + + private ICursorPos cursorPos; + + public MouseInputListener(IEventQueue queue, ICursorPos cp) + { + super(queue); + this.cursorPos = cp; + } + + @Override + public void onEvent(InputEvent event) { +// if (!eventsPermitted) { +// throw new UnsupportedOperationException("MouseInput has raised an event at an illegal time."); +// } + + if(event instanceof MouseMotionEvent){ + MouseMotionEvent evt = (MouseMotionEvent) event; + cursorPos.setCursorPosition(evt.getX(), evt.getY()); + }else if(event instanceof MouseButtonEvent){ + MouseButtonEvent evt = (MouseButtonEvent) event; + cursorPos.setCursorPosition(evt.getX(), evt.getY()); + }else { + return; + } + + + inputQueue.add(event); + } + + @Override + public void onJoyAxisEvent(JoyAxisEvent evt) { + onEvent(evt); + + } + + @Override + public void onJoyButtonEvent(JoyButtonEvent evt) { + onEvent(evt); + + } + + @Override + public void onMouseMotionEvent(MouseMotionEvent evt) { + onEvent(evt); + + } + + @Override + public void onMouseButtonEvent(MouseButtonEvent evt) { + onEvent(evt); + + } + + @Override + public void onKeyEvent(KeyInputEvent evt) { + onEvent(evt); + + } + + @Override + public void onTouchEvent(TouchEvent evt) { + onEvent(evt); + + } + +} diff --git a/jme3-core/src/main/java/com/jme3/input/inputListener/TouchInputListener.java b/jme3-core/src/main/java/com/jme3/input/inputListener/TouchInputListener.java new file mode 100644 index 0000000000..1e0e228456 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/inputListener/TouchInputListener.java @@ -0,0 +1,74 @@ +package com.jme3.input.inputListener; + +import com.jme3.input.ICursorPos; +import com.jme3.input.event.InputEvent; +import com.jme3.input.event.JoyAxisEvent; +import com.jme3.input.event.JoyButtonEvent; +import com.jme3.input.event.KeyInputEvent; +import com.jme3.input.event.MouseButtonEvent; +import com.jme3.input.event.MouseMotionEvent; +import com.jme3.input.event.TouchEvent; +import com.jme3.input.queue.IEventQueue; + +public class TouchInputListener extends BaseInputListener{ + + private ICursorPos cursorPos; + + public TouchInputListener(IEventQueue queue, ICursorPos cp) + { + super(queue); + this.cursorPos = cp; + } + + @Override + public void onEvent(InputEvent event) { + if(event instanceof TouchEvent) + { + TouchEvent evt = (TouchEvent) event; +// if (!eventsPermitted) { +// throw new UnsupportedOperationException("MouseInput has raised an event at an illegal time."); +// } + + cursorPos.setCursorPosition(evt.getX(), evt.getY()); + inputQueue.add(event); + } + } + + @Override + public void onJoyAxisEvent(JoyAxisEvent evt) { + onEvent(evt); + + } + + @Override + public void onJoyButtonEvent(JoyButtonEvent evt) { + onEvent(evt); + + } + + @Override + public void onMouseMotionEvent(MouseMotionEvent evt) { + onEvent(evt); + + } + + @Override + public void onMouseButtonEvent(MouseButtonEvent evt) { + onEvent(evt); + + } + + @Override + public void onKeyEvent(KeyInputEvent evt) { + onEvent(evt); + + } + + @Override + public void onTouchEvent(TouchEvent evt) { + onEvent(evt); + + } + +} + diff --git a/jme3-core/src/main/java/com/jme3/input/queue/EventQueue.java b/jme3-core/src/main/java/com/jme3/input/queue/EventQueue.java new file mode 100644 index 0000000000..eac087bbda --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/queue/EventQueue.java @@ -0,0 +1,49 @@ +package com.jme3.input.queue; + +import java.util.ArrayList; + +import com.jme3.input.IBaseListenerEmitter; +import com.jme3.input.event.InputEvent; +import com.jme3.input.eventprocessing.IEventProcessor; + +public class EventQueue implements IEventQueue{ + + private final ArrayList inputQueue = new ArrayList(); + private IBaseListenerEmitter baselisteners; + private IEventProcessor eventprocessors; + public boolean eventsPermitted = false; + + /** + * Initializes the EventQueue + */ + public EventQueue( IBaseListenerEmitter listener, IEventProcessor eventProcessor ) { + baselisteners = listener; + eventprocessors = eventProcessor; + } + + /* (non-Javadoc) + * @see com.jme3.input.IQueueProcessor#processQueue() + */ + @Override + public void processQueue() { + baselisteners.emit(inputQueue); + + eventprocessors.emit(inputQueue); + + inputQueue.clear(); + } + + + @Override + public void add(InputEvent event) { + inputQueue.add(event); + } + + public IBaseListenerEmitter getBaselisteners() { + return baselisteners; + } + + public IEventProcessor getEventprocessors() { + return eventprocessors; + } +} diff --git a/jme3-core/src/main/java/com/jme3/input/queue/IEventQueue.java b/jme3-core/src/main/java/com/jme3/input/queue/IEventQueue.java new file mode 100644 index 0000000000..7a092c38e1 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/queue/IEventQueue.java @@ -0,0 +1,17 @@ +package com.jme3.input.queue; + +import com.jme3.input.event.InputEvent; + +public interface IEventQueue { + + /** + * Add event ot Queue. + * @param event + */ + public void add(InputEvent event); + + /** + * Process the evenQueue + */ + public void processQueue(); +} diff --git a/jme3-core/src/main/java/com/jme3/input/util/IReadInputSettings.java b/jme3-core/src/main/java/com/jme3/input/util/IReadInputSettings.java new file mode 100644 index 0000000000..71bc79819e --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/util/IReadInputSettings.java @@ -0,0 +1,10 @@ +package com.jme3.input.util; + +public interface IReadInputSettings { + + float getFrameTPF(); + + float getGlobalAxisDeadZone(); + + public boolean safeModeEnabled(); +} \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/input/util/IReadTimer.java b/jme3-core/src/main/java/com/jme3/input/util/IReadTimer.java new file mode 100644 index 0000000000..8366ca0d50 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/util/IReadTimer.java @@ -0,0 +1,11 @@ +package com.jme3.input.util; + +public interface IReadTimer { + + long getLastLastUpdateTime(); + + long getLastUpdateTime(); + + long getFrameDelta(); + +} \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/input/util/ISetInputSettings.java b/jme3-core/src/main/java/com/jme3/input/util/ISetInputSettings.java new file mode 100644 index 0000000000..4f0ab40a67 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/util/ISetInputSettings.java @@ -0,0 +1,11 @@ +package com.jme3.input.util; + +public interface ISetInputSettings { + + void setFrameTPF(float frameTPF); + + void setGlobalAxisDeadZone(float globalAxisDeadZone); + + void setSafeMode(boolean s); + +} \ No newline at end of file diff --git a/jme3-core/src/main/java/com/jme3/input/util/InputSettings.java b/jme3-core/src/main/java/com/jme3/input/util/InputSettings.java new file mode 100644 index 0000000000..88b636f45f --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/util/InputSettings.java @@ -0,0 +1,52 @@ +package com.jme3.input.util; + +public class InputSettings implements IReadInputSettings, ISetInputSettings { + + private float frameTPF; + private float globalAxisDeadZone = 0.05f; + private boolean safemode = false; + + /* (non-Javadoc) + * @see com.jme3.input.IReadInputSettings#getFrameTPF() + */ + @Override + public float getFrameTPF() { + return frameTPF; + } + /* (non-Javadoc) + * @see com.jme3.input.ISetInputSettings#setFrameTPF(float) + */ + @Override + public void setFrameTPF(float frameTPF) { + this.frameTPF = frameTPF; + } + /* (non-Javadoc) + * @see com.jme3.input.IReadInputSettings#getGlobalAxisDeadZone() + */ + @Override + public float getGlobalAxisDeadZone() { + return globalAxisDeadZone; + } + /* (non-Javadoc) + * @see com.jme3.input.ISetInputSettings#setGlobalAxisDeadZone(float) + */ + @Override + public void setGlobalAxisDeadZone(float globalAxisDeadZone) { + this.globalAxisDeadZone = globalAxisDeadZone; + } + + /* (non-Javadoc) + * @see com.jme3.input.ISetInputSettings#setSafeMode(boolean) + */ + @Override + public void setSafeMode(boolean s) + { + safemode = s; + } + + public boolean safeModeEnabled() + { + return safemode; + } + +} diff --git a/jme3-core/src/main/java/com/jme3/input/util/InputTimer.java b/jme3-core/src/main/java/com/jme3/input/util/InputTimer.java new file mode 100644 index 0000000000..61fd11f7f5 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/util/InputTimer.java @@ -0,0 +1,41 @@ +package com.jme3.input.util; + +public class InputTimer implements IReadTimer { + + private long lastLastUpdateTime = 0; + private long lastUpdateTime = 0; + private long frameDelta = 0; + + /* (non-Javadoc) + * @see com.jme3.input.IReadTimer#getLastLastUpdateTime() + */ + @Override + public long getLastLastUpdateTime() { + return lastLastUpdateTime; + } + public void setLastLastUpdateTime(long lastLastUpdateTime) { + this.lastLastUpdateTime = lastLastUpdateTime; + } + /* (non-Javadoc) + * @see com.jme3.input.IReadTimer#getLastUpdateTime() + */ + @Override + public long getLastUpdateTime() { + return lastUpdateTime; + } + public void setLastUpdateTime(long lastUpdateTime) { + this.lastUpdateTime = lastUpdateTime; + } + /* (non-Javadoc) + * @see com.jme3.input.IReadTimer#getFrameDelta() + */ + @Override + public long getFrameDelta() { + return frameDelta; + } + public void setFrameDelta(long frameDelta) { + this.frameDelta = frameDelta; + } + + +} diff --git a/jme3-core/src/main/java/com/jme3/input/util/JoyStickSettings.java b/jme3-core/src/main/java/com/jme3/input/util/JoyStickSettings.java new file mode 100644 index 0000000000..38265f5141 --- /dev/null +++ b/jme3-core/src/main/java/com/jme3/input/util/JoyStickSettings.java @@ -0,0 +1,43 @@ +package com.jme3.input.util; + +import com.jme3.input.Joystick; +import com.jme3.input.controls.ActionListener; + +public class JoyStickSettings { + + private float globalAxisDeadZone; + private Joystick[] joysticks; + + /** + * Set the deadzone for joystick axes. + * + *

{@link ActionListener#onAction(java.lang.String, boolean, float) } + * events will only be raised if the joystick axis value is greater than + * the deadZone. + * + * @param deadZone the deadzone for joystick axes. + */ + public void setAxisDeadZone(float deadZone) { + this.globalAxisDeadZone = deadZone; + } + + /** + * Returns the deadzone for joystick axes. + * + * @return the deadzone for joystick axes. + */ + public float getAxisDeadZone() { + return globalAxisDeadZone; + } + + + /** + * Returns an array of all joysticks installed on the system. + * + * @return an array of all joysticks installed on the system. + */ + public Joystick[] getJoysticks() { + return joysticks; + } + +} diff --git a/jme3-core/src/test/java/com/jme3/input/InputManagerMappingTest.java b/jme3-core/src/test/java/com/jme3/input/InputManagerMappingTest.java new file mode 100644 index 0000000000..4651124626 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/InputManagerMappingTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.input; + + +import com.jme3.input.InputManager; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.dummy.DummyKeyInput; +import com.jme3.input.dummy.DummyMouseInput; +import com.jme3.test.util.TestLogHandler; + +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Tests functionality of input behaviour as: http://marketplace.eclipse.org/marketplace-client-intro?mpc_install=264 + * + * @author + */ +public class InputManagerMappingTest { + + public InputManager inputManager; + public TestLogHandler tlh; + + @Before + public void setUp() { + inputManager = new InputManager(new DummyMouseInput(), new DummyKeyInput(), null, null); + + Logger logger = Logger.getLogger(InputManager.class.getName()); + tlh = new TestLogHandler(); + tlh.setLevel(Level.ALL); + logger.setUseParentHandlers(false); + logger.addHandler(tlh); + logger.setLevel(Level.ALL); + } + + + @Test(expected = IllegalArgumentException.class) + public void testConstructorInvalid1() + { + inputManager = new InputManager(null, new DummyKeyInput(), null, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testConstructorInvalid2() + { + inputManager = new InputManager(new DummyMouseInput(), null, null, null); + } + + @Test + public void testAddNewMapping() + { + inputManager.addMapping("testMapping", new KeyTrigger(0)); + assertTrue(inputManager.hasMapping("testMapping")); + } + + @Test + public void testAddExistingMapping() + { + inputManager.addMapping("testMapping", new KeyTrigger(0)); + inputManager.addMapping("testMapping", new KeyTrigger(1)); + assertTrue(inputManager.hasMapping("testMapping")); + } + + @Test + public void testAddTriggerTwice() + { + inputManager.addMapping("testMapping", new KeyTrigger(0)); + inputManager.addMapping("testMapping", new KeyTrigger(0)); + assertTrue(inputManager.hasMapping("testMapping")); + assertEquals(1, tlh.getNrOfLoggedMessages()); + } + + @Test + public void testRemoveMappingExisting() + { + inputManager.addMapping("testMapping", new KeyTrigger(5)); + inputManager.deleteMapping("testMapping"); + assertFalse(inputManager.hasMapping("testMapping")); + } + + @Test + public void testRemoveMappingNonExistent() + { + inputManager.addMapping("testMapping", new KeyTrigger(1)); + inputManager.deleteMapping("test"); + assertEquals(1, tlh.getNrOfLoggedMessages()); + } + + @Test + public void testClearMapping() + { + inputManager.addMapping("testMapping1", new KeyTrigger(8)); + inputManager.addMapping("testMapping2", new KeyTrigger(9)); + inputManager.clearMappings(); + assertFalse(inputManager.hasMapping("testMapping1")); + assertFalse(inputManager.hasMapping("testMapping2")); + } +} diff --git a/jme3-core/src/test/java/com/jme3/input/InputManagerTest.java b/jme3-core/src/test/java/com/jme3/input/InputManagerTest.java new file mode 100644 index 0000000000..30090d6998 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/InputManagerTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.input; + + +import com.jme3.input.dummy.*; +import com.jme3.input.event.InputEvent; +import com.jme3.input.event.JoyButtonEvent; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Tests functionality of input behavior as: + * + * @author + */ +public class InputManagerTest { + + public MouseInput mi; + public KeyInput ki; + public InputManager im; + + @Before + public void setUp() { + mi = new DummyMouseInput(); + ki = new DummyKeyInput(); + + im = new InputManager(mi,ki,null,null); + } + + @Test(expected=IllegalArgumentException.class) + public void testCreateEmptyInputManager() { + im = new InputManager(null,null,null,null); + } +} diff --git a/jme3-core/src/test/java/com/jme3/input/JoyInputHelper.java b/jme3-core/src/test/java/com/jme3/input/JoyInputHelper.java new file mode 100644 index 0000000000..b176945ff5 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/JoyInputHelper.java @@ -0,0 +1,60 @@ +package com.jme3.input; + +public class JoyInputHelper implements JoyInput { + + private RawInputListener inputListener; + + @Override + public void initialize() { + // TODO Auto-generated method stub + + } + + @Override + public void update() { + // TODO Auto-generated method stub + + } + + @Override + public void destroy() { + // TODO Auto-generated method stub + + } + + @Override + public boolean isInitialized() { + // TODO Auto-generated method stub + return false; + } + + @Override + public void setInputListener(RawInputListener listener) { + this.inputListener = listener; + + } + + public RawInputListener getRawInputListener() + { + return this.inputListener; + } + + @Override + public long getInputTimeNanos() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public void setJoyRumble(int joyId, float amount) { + // TODO Auto-generated method stub + + } + + @Override + public Joystick[] loadJoysticks(InputManager inputManager) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/jme3-core/src/test/java/com/jme3/input/JoyInputTest.java b/jme3-core/src/test/java/com/jme3/input/JoyInputTest.java new file mode 100644 index 0000000000..25dc13bec8 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/JoyInputTest.java @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.input; + +import static org.junit.Assert.*; + +import com.jme3.input.controls.JoyAxisTrigger; +import com.jme3.input.controls.JoyButtonTrigger; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.input.dummy.*; +import com.jme3.input.event.*; +import com.jme3.input.test.util.ActionListenerTester; +import com.jme3.input.test.util.AnalogListenerTester; + +import org.junit.Before; +import org.junit.Test; + +/** + * Tests functionality of input behavior of the mouse and events + * + * @author Willem Vaandrager + */ + +public class JoyInputTest{ + + public MouseInput mi; + public KeyInput ki; + public TestJoyInput ji; + public InputManager im; + + public Joystick joystick; + public JoystickButton button; + public JoystickAxis axis; + + @Before + public void setUp() { + mi = new DummyMouseInput(); + mi.initialize(); + + ki = new DummyKeyInput(); + ki.initialize(); + + ji = new TestJoyInput(); + ji.initialize(); + + im = new InputManager(mi, ki, ji, null); + + //Test joystick + joystick = new TestJoystick(im, ji, 0, "test"); + button = new DefaultJoystickButton(im, joystick, 0, "button0", "0"); + axis = new DefaultJoystickAxis(im, joystick, 0, "x", "x", false, false, 0); + ji.setJoystick(joystick); + } + + @Test(expected=UnsupportedOperationException.class) + public void testJoyButtonEventNotEventsPermitted() { + im.onJoyButtonEvent(new JoyButtonEvent(button,true)); + } + + @Test(expected=UnsupportedOperationException.class) + public void testJoyAxisEventNotEventsPermitted() { + im.onJoyAxisEvent(new JoyAxisEvent(axis, 5)); + } + + @Test(expected=NullPointerException.class) + public void testOnJoyButtonEventNoButton() { + ji.addEvent(new JoyButtonEvent(null,true)); + assertEquals(false,ji.buttonQueue.get(0).isConsumed()); + im.update(1); + } + + @Test + public void testOnJoyButtonEventPressed() { + ji.addEvent(new JoyButtonEvent(button,true)); + + //test binding + im.addMapping("button0", new JoyButtonTrigger(0, 0)); + + ActionListenerTester acl = new ActionListenerTester(); + AnalogListenerTester anl = new AnalogListenerTester(); + + im.addListener(acl, "button0"); + im.addListener(anl, "button0"); + + im.update(1); + + assertEquals(true, acl.onActionCalled); + assertEquals(1, acl.nrsCalled); + + assertEquals(false, anl.onAnalogCalled); + } + + @Test + public void testOnJoyButtonEventNotPressed() { + ji.addEvent(new JoyButtonEvent(button,false)); + assertEquals(false,ji.buttonQueue.get(0).isConsumed()); + im.update(1); + assertEquals(true,ji.buttonQueue.get(0).isConsumed()); + } + + @Test + public void testOnJoyButtonEventPressReleaseBindingTiming() { + //test binding + im.addMapping("button0", new JoyButtonTrigger(0, 0)); + + ji.addEvent(new JoyButtonEvent(button,true)); + assertEquals(false,ji.buttonQueue.get(0).isConsumed()); + im.update(1); + assertEquals(true,ji.buttonQueue.get(0).isConsumed()); + + JoyButtonEvent je = new JoyButtonEvent(button, false); + je.setTime(1); + + ji.addEvent(je); + assertEquals(false,ji.buttonQueue.get(1).isConsumed()); + im.update(1); + assertEquals(true,ji.buttonQueue.get(1).isConsumed()); + } + + @Test + public void testOnJoyButtonEventPressTwiceBindingTiming() { + + TestKeyInput key = new TestKeyInput(); + key.initialize(); + + im = new InputManager(mi, key, ji, null); + + //test binding + im.addMapping("button0", new JoyButtonTrigger(0, 0)); + + ActionListenerTester acl = new ActionListenerTester(); + AnalogListenerTester anl = new AnalogListenerTester(); + + im.addListener(acl, "button0"); + im.addListener(anl, "button0"); + + ji.addEvent(new JoyButtonEvent(button,true)); + + im.update(1); + + assertEquals(true, acl.onActionCalled); + assertEquals(1, acl.nrsCalled); + + assertEquals(false, anl.onAnalogCalled); + + ji.addEvent(new JoyButtonEvent(button,true)); + + im.update(1); + + assertEquals(true, acl.onActionCalled); + assertEquals(2, acl.nrsCalled); + assertEquals(1, anl.nrsCalled); + assertEquals(true, anl.onAnalogCalled); + } + + @Test(expected=NullPointerException.class) + public void testOnJoyAxisEventNoAxis() { + ji.addEvent(new JoyAxisEvent(null, 0)); + assertEquals(false,ji.axisQueue.get(0).isConsumed()); + im.update(1); + } + + @Test + public void testOnJoyAxisEventInDeadzone() { + ji.addEvent(new JoyAxisEvent(axis, 0.03F)); + assertEquals(false,ji.axisQueue.get(0).isConsumed()); + im.update(1); + assertEquals(true,ji.axisQueue.get(0).isConsumed()); + } + + @Test + public void testOnJoyAxisEventMultiple() { + ji.addEvent(new JoyAxisEvent(axis, 0.1F)); + assertEquals(false,ji.axisQueue.get(0).isConsumed()); + im.update(1); + assertEquals(true,ji.axisQueue.get(0).isConsumed()); + + axis = new DefaultJoystickAxis(im, joystick, 1, "y", "y", true, true, 0); + + ji.addEvent(new JoyAxisEvent(axis,-0.1F)); + assertEquals(false,ji.axisQueue.get(1).isConsumed()); + im.update(1); + assertEquals(true,ji.axisQueue.get(1).isConsumed()); + ji.addEvent(new JoyAxisEvent(axis, 0.04F)); + assertEquals(false,ji.axisQueue.get(2).isConsumed()); + im.update(1); + assertEquals(true,ji.axisQueue.get(2).isConsumed()); + ji.addEvent(new JoyAxisEvent(axis, 0.03F)); + assertEquals(false,ji.axisQueue.get(3).isConsumed()); + im.update(1); + assertEquals(true,ji.axisQueue.get(3).isConsumed()); + } + + @Test + public void testOnJoyAxisEventOutsideDeadzone() { + ji.addEvent(new JoyAxisEvent(axis, 0.1F)); + assertEquals(false,ji.axisQueue.get(0).isConsumed()); + im.update(1); + assertEquals(true,ji.axisQueue.get(0).isConsumed()); + } + + @Test + public void testOnJoyAxisEventOutsideDeadzoneNegative() { + ji.addEvent(new JoyAxisEvent(axis, -0.1F)); + assertEquals(false,ji.axisQueue.get(0).isConsumed()); + im.update(1); + assertEquals(true,ji.axisQueue.get(0).isConsumed()); + } + + @Test + public void testOnJoyAxisEventInDeadzoneBinding() { + //test binding + im.addMapping("x", new JoyAxisTrigger(0, 0, false)); + + ji.addEvent(new JoyAxisEvent(axis, 0.03F)); + assertEquals(false,ji.axisQueue.get(0).isConsumed()); + im.update(1); + assertEquals(true,ji.axisQueue.get(0).isConsumed()); + } + + @Test + public void testOnJoyAxisEventOutsideDeadzoneBinding() { + //test binding + im.addMapping("x", new JoyAxisTrigger(0, 0, false)); + + ji.addEvent(new JoyAxisEvent(axis, 0.1F)); + + ActionListenerTester acl = new ActionListenerTester(); + AnalogListenerTester anl = new AnalogListenerTester(); + + im.addListener(acl, "x"); + im.addListener(anl, "x"); + + im.update(1); + + assertEquals(true, acl.onActionCalled); + assertEquals(1, acl.nrsCalled); + assertEquals(2, anl.nrsCalled); + + assertEquals(true, anl.onAnalogCalled); + } + + @Test + public void testOnJoyAxisEventOutsideDeadzoneNegativeBinding() { + //test binding + im.addMapping("x", new JoyAxisTrigger(0, 0, false)); + + ji.addEvent(new JoyAxisEvent(axis, -0.1F)); + assertEquals(false,ji.axisQueue.get(0).isConsumed()); + im.update(1); + assertEquals(true,ji.axisQueue.get(0).isConsumed()); + } + + + @Test + public void testSetAxisDeadzone(){ + assertEquals(0.05f, im.getAxisDeadZone(),0.001); + im.setAxisDeadZone(0.1f); + assertEquals(0.1f, im.getAxisDeadZone(),0.001); + } + + @Test + public void testgetAxisDeadzone(){ + assertEquals(0.05f, im.getAxisDeadZone(),0.001); + } + + @Test + public void testGetJoysticks(){ + assertEquals(joystick.getName(),im.getJoysticks()[0].getName()); + assertEquals(joystick.getJoyId(),im.getJoysticks()[0].getJoyId()); + assertEquals(joystick.toString(),im.getJoysticks()[0].toString()); + } +} diff --git a/jme3-core/src/test/java/com/jme3/input/KeysInputTest.java b/jme3-core/src/test/java/com/jme3/input/KeysInputTest.java new file mode 100644 index 0000000000..4db858aff8 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/KeysInputTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.input; + +import static org.junit.Assert.*; + +import com.jme3.input.controls.*; +import com.jme3.input.dummy.*; +import com.jme3.input.event.*; + +import org.junit.Before; +import org.junit.Test; + +/** + * Tests functionality of input behavior of the mouse and events + * + * @author Willem Vaandrager + */ + +public class KeysInputTest{ + + public MouseInput mi; + public TestKeyInput ki; + public InputManager im; + + @Before + public void setUp() { + mi = new DummyMouseInput(); + mi.initialize(); + + ki = new TestKeyInput(); + ki.initialize(); + + im = new InputManager(mi, ki, null, null); + + //test binding + im.addMapping("1", new KeyTrigger(1)); + } + + @Test(expected=UnsupportedOperationException.class) + public void testKeyInputEventNotEventsPermitted() { + im.onKeyEvent(new KeyInputEvent(1, '1', true, false)); + } + + @Test + public void testOnKeyInputEventNoBinding() { + ki.addEvent(new KeyInputEvent(2, '2', true, false)); + assertEquals(false,ki.eventQueue.get(0).isConsumed()); + im.update(1); + assertEquals(true,ki.eventQueue.get(0).isConsumed()); + } + + @Test + public void testOnKeyInputEventBinding() { + ki.addEvent(new KeyInputEvent(1, '1', true, false)); + assertEquals(false,ki.eventQueue.get(0).isConsumed()); + im.update(1); + assertEquals(true,ki.eventQueue.get(0).isConsumed()); + } + + @Test + public void testOnKeyInputEventNotPressed() { + ki.addEvent(new KeyInputEvent(1, '1', false, false)); + assertEquals(false,ki.eventQueue.get(0).isConsumed()); + im.update(1); + assertEquals(true,ki.eventQueue.get(0).isConsumed()); + } + + @Test + public void testOnKeyInputEventPressRelease() { + ki.addEvent(new KeyInputEvent(1, '1', true, false)); + assertEquals(false,ki.eventQueue.get(0).isConsumed()); + im.update(1); + assertEquals(true,ki.eventQueue.get(0).isConsumed()); + + ki.addEvent(new KeyInputEvent(1, '1', false, false)); + assertEquals(false,ki.eventQueue.get(1).isConsumed()); + im.update(1); + assertEquals(true,ki.eventQueue.get(1).isConsumed()); + + ki.addEvent(new KeyInputEvent(1, '1', true, false)); + assertEquals(false,ki.eventQueue.get(2).isConsumed()); + im.update(1); + assertEquals(true,ki.eventQueue.get(2).isConsumed()); + + ki.addEvent(new KeyInputEvent(1, '1', false, false)); + assertEquals(false,ki.eventQueue.get(3).isConsumed()); + im.update(1); + assertEquals(true,ki.eventQueue.get(3).isConsumed()); + } + + @Test + public void testOnKeyInputEventRepeating() { + ki.addEvent(new KeyInputEvent(1, '1', true, true)); + assertEquals(false,ki.eventQueue.get(0).isConsumed()); + im.update(1); + assertEquals(true,ki.eventQueue.get(0).isConsumed()); + } +} diff --git a/jme3-core/src/test/java/com/jme3/input/MouseInputTest.java b/jme3-core/src/test/java/com/jme3/input/MouseInputTest.java new file mode 100644 index 0000000000..77e48f99d6 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/MouseInputTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.input; +import com.jme3.cursors.plugins.JmeCursor; +import com.jme3.input.controls.MouseButtonTrigger; +import com.jme3.input.dummy.*; +import com.jme3.input.event.*; +import com.jme3.input.test.util.ActionListenerTester; +import com.jme3.input.test.util.AnalogListenerTester; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Tests functionality of input behavior of the mouse and events + * + * @author Willem Vaandrager + */ + +public class MouseInputTest{ + + public TestMouseInput mi; + public KeyInput ki; + public TouchInput ti; + public JoyInput ji; + public InputManager im; + + @Before + public void setUp() { + ki = new DummyKeyInput(); + ki.initialize(); + + mi = new TestMouseInput(); + mi.initialize(); + + + im = new InputManager(mi, ki, null, null); + im.addMapping("MouseL", new MouseButtonTrigger(MouseInput.BUTTON_LEFT)); + + } + + @Test(expected=UnsupportedOperationException.class) + public void testOnMouseButtonEventNotEventsPermitted() { + im.onMouseButtonEvent(new MouseButtonEvent(0, true, 5, 10)); + } + + @Test(expected=UnsupportedOperationException.class) + public void testOnMouseMotionEventNotEventsPermitted() { + im.onMouseMotionEvent(new MouseMotionEvent(0, 0, 0, 0, 0, 0)); + } + + @Test + public void testOnLeftMouseButtonEvent() { + mi.addEvent(new MouseButtonEvent(0, true, 5, 10)); + + ActionListenerTester acl = new ActionListenerTester(); + AnalogListenerTester anl = new AnalogListenerTester(); + + im.addListener(acl, "MouseL"); + im.addListener(anl, "MouseL"); + + im.update(1); + + assertEquals(true, acl.onActionCalled); + assertEquals(1, acl.nrsCalled); + + assertEquals(false, anl.onAnalogCalled); + + assertEquals(5, im.getCursorPosition().getX(),0.001); + assertEquals(10, im.getCursorPosition().getY(),0.001); + } + + @Test + public void testOnRightMouseButtonEvent() { + + mi.addEvent(new MouseButtonEvent(1, true, 10, 5)); + + im.update(1); + + assertEquals(10, im.getCursorPosition().getX(),0.001); + assertEquals(5, im.getCursorPosition().getY(),0.001); + } + + @Test + public void testMouseMotion() { + assertEquals(0, im.getCursorPosition().getX(),0.001); + assertEquals(0, im.getCursorPosition().getY(),0.001); + + mi.addEvent(new MouseMotionEvent(5,10,10,10,2,2)); + + im.update(1); + + assertEquals(5, im.getCursorPosition().getX(),0.001); + assertEquals(10, im.getCursorPosition().getY(),0.001); + } + + @Test + public void testCursor(){ + assertEquals(true,im.isCursorVisible()); + + im.setMouseCursor(new JmeCursor()); + assertEquals(true,im.isCursorVisible()); + + im.setCursorVisible(false); + assertEquals(false,im.isCursorVisible()); + } +} diff --git a/jme3-core/src/test/java/com/jme3/input/TestJoyInput.java b/jme3-core/src/test/java/com/jme3/input/TestJoyInput.java new file mode 100644 index 0000000000..78d85dc246 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/TestJoyInput.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.input; + +import java.util.ArrayList; + +import com.jme3.input.event.JoyAxisEvent; +import com.jme3.input.event.JoyButtonEvent; + +/** + * TestJoyInput as an implementation of JoyInput to simulate joystick for tests. + * + * @author Willem Vaandrager. + */ +public class TestJoyInput implements JoyInput { + + protected boolean inited = false; + + private Joystick joystick; + + public ArrayList buttonQueue = new ArrayList(); + public ArrayList axisQueue = new ArrayList(); + + private RawInputListener listener; + + public void initialize() { + if (inited) + throw new IllegalStateException("Input already initialized."); + + inited = true; + } + + public void addEvent(JoyButtonEvent evt){ + buttonQueue.add(evt); + } + + public void addEvent(JoyAxisEvent evt){ + axisQueue.add(evt); + } + + public void setInputListener(RawInputListener listener) { + this.listener = listener; + } + + public RawInputListener getInputListener() { + return listener; + } + + public void update() { + if (!inited) + throw new IllegalStateException("Input not initialized."); + + for (JoyButtonEvent evt : buttonQueue) { + listener.onJoyButtonEvent(evt); + } + for (JoyAxisEvent evt : axisQueue) { + listener.onJoyAxisEvent(evt); + } + } + + public void destroy() { + if (!inited) + throw new IllegalStateException("Input not initialized."); + + inited = false; + } + + public boolean isInitialized() { + return inited; + } + + public long getInputTimeNanos() { + return System.currentTimeMillis() * 1000000; + } + + public void setJoystick(Joystick joystick){ + this.joystick = joystick; + } + + public Joystick getJoystick(){ + return joystick; + } + + @Override + public void setJoyRumble(int joyId, float amount) { + // TODO Auto-generated method stub + } + + @Override + public Joystick[] loadJoysticks(InputManager inputManager) { + if(joystick == null){ + joystick = new TestJoystick(inputManager, this, 0, "test"); + } + return new Joystick[]{joystick}; + } +} + diff --git a/jme3-core/src/test/java/com/jme3/input/TestJoystick.java b/jme3-core/src/test/java/com/jme3/input/TestJoystick.java new file mode 100644 index 0000000000..a8afa01943 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/TestJoystick.java @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.input; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.jme3.input.controls.JoyAxisTrigger; +import com.jme3.input.controls.JoyButtonTrigger; + +/** + * TestJoystick as an implementation of Joystick to simulate joystick for tests. + * + * @author Willem Vaandrager. + */ + +public class TestJoystick implements Joystick { + + private InputManager inputManager; + private JoyInput joyInput; + private int joyId; + private String name; + + private List axes = new ArrayList(); + private List buttons = new ArrayList(); + + /** + * Creates a new joystick instance. Only used internally. + */ + public TestJoystick(InputManager inputManager, JoyInput joyInput, + int joyId, String name) { + this.inputManager = inputManager; + this.joyInput = joyInput; + this.joyId = joyId; + this.name = name; + } + + public InputManager getInputManager() { + return inputManager; + } + + public JoyInput getJoyInput() { + return joyInput; + } + + public void addAxis( JoystickAxis axis ) { + axes.add(axis); + } + + public void addButton( JoystickButton button ) { + buttons.add(button); + } + + /** + * Rumbles the joystick for the given amount/magnitude. + * + * @param amount The amount to rumble. Should be between 0 and 1. + */ + @Override + public void rumble(float amount){ + joyInput.setJoyRumble(joyId, amount); + } + + /** + * Assign the mapping name to receive events from the given button index + * on the joystick. + * + * @param mappingName The mapping to receive joystick button events. + * @param buttonId The button index. + * + * @see Joystick#getButtonCount() + * @deprecated Use JoystickButton.assignButton() instead. + */ + @Override + public void assignButton(String mappingName, int buttonId){ + if (buttonId < 0 || buttonId >= getButtonCount()) + throw new IllegalArgumentException(); + + inputManager.addMapping(mappingName, new JoyButtonTrigger(joyId, buttonId)); + } + + /** + * Assign the mappings to receive events from the given joystick axis. + * + * @param positiveMapping The mapping to receive events when the axis is negative + * @param negativeMapping The mapping to receive events when the axis is positive + * @param axisId The axis index. + * + * @see Joystick#getAxisCount() + * @deprecated Use JoystickAxis.assignAxis() instead. + */ + @Override + public void assignAxis(String positiveMapping, String negativeMapping, int axisId){ + + // For backwards compatibility + if( axisId == JoyInput.AXIS_POV_X ) { + axisId = getPovXAxis().getAxisId(); + } else if( axisId == JoyInput.AXIS_POV_Y ) { + axisId = getPovYAxis().getAxisId(); + } + + inputManager.addMapping(positiveMapping, new JoyAxisTrigger(joyId, axisId, false)); + inputManager.addMapping(negativeMapping, new JoyAxisTrigger(joyId, axisId, true)); + } + + @Override + public JoystickAxis getAxis(String logicalId) { + for( JoystickAxis axis : axes ) { + if( axis.getLogicalId().equals(logicalId) ) + return axis; + } + return null; + } + + /** + * Returns a read-only list of all joystick axes for this Joystick. + */ + @Override + public List getAxes() { + return Collections.unmodifiableList(axes); + } + + /** + * Returns the number of axes on this joystick. + * + * @return the number of axes on this joystick. + */ + @Override + public int getAxisCount() { + return axes.size(); + } + + @Override + public JoystickButton getButton(String logicalId) { + for( JoystickButton b : buttons ) { + if( b.getLogicalId().equals(logicalId) ) + return b; + } + return null; + } + + /** + * Returns a read-only list of all joystick buttons for this Joystick. + */ + @Override + public List getButtons() { + return Collections.unmodifiableList(buttons); + } + + /** + * Returns the number of buttons on this joystick. + * + * @return the number of buttons on this joystick. + */ + @Override + public int getButtonCount() { + return buttons.size(); + } + + /** + * Returns the name of this joystick. + * + * @return the name of this joystick. + */ + @Override + public String getName() { + return name; + } + + /** + * Returns the joyId of this joystick. + * + * @return the joyId of this joystick. + */ + @Override + public int getJoyId() { + return joyId; + } + + /** + * Gets the index number for the X axis on the joystick. + * + *

E.g. for most gamepads, the left control stick X axis will be returned. + * + * @return The axis index for the X axis for this joystick. + * + * @see Joystick#assignAxis(java.lang.String, java.lang.String, int) + */ + @Override + public int getXAxisIndex(){ + return getXAxis().getAxisId(); + } + + /** + * Gets the index number for the Y axis on the joystick. + * + *

E.g. for most gamepads, the left control stick Y axis will be returned. + * + * @return The axis index for the Y axis for this joystick. + * + * @see Joystick#assignAxis(java.lang.String, java.lang.String, int) + */ + @Override + public int getYAxisIndex(){ + return getYAxis().getAxisId(); + } + + @Override + public String toString(){ + return "Joystick[name=" + name + ", id=" + joyId + ", buttons=" + getButtonCount() + + ", axes=" + getAxisCount() + "]"; + } + + @Override + public JoystickAxis getXAxis() { + // TODO Auto-generated method stub + return null; + } + + @Override + public JoystickAxis getYAxis() { + // TODO Auto-generated method stub + return null; + } + + @Override + public JoystickAxis getPovXAxis() { + // TODO Auto-generated method stub + return null; + } + + @Override + public JoystickAxis getPovYAxis() { + // TODO Auto-generated method stub + return null; + } +} + diff --git a/jme3-core/src/test/java/com/jme3/input/TestKeyInput.java b/jme3-core/src/test/java/com/jme3/input/TestKeyInput.java new file mode 100644 index 0000000000..7928216a3c --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/TestKeyInput.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.input; + +import java.util.ArrayList; + +import com.jme3.input.event.KeyInputEvent; + +/** + * TestKeyInput as an implementation of KeyInput to simulate keys for tests. + * + * @author Willem Vaandrager. + */ +public class TestKeyInput implements KeyInput { + + protected boolean inited = false; + + public ArrayList eventQueue = new ArrayList(); + + private RawInputListener listener; + + + public void initialize() { + if (inited) + throw new IllegalStateException("Input already initialized."); + + inited = true; + } + + public void addEvent(KeyInputEvent evt){ + eventQueue.add(evt); + } + + public void setInputListener(RawInputListener listener) { + this.listener = listener; + } + + public RawInputListener getInputListener() { + return listener; + } + + public void update() { + if (!inited) + throw new IllegalStateException("Input not initialized."); + + for (KeyInputEvent evt : eventQueue) { + listener.onKeyEvent(evt); + } + } + + public void destroy() { + if (!inited) + throw new IllegalStateException("Input not initialized."); + + inited = false; + } + + public boolean isInitialized() { + return inited; + } + + public long getInputTimeNanos() { + return System.currentTimeMillis() * 1000000; + } +} + diff --git a/jme3-core/src/test/java/com/jme3/input/TestMouseInput.java b/jme3-core/src/test/java/com/jme3/input/TestMouseInput.java new file mode 100644 index 0000000000..82ad64387d --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/TestMouseInput.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.input; + +import java.util.ArrayList; + +import com.jme3.cursors.plugins.JmeCursor; +import com.jme3.input.event.MouseButtonEvent; +import com.jme3.input.event.MouseMotionEvent; + +/** + * TestMouseInput as an implementation of MouseInput to simulate mouse for tests. + * + * @author Willem Vaandrager. + */ +public class TestMouseInput implements MouseInput { + + protected boolean inited = false; + + public ArrayList eventQueue = new ArrayList(); + public ArrayList motionQueue = new ArrayList(); + + private RawInputListener listener; + + public void initialize() { + if (inited) + throw new IllegalStateException("Input already initialized."); + + inited = true; + } + + public void setCursorVisible(boolean visible) { + if (!inited) + throw new IllegalStateException("Input not initialized."); + } + + public int getButtonCount() { + return 3; + } + + public void addEvent(MouseButtonEvent evt){ + eventQueue.add(evt); + } + + public void addEvent(MouseMotionEvent evt){ + motionQueue.add(evt); + } + + public void setInputListener(RawInputListener listener) { + this.listener = listener; + } + + public RawInputListener getInputListener() { + return listener; + } + + public void update() { + if (!inited) + throw new IllegalStateException("Input not initialized."); + + for (MouseButtonEvent evt : eventQueue) { + listener.onMouseButtonEvent(evt); + + } + for (MouseMotionEvent evt : motionQueue) { + listener.onMouseMotionEvent(evt); + } + } + + public void setNativeCursor(JmeCursor cursor) { + } + + public void destroy() { + if (!inited) + throw new IllegalStateException("Input not initialized."); + + inited = false; + } + + public boolean isInitialized() { + return inited; + } + + public long getInputTimeNanos() { + return System.currentTimeMillis() * 1000000; + } +} + diff --git a/jme3-core/src/test/java/com/jme3/input/TestTouchInput.java b/jme3-core/src/test/java/com/jme3/input/TestTouchInput.java new file mode 100644 index 0000000000..334402af68 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/TestTouchInput.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2009-2012 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.input; + +import java.util.ArrayList; + +import com.jme3.input.event.TouchEvent; + +/** + * TestTouchInput as an implementation of TouchInput to simulate events of touch device for tests. + * + * @author Willem Vaandrager. + */ +public class TestTouchInput implements TouchInput { + + protected boolean inited = false; + + public ArrayList eventQueue = new ArrayList(); + + private RawInputListener listener; + + private boolean isSimulateMouse = false; + private boolean isSimulateKeyboard = false; + + public void initialize() { + if (inited) + throw new IllegalStateException("Input already initialized."); + + inited = true; + } + + public void addEvent(TouchEvent evt){ + eventQueue.add(evt); + } + + public void setInputListener(RawInputListener listener) { + this.listener = listener; + } + + public RawInputListener getInputListener() { + return listener; + } + + public void update() { + if (!inited) + throw new IllegalStateException("Input not initialized."); + + for (TouchEvent evt : eventQueue) { + listener.onTouchEvent(evt); + } + } + + public void destroy() { + if (!inited) + throw new IllegalStateException("Input not initialized."); + + inited = false; + } + + public boolean isInitialized() { + return inited; + } + + public long getInputTimeNanos() { + return System.currentTimeMillis() * 1000000; + } + + @Override + public void setSimulateMouse(boolean simulate) { + isSimulateMouse = simulate; + } + + @Override + public boolean isSimulateMouse() { + return isSimulateMouse; + } + + @Override + public void setSimulateKeyboard(boolean simulate) { + isSimulateKeyboard = simulate; + + } + + @Override + public boolean isSimulateKeyboard() { + return isSimulateKeyboard; + } + + @Override + public void setOmitHistoricEvents(boolean dontSendHistory) { + // TODO Auto-generated method stub + + } +} + diff --git a/jme3-core/src/test/java/com/jme3/input/TouchInputHelper.java b/jme3-core/src/test/java/com/jme3/input/TouchInputHelper.java new file mode 100644 index 0000000000..b33eb368bd --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/TouchInputHelper.java @@ -0,0 +1,78 @@ +package com.jme3.input; + +public class TouchInputHelper implements TouchInput { + + private RawInputListener inputListener; + + @Override + public void initialize() { + // TODO Auto-generated method stub + + } + + @Override + public void update() { + // TODO Auto-generated method stub + + } + + @Override + public void destroy() { + // TODO Auto-generated method stub + + } + + @Override + public boolean isInitialized() { + // TODO Auto-generated method stub + return false; + } + + @Override + public void setInputListener(RawInputListener listener) { + this.inputListener = listener; + + } + + public RawInputListener getRawInputListener() + { + return this.inputListener; + } + + @Override + public long getInputTimeNanos() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public void setSimulateMouse(boolean simulate) { + // TODO Auto-generated method stub + + } + + @Override + public boolean isSimulateMouse() { + // TODO Auto-generated method stub + return false; + } + + @Override + public void setSimulateKeyboard(boolean simulate) { + // TODO Auto-generated method stub + + } + + @Override + public boolean isSimulateKeyboard() { + // TODO Auto-generated method stub + return false; + } + + @Override + public void setOmitHistoricEvents(boolean dontSendHistory) { + // TODO Auto-generated method stub + + } + +} diff --git a/jme3-core/src/test/java/com/jme3/input/TouchInputTest.java b/jme3-core/src/test/java/com/jme3/input/TouchInputTest.java new file mode 100644 index 0000000000..3ca9644fe9 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/TouchInputTest.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2009-2015 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.input; + +import static org.junit.Assert.*; + +import com.jme3.input.controls.TouchTrigger; +import com.jme3.input.dummy.*; +import com.jme3.input.event.*; +import com.jme3.input.event.TouchEvent.Type; +import com.jme3.input.test.util.ActionListenerTester; +import com.jme3.input.test.util.AnalogListenerTester; +import com.jme3.input.test.util.TouchListenerTester; + +import org.junit.Before; +import org.junit.Test; + +/** + * Tests functionality of input behavior of the mouse and events + * + * @author Willem Vaandrager + */ + +public class TouchInputTest{ + + public MouseInput mi; + public KeyInput ki; + public TestTouchInput ti; + public InputManager im; + + @Before + public void setUp() { + mi = new DummyMouseInput(); + mi.initialize(); + + ki = new DummyKeyInput(); + ki.initialize(); + + ti = new TestTouchInput(); + ti.initialize(); + + im = new InputManager(mi, ki, null, ti); + } + + @Test(expected=UnsupportedOperationException.class) + public void testTouchEventNotEventsPermitted() { + im.onTouchEvent(new TouchEvent()); + } + + @Test + public void testOnTouchEvent() { + ti.addEvent(new TouchEvent(Type.DOWN,5,10,5,10)); + assertEquals(false,ti.eventQueue.get(0).isConsumed()); + im.update(1); + assertEquals(true,ti.eventQueue.get(0).isConsumed()); + + assertEquals(5, im.getCursorPosition().getX(),0.001); + assertEquals(10, im.getCursorPosition().getY(),0.001); + } + + @Test + public void testOnTouchEventBinding() { + //test binding + im.addMapping("3", new TouchTrigger(TouchInput.KEYCODE_HOME)); + + TouchEvent te = new TouchEvent(Type.DOWN,5,10,5,10); + te.setKeyCode(3); + + ti.addEvent(te); + + ActionListenerTester acl = new ActionListenerTester(); + TouchListenerTester tcl = new TouchListenerTester(); + + im.addListener(acl, "3"); + im.addListener(tcl, "3"); + + im.update(1); + + assertEquals(false, acl.onActionCalled); + assertEquals(0, acl.nrsCalled); + assertEquals(1, tcl.nrsCalled); + + assertEquals(true, tcl.onTouchCalled); + + assertEquals(5, im.getCursorPosition().getX(),0.001); + assertEquals(10, im.getCursorPosition().getY(),0.001); + } + + @SuppressWarnings("deprecation") + @Test + public void testSimulateMouse(){ + assertEquals(false, im.isSimulateMouse()); + + //deprecated method + assertEquals(false, im.getSimulateMouse()); + + im.setSimulateMouse(true); + assertEquals(true, im.isSimulateMouse()); + + im.setSimulateMouse(false); + assertEquals(false, im.isSimulateMouse()); + + } + + @Test + public void testSimulateKeyboard(){ + assertEquals(false, im.isSimulateKeyboard()); + + im.setSimulateKeyboard(true); + assertEquals(true, im.isSimulateKeyboard()); + + im.setSimulateKeyboard(false); + assertEquals(false, im.isSimulateKeyboard()); + } + + @SuppressWarnings("deprecation") + @Test + public void testSimulateMouseNoTouchDevice(){ + im = new InputManager(mi, ki, null, null); + + im.setSimulateMouse(true); + assertEquals(false,im.isSimulateMouse()); + + //deprecated method + assertEquals(false,im.getSimulateMouse()); + } + + @Test + public void testSimulateKeyboardNoTouchDevice(){ + im = new InputManager(mi, ki, null, null); + + im.setSimulateKeyboard(true); + assertEquals(false,im.isSimulateKeyboard()); + } +} diff --git a/jme3-core/src/test/java/com/jme3/input/test/util/ActionListenerTester.java b/jme3-core/src/test/java/com/jme3/input/test/util/ActionListenerTester.java new file mode 100644 index 0000000000..3232698232 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/test/util/ActionListenerTester.java @@ -0,0 +1,14 @@ +package com.jme3.input.test.util; + +public class ActionListenerTester implements com.jme3.input.controls.ActionListener { + + public boolean onActionCalled = false; + public int nrsCalled = 0; + + @Override + public void onAction(String name, boolean isPressed, float tpf) { + nrsCalled++; + onActionCalled = true; + } + +} diff --git a/jme3-core/src/test/java/com/jme3/input/test/util/AnalogListenerTester.java b/jme3-core/src/test/java/com/jme3/input/test/util/AnalogListenerTester.java new file mode 100644 index 0000000000..7b8d7a7171 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/test/util/AnalogListenerTester.java @@ -0,0 +1,16 @@ +package com.jme3.input.test.util; + +import com.jme3.input.controls.AnalogListener; + +public class AnalogListenerTester implements AnalogListener { + + public boolean onAnalogCalled = false; + public int nrsCalled = 0; + + @Override + public void onAnalog(String name, float value, float tpf) { + nrsCalled++; + onAnalogCalled = true; + } + +} diff --git a/jme3-core/src/test/java/com/jme3/input/test/util/TouchListenerTester.java b/jme3-core/src/test/java/com/jme3/input/test/util/TouchListenerTester.java new file mode 100644 index 0000000000..66c2db3165 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/input/test/util/TouchListenerTester.java @@ -0,0 +1,17 @@ +package com.jme3.input.test.util; + +import com.jme3.input.controls.TouchListener; +import com.jme3.input.event.TouchEvent; + +public class TouchListenerTester implements TouchListener { + + public boolean onTouchCalled = false; + public int nrsCalled = 0; + + @Override + public void onTouch(String name, TouchEvent event, float tpf) { + nrsCalled++; + onTouchCalled = true; + } + +} diff --git a/jme3-core/src/test/java/com/jme3/test/util/TestLogHandler.java b/jme3-core/src/test/java/com/jme3/test/util/TestLogHandler.java new file mode 100644 index 0000000000..d2fd55cb09 --- /dev/null +++ b/jme3-core/src/test/java/com/jme3/test/util/TestLogHandler.java @@ -0,0 +1,28 @@ +package com.jme3.test.util; + +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; + +public class TestLogHandler extends Handler +{ + Level lastLevel = Level.FINEST; + int loggedMessages = 0; + + public Level checkLevel() { + return lastLevel; + } + + public void publish(LogRecord record) { + lastLevel = record.getLevel(); + loggedMessages++; + } + + public int getNrOfLoggedMessages() + { + return loggedMessages; + } + + public void close(){} + public void flush(){} +}