Although I’ve found a solution, I’m not sure if it’s a bug or intended behaviour, so for my own education if anything else, so I understand why and avoid this situation again, it would be much appreciated if anyone could explain this behaviour.
I was experiencing an issue when I switched between vehicle controls and player controls.
enter vehicle: disable character controls, enable vehicle controls.
exit vehicle: disable vehicle controls, enable character controls.
Below are three appstates: the main example (for encapsulation) and two inner states that switch between each other. Pressing A and S switches between the inner states.
This is the line that causes and solves the issue.
private InputState inputState = InputState.Positive;
If the inputState value = InputState.Positive
then the keybindings do not appear to be removed and will result in the println being printed the same amount of times it’s been added - meaning they don’t actually get removed. This is the result of switching them six times.
Enabled 1
Enabled 2
Enabled 1
Enabled 2
Enabled 2
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 2
Enabled 2
Enabled 2
Enabled 2
Enabled 2
Enabled 2
Enabled 2
Enabled 2
Enabled 2
Enabled 2
Enabled 2
Enabled 2
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
Enabled 1
If the inputState value = InputState.Off
it works as intended. The keys are unregistered and behave as intended. The println’s display what I would expect. This is the result of switching them six times.
Enabled 1
Enabled 2
Enabled 1
Enabled 2
Enabled 1
Enabled 2
Enabled 1
Here is a test case that exposes the issue.
To clarify: changing the variable inputState
to InputState.Positive
causes the repeating issue, and changing the inputState
variable to InputState.Off
causes the correct (expected) behaviour.
package com.jayfella.modular.debug;
import com.jme3.app.Application;
import com.jme3.app.state.BaseAppState;
import com.jme3.input.KeyInput;
import com.simsilica.lemur.GuiGlobals;
import com.simsilica.lemur.input.FunctionId;
import com.simsilica.lemur.input.InputMapper;
import com.simsilica.lemur.input.InputState;
import com.simsilica.lemur.input.StateFunctionListener;
public class TestLemurMapping extends BaseAppState {
private static final String GROUP_NAME_1 = "G_STATE_ONE";
private static final FunctionId F_1 = new FunctionId(GROUP_NAME_1, "Function 1");
private static final String GROUP_NAME_2 = "G_STATE_TWO";
private static final FunctionId F_2 = new FunctionId(GROUP_NAME_2, "Function 2");
private InputMapper inputMapper;
private InputState inputState = InputState.Positive;
public TestLemurMapping() {
}
@Override
protected void initialize(Application app) {
GuiGlobals.initialize(app);
this.inputMapper = GuiGlobals.getInstance().getInputMapper();
}
@Override
protected void cleanup(Application app) {
}
@Override
protected void onEnable() {
getStateManager().attach(new StateOne());
}
@Override
protected void onDisable() {
}
private class StateOne extends BaseAppState implements StateFunctionListener {
@Override
protected void initialize(Application app) {
inputMapper.map( F_1 , KeyInput.KEY_A);
inputMapper.addStateListener(this, F_1);
}
@Override
protected void cleanup(Application app) {
inputMapper.removeMapping( F_1, KeyInput.KEY_A );
inputMapper.removeStateListener(this, F_1);
}
@Override
protected void onEnable() {
inputMapper.activateGroup( GROUP_NAME_1 );
System.out.println("Enabled 1");
}
@Override
protected void onDisable() {
inputMapper.deactivateGroup( GROUP_NAME_1 );
}
@Override
public void valueChanged(FunctionId func, InputState value, double tpf) {
if (func == F_1 && value == inputState) {
getStateManager().detach(this);
getStateManager().attach(new StateTwo());
}
}
}
private class StateTwo extends BaseAppState implements StateFunctionListener {
@Override
protected void initialize(Application app) {
inputMapper.map( F_2 , KeyInput.KEY_S);
inputMapper.addStateListener(this, F_2);
}
@Override
protected void cleanup(Application app) {
inputMapper.removeMapping( F_2, KeyInput.KEY_S );
inputMapper.removeStateListener(this, F_2);
}
@Override
protected void onEnable() {
inputMapper.activateGroup( GROUP_NAME_2 );
System.out.println("Enabled 2");
}
@Override
protected void onDisable() {
inputMapper.deactivateGroup( GROUP_NAME_2 );
}
@Override
public void valueChanged(FunctionId func, InputState value, double tpf) {
if (func == F_2 && value == inputState) {
getStateManager().detach(this);
getStateManager().attach(new StateOne());
}
}
}
}