|
|
|
@ -31,6 +31,7 @@ |
|
|
|
|
*/ |
|
|
|
|
package com.jme3.input; |
|
|
|
|
|
|
|
|
|
import com.jme3.app.Application; |
|
|
|
|
import com.jme3.input.controls.ActionListener; |
|
|
|
|
import com.jme3.input.controls.AnalogListener; |
|
|
|
|
import com.jme3.input.controls.InputListener; |
|
|
|
@ -62,10 +63,38 @@ import java.util.logging.Logger; |
|
|
|
|
* The <code>InputManager</code> 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 a dispatcher is included with every Application instance for use |
|
|
|
|
* <p> |
|
|
|
|
* By default an <code>InputManager</code> 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. |
|
|
|
|
* <p> |
|
|
|
|
* 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. |
|
|
|
|
* <p> |
|
|
|
|
* 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. |
|
|
|
|
* <p> |
|
|
|
|
* <code>onAction</code> events are raised when the specific input |
|
|
|
|
* activates or deactivates. For a digital input such as key press, the <code>onAction()</code> |
|
|
|
|
* event will be raised with the <code>isPressed</code> argument equal to true, |
|
|
|
|
* when the key is released, <code>onAction</code> is called again but this time |
|
|
|
|
* with the <code>isPressed</code> argument set to false. |
|
|
|
|
* For analog inputs, the <code>onAction</code> 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}. |
|
|
|
|
* <p> |
|
|
|
|
* <code>onAnalog</code> events are raised every frame while the input is activated. |
|
|
|
|
* For digital inputs, every frame that the input is active will cause the |
|
|
|
|
* <code>onAnalog</code> method to be called, the argument <code>value</code> |
|
|
|
|
* argument will equal to the frame's time per frame (TPF) value but only |
|
|
|
|
* for digital inputs. For analog inputs however, the <code>value</code> argument |
|
|
|
|
* will equal the actual analog value. |
|
|
|
|
*/ |
|
|
|
|
public class InputManager implements RawInputListener { |
|
|
|
|
|
|
|
|
@ -106,6 +135,8 @@ public class InputManager implements RawInputListener { |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Initializes the InputManager. |
|
|
|
|
* |
|
|
|
|
* <p>This should only be called internally in {@link Application}. |
|
|
|
|
* |
|
|
|
|
* @param mouseInput |
|
|
|
|
* @param keyInput |
|
|
|
@ -267,9 +298,15 @@ public class InputManager implements RawInputListener { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Callback from RawInputListener. Do not use. |
|
|
|
|
*/ |
|
|
|
|
public void beginInput() { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Callback from RawInputListener. Do not use. |
|
|
|
|
*/ |
|
|
|
|
public void endInput() { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -309,6 +346,9 @@ public class InputManager implements RawInputListener { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Callback from RawInputListener. Do not use. |
|
|
|
|
*/ |
|
|
|
|
public void onJoyAxisEvent(JoyAxisEvent evt) { |
|
|
|
|
if (!eventsPermitted) { |
|
|
|
|
throw new UnsupportedOperationException("JoyInput has raised an event at an illegal time."); |
|
|
|
@ -327,6 +367,9 @@ public class InputManager implements RawInputListener { |
|
|
|
|
invokeTimedActions(hash, evt.getTime(), evt.isPressed()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Callback from RawInputListener. Do not use. |
|
|
|
|
*/ |
|
|
|
|
public void onJoyButtonEvent(JoyButtonEvent evt) { |
|
|
|
|
if (!eventsPermitted) { |
|
|
|
|
throw new UnsupportedOperationException("JoyInput has raised an event at an illegal time."); |
|
|
|
@ -354,6 +397,9 @@ public class InputManager implements RawInputListener { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Callback from RawInputListener. Do not use. |
|
|
|
|
*/ |
|
|
|
|
public void onMouseMotionEvent(MouseMotionEvent evt) { |
|
|
|
|
if (!eventsPermitted) { |
|
|
|
|
throw new UnsupportedOperationException("MouseInput has raised an event at an illegal time."); |
|
|
|
@ -364,15 +410,14 @@ public class InputManager implements RawInputListener { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void onMouseButtonEventQueued(MouseButtonEvent evt) { |
|
|
|
|
// for (int i = 0; i < rawListeners.size(); i++){
|
|
|
|
|
// rawListeners.get(i).onMouseButtonEvent(evt);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
int hash = MouseButtonTrigger.mouseButtonHash(evt.getButtonIndex()); |
|
|
|
|
invokeActions(hash, evt.isPressed()); |
|
|
|
|
invokeTimedActions(hash, evt.getTime(), evt.isPressed()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Callback from RawInputListener. Do not use. |
|
|
|
|
*/ |
|
|
|
|
public void onMouseButtonEvent(MouseButtonEvent evt) { |
|
|
|
|
if (!eventsPermitted) { |
|
|
|
|
throw new UnsupportedOperationException("MouseInput has raised an event at an illegal time."); |
|
|
|
@ -382,18 +427,18 @@ public class InputManager implements RawInputListener { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void onKeyEventQueued(KeyInputEvent evt) { |
|
|
|
|
// for (int i = 0; i < rawListeners.size(); i++){
|
|
|
|
|
// rawListeners.get(i).onKeyEvent(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. |
|
|
|
|
*/ |
|
|
|
|
public void onKeyEvent(KeyInputEvent evt) { |
|
|
|
|
if (!eventsPermitted) { |
|
|
|
|
throw new UnsupportedOperationException("KeyInput has raised an event at an illegal time."); |
|
|
|
@ -401,11 +446,69 @@ public class InputManager implements RawInputListener { |
|
|
|
|
|
|
|
|
|
inputQueue.add(evt); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void onTouchEventQueued(TouchEvent evt) { |
|
|
|
|
for (Mapping mapping : mappings.values()) { |
|
|
|
|
for (InputListener listener : mapping.listeners) { |
|
|
|
|
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."); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
inputQueue.add(evt); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Set the deadzone for joystick axes. |
|
|
|
|
* |
|
|
|
|
* <p>{@link ActionListener#onAction(java.lang.String, boolean, float) } |
|
|
|
|
* events will only be raised if the joystick axis value is greater than |
|
|
|
|
* the <code>deadZone</code>. |
|
|
|
|
* |
|
|
|
|
* @param deadZone the deadzone for joystick axes. |
|
|
|
|
*/ |
|
|
|
|
public void setAxisDeadZone(float deadZone) { |
|
|
|
|
this.axisDeadZone = deadZone; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns the deadzone for joystick axes. |
|
|
|
|
* |
|
|
|
|
* @return the deadzone for joystick axes. |
|
|
|
|
*/ |
|
|
|
|
public float getAxisDeadZone() { |
|
|
|
|
return axisDeadZone; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Adds a new listener to receive events on the given mappings. |
|
|
|
|
* |
|
|
|
|
* <p>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 <code>listener</code> 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); |
|
|
|
@ -419,12 +522,36 @@ public class InputManager implements RawInputListener { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Removes a listener from receiving events. |
|
|
|
|
* |
|
|
|
|
* <p>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. |
|
|
|
|
* |
|
|
|
|
* <p> |
|
|
|
|
* 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) { |
|
|
|
@ -448,6 +575,17 @@ public class InputManager implements RawInputListener { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Deletes a mapping from receiving trigger events. |
|
|
|
|
* |
|
|
|
|
* <p> |
|
|
|
|
* 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) { |
|
|
|
@ -462,6 +600,17 @@ public class InputManager implements RawInputListener { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Deletes a specific trigger registered to a mapping. |
|
|
|
|
* |
|
|
|
|
* <p> |
|
|
|
|
* 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) { |
|
|
|
@ -474,7 +623,8 @@ public class InputManager implements RawInputListener { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Clears all the input mappings from this InputManager. Consequently, also clears all of the |
|
|
|
|
* Clears all the input mappings from this InputManager. |
|
|
|
|
* Consequently, also clears all of the |
|
|
|
|
* InputListeners as well. |
|
|
|
|
*/ |
|
|
|
|
public void clearMappings() { |
|
|
|
@ -484,6 +634,7 @@ public class InputManager implements RawInputListener { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Do not use. |
|
|
|
|
* Called to reset pressed keys or buttons when focus is restored. |
|
|
|
|
*/ |
|
|
|
|
public void reset() { |
|
|
|
@ -492,13 +643,21 @@ public class InputManager implements RawInputListener { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Returns whether the mouse cursor is visible or not. |
|
|
|
|
* |
|
|
|
|
* <p>By default the cursor is visible. |
|
|
|
|
* |
|
|
|
|
* @param visible 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) { |
|
|
|
@ -508,24 +667,68 @@ public class InputManager implements RawInputListener { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 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. |
|
|
|
|
* |
|
|
|
|
* <p> |
|
|
|
|
* Any raw input listeners registered to this <code>InputManager</code> |
|
|
|
|
* will receive raw input events first, before they get handled |
|
|
|
|
* by the <code>InputManager</code> itself. The listeners are |
|
|
|
|
* each processed in the order they were added, e.g. FIFO. |
|
|
|
|
* <p> |
|
|
|
|
* 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); |
|
|
|
|
rawListenerArray = null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 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); |
|
|
|
|
rawListenerArray = null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Clears all {@link RawInputListener}s. |
|
|
|
|
* |
|
|
|
|
* @see InputManager#addRawInputListener(com.jme3.input.RawInputListener) |
|
|
|
|
*/ |
|
|
|
|
public void clearRawInputListeners() { |
|
|
|
|
rawListeners.clear(); |
|
|
|
|
rawListenerArray = null; |
|
|
|
@ -537,16 +740,22 @@ public class InputManager implements RawInputListener { |
|
|
|
|
return rawListenerArray; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public TouchInput getTouchInput() { |
|
|
|
|
return touch; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 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); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 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); |
|
|
|
@ -557,7 +766,7 @@ public class InputManager implements RawInputListener { |
|
|
|
|
int queueSize = inputQueue.size(); |
|
|
|
|
RawInputListener[] array = getRawListenerArray(); |
|
|
|
|
|
|
|
|
|
for (RawInputListener listener : array) { |
|
|
|
|
for (RawInputListener listener : array) { |
|
|
|
|
listener.beginInput(); |
|
|
|
|
|
|
|
|
|
for (int j = 0; j < queueSize; j++) { |
|
|
|
@ -618,14 +827,19 @@ public class InputManager implements RawInputListener { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Updates the Dispatcher. This will query current input devices and send |
|
|
|
|
* Updates the <code>InputManager</code>. |
|
|
|
|
* 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; |
|
|
|
|
|
|
|
|
|