asherbret
asherbret

Reputation: 6018

Can an Actor handle click and key down events?

I'm trying to make an Actor handle both click and key down events. I initialized the actor (in this case, an Image) as following:

stage = new Stage();
texture = new Texture("badlogic.jpg");
Image image = new Image(texture);
image.addListener(new ClickListener() {
    @Override
    public void clicked(InputEvent event, float x, float y) {
        Gdx.app.log("Image ClickListener", "clicked");
    }

    @Override
    public boolean keyDown(InputEvent event, int keycode) {
        Gdx.app.log("Image ClickListener", "keyDown. keycode=" + keycode);
        return true;
    }
});
stage.addActor(image);
Gdx.input.setInputProcessor(stage);

When I click on image, the clicked event is fired as expected, i.e., I see the respective log. However, no matter what key I press, the key down event does not fire. My question is: Why? Can't an Actor be able to handle both click and key down events?

Upvotes: 1

Views: 1428

Answers (2)

Stemkoski
Stemkoski

Reputation: 9045

Create a custom class that extends the Actor class and implements the InputProcessor interface.

When you set up your game, use an InputMultiplexer:

InputMultiplexer inputMulti = new InputMultiplexer(stage);
Gdx.input.setInputProcessor( inputMulti );

Then, in the constructor of your custom class, you can add the instance being created to the multiplexer as follows:

((InputMultiplexer)Gdx.input.getInputProcessor()).addProcessor(this);

Handling key input functionality then becomes simpler: instead of using the addListener method and creating an anonymous inner class that extends ClickListener etc. etc., you can just use the InputProcessor methods, for example:

public boolean keyDown(int keycode)
{
    if (keycode == Keys.SPACE)
    {
        // do something
    }

    return false;
}

This also avoids the need to set keyboard focus on the actor, which might not generalize well if you have multiple actors that need to process keyboard input.

However, one caveat to this approach is that any actor configured as an input processor will process all input events now, including touch events that do not overlap the actor, and this behavior may be undesired and/or confusing.

Upvotes: 1

m.antkowicz
m.antkowicz

Reputation: 13571

By default you should rather attach keyboard listener to the stage since the stage has keyboard focus on it so it should be something like

    stage.addListener(new InputListener() 
    {
        @Override
        public boolean keyDown(InputEvent event, int keycode) 
        {
            Gdx.app.log("Image ClickListener", "keyDown. keycode=" + keycode);
            return true;
        }
    });

If you want to change focus to be on the actor you can do this by using Stage method setKeyboardFocus(Actor actor). It should be something like:

    image.addListener(new ClickListener() 
    {
        @Override
        public void clicked(InputEvent event, float x, float y) {
            Gdx.app.log("Image ClickListener", "clicked");
        }

        @Override
        public boolean keyDown(InputEvent event, int keycode) {
            Gdx.app.log("Image ClickListener", "keyDown. keycode=" + keycode);
            return true;
        }
    });

    stage.setKeyboardFocus(image);

Upvotes: 4

Related Questions