Event handling allows you to get more granular and most of all chronological information about input from the user. Event handling provides a way to implement interactions with user interfaces, where specific input sequences are important, e.g. touch down, touch up on a button means the user clicked the button. Such interactions are hard to implement with polling.
Input Processor
Event handling is done using the common observer pattern. First we have to implement a listener interface called InputProcessor:
public class MyInputProcessor implements InputProcessor {
public boolean keyDown (int keycode) {
return false;
}
public boolean keyUp (int keycode) {
return false;
}
public boolean keyTyped (char character) {
return false;
}
public boolean touchDown (int x, int y, int pointer, int button) {
return false;
}
public boolean touchUp (int x, int y, int pointer, int button) {
return false;
}
public boolean touchDragged (int x, int y, int pointer) {
return false;
}
public boolean mouseMoved (int x, int y) {
return false;
}
public boolean scrolled (float amountX, float amountY) {
return false;
}
}
The first three methods allow you to listen for keyboard events:
- keyDown(): Called when a key was pressed down. Reports the key code, as found in Keys.
- keyUp(): Called when a key was lifted. Reports the key code as above.
- keyTyped(): Called when a Unicode character was generated by the keyboard input. This can be used to implement text fields and similar user interface elements.
The next five methods report mouse/touch events:
- touchDown(): Called when a finger went down on the screen or a mouse button was pressed. Reports the coordinates as well as the pointer index and mouse button (always Buttons.LEFT for touch screens).
- touchUp(): Called when a finger was lifted from the screen or a mouse button was released. Reports the last known coordinates as well as the pointer index and mouse button (always
Buttons.Left
for touch screens). - touchDragged(): Called when a finger is being dragged over the screen or the mouse is dragged while a button is pressed. Reports the coordinates and pointer index. The button is not reported as multiple buttons could be pressed while the mouse is being dragged. You can use
Gdx.input.isButtonPressed()
to check for a specific button. - mouseMoved(): Called when the mouse is moved over the screen without a mouse button being down. This event is only relevant on the desktop and will never occur on touch screen devices where you only get
touchDragged()
events. - scrolled(): Called when the scroll wheel of the mouse was turned. Reports a positive value, a negative value or zero depending on the direction of spin. This will never be called for touch screen devices.
Each of the methods returns a boolean
. We’ll look into why that is in the InputMultiplexer section below.
Once you implement your InputProcessor
you have to tell libGDX about it so it can be called when a new input event arrives:
MyInputProcessor inputProcessor = new MyInputProcessor();
Gdx.input.setInputProcessor(inputProcessor);
From this point on, all new input events will be pushed to the MyInputProcessor
instance. Events are dispatched right before the call to ApplicationListener.render()
, on the rendering thread.
InputAdapter
InputAdapter
implements all the InputProcessor
methods, returning false from each. You can extend InputAdapter
so you only need to implement the methods you need. You can also use an anonymous inner class.
Gdx.input.setInputProcessor(new InputAdapter () {
@Override
public boolean touchDown (int x, int y, int pointer, int button) {
// your touch down code here
return true; // return true to indicate the event was handled
}
@Override
public boolean touchUp (int x, int y, int pointer, int button) {
// your touch up code here
return true; // return true to indicate the event was handled
}
});
InputMultiplexer
Sometimes you want to chain InputProcessors
, e.g. you have one processor for your UI which should be invoked first, and a second processor for input events that manipulate your game’s world. You can use the InputMultiplexer class to achieve this:
InputMultiplexer multiplexer = new InputMultiplexer();
multiplexer.addProcessor(new MyUiInputProcessor());
multiplexer.addProcessor(new MyGameInputProcessor());
Gdx.input.setInputProcessor(multiplexer);
The InputMultiplexer
will hand any new events to the first InputProcessor
that was added to it. If that processor returns false from the method invoked to handle the event, this indicates the event was not handled and the multiplexer will hand the event to the next processor in the chain. Through this mechanism, the MyUiInputProcessor
can handle any events that fall inside one of its widgets and pass on any other events to the MyGameInputProcessor
.
Example of continuous Input handle
If you want to move an actor using the Input Processor, you will notice that it will move only when the key is typed (or pressed with keydown). To continuosly handle input, or to move a sprite, you could add a flag to your actor like this:
public class Bob
{
boolean leftMove;
boolean rightMove;
...
updateMotion()
{
if (leftMove)
{
x -= 5 * Gdx.graphics.getDeltaTime();
}
if (rightMove)
{
x += 5 * Gdx.graphics.getDeltaTime();
}
}
...
public void setLeftMove(boolean t)
{
if(rightMove && t) rightMove = false;
leftMove = t;
}
public void setRightMove(boolean t)
{
if(leftMove && t) leftMove = false;
rightMove = t;
}
Then, in your Input processor:
...
@Override
public boolean keyDown(int keycode)
{
switch (keycode)
{
case Keys.LEFT:
bob.setLeftMove(true);
break;
case Keys.RIGHT:
bob.setRightMove(true);
break;
}
return true;
}
@Override
public boolean keyUp(int keycode)
{
switch (keycode)
{
case Keys.LEFT:
bob.setLeftMove(false);
break;
case Keys.RIGHT:
bob.setRightMove(false);
break;
}
return true;
}