Keypresses not being detected when low FPS

Hello, it looks like I've come across a bug in KeyBindingManager. If your framerate is very poor (i.e. <10fps), then keypresses you make can often be discarded by KeyBindingManager.



I've included code for a test class that shows this. It will force your framerate down to 1fps and adds two ways of detecting the 'B' key being pressed. One way is using KeyBindingManager, the other using InputHandler and ActionEvents. When you press the B key, it will System.out.println the result. I've found that the action event will always pick up the keypress, but the binding manager won't.



I believe this is because KeyBindingManager's isValidCommand() always asks what the current key is, but it's asking this well after the key has been both pressed and released.



I hope this helps.



package draco;

import com.jme.app.FixedFramerateGame;
import com.jme.input.InputHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.KeyInputListener;
import com.jme.input.action.InputAction;
import com.jme.input.action.InputActionEvent;
import com.jme.system.DisplaySystem;
import com.jme.system.GameSettings;
import com.jme.system.PropertiesGameSettings;
import com.jme.util.Timer;

/**
 *
 */
public class KeyPressTest extends FixedFramerateGame {
   Timer timer;
   InputHandler input;

   public static void main(String[] args)
   {
      KeyPressTest main = new KeyPressTest();
      main.setConfigShowMode(ConfigShowMode.AlwaysShow);
      main.start();
   }

   @Override
   protected void update(float interpolation) {
      timer.update();
      input.update(timer.getTimePerFrame());
      
      if (KeyBindingManager.getKeyBindingManager().isValidCommand("mytest", false)) {
         System.out.println("KeyBindingManager detected the 'B' being pressed");
      }
   }

   @Override
   protected void render(float interpolation) {
   }

   @Override
   protected void initSystem() {
      display = DisplaySystem.getDisplaySystem(settings.getRenderer());
      // Create a window with the startup box's information.
      display.createWindow(settings.getWidth(), settings.getHeight(),
            settings.getDepth(), settings.getFrequency(),
            settings.isFullscreen());

      input = new InputHandler();
   }

   @Override
   protected void initGame() {
      setFrameRate(1);

      /*
      KeyInput.get().addListener(new KeyInputListener() {
         public void onKey(char character, int keyCode, boolean pressed) {
            System.out.println("Pressed " + character);
         }
      });
      */

      KeyBindingManager.getKeyBindingManager().set("mytest", KeyInput.KEY_B);
      KeyBindingManager.getKeyBindingManager().set("showframerate", KeyInput.KEY_F);

      final InputAction actionBKey = new InputAction() {
             public void performAction( InputActionEvent evt ) {
                if (evt.getTriggerPressed())
                {
                   System.out.println("InputHandler detected 'B' key");
                }
             }
         };
      input.addAction(actionBKey, InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_B, InputHandler.AXIS_NONE, false );   
      
      final InputAction showFrameRate = new InputAction() {
             public void performAction( InputActionEvent evt ) {
                if (evt.getTriggerPressed())
                {
                   System.out.println("FPS = " + timer.getFrameRate());
                }
             }
         };
      input.addAction(showFrameRate, InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_F, InputHandler.AXIS_NONE, false );   
   
      timer = Timer.getTimer();
   }

   @Override
   protected void reinit() {
   }

   @Override
   protected void cleanup() {
   }

   @Override
   protected GameSettings getNewSettings() {
      GameSettings gameSettings = new BaseGameSettings();

      gameSettings.setFramerate(1);
      gameSettings.setVerticalSync(true);
      
      return gameSettings;
   }
   
   static class BaseGameSettings extends PropertiesGameSettings
   {
      static
      {
         defaultFullscreen = Boolean.FALSE;
         defaultSettingsWidgetImage = "/jmetest/data/images/Monkey.png";
      }
      BaseGameSettings()
      {
         super("properties.cfg");
         load();
      }
   }
}

Yes, I've been there too:



http://www.jmonkeyengine.com/jmeforum/index.php?topic=8665.0


oops sorry… I tried searching to see if anyone else had reported it, but I didn't find anything. Since the advice in your thread is to simply not use the KeyBindingManager way of doing it, I'm wondering if it should be deprecated so others don't fall into the same trap? :slight_smile:

I think you described the problem in a better way.



I started having problems with this when I updated from the jme1.0 release  to a later version.



Now I'm having a similar problem with the MouseInputListener, loosing onButton events. Is that being polled in the same way?

Ah I'm on the later version too - it looked way too shiny to pass up :slight_smile:



Hmm… I've just tested mouseclicks by setting my fps to 1 again, but those are working fine for me. The clicks just queue up and I get all the events firing.



I'm using



MouseInput.get().addListener(class that implements MouseInputListener);



I should add that my jME version was last updated a couple of weeks ago, so maybe something changed since then.

Thanks!



That's good to know.

The error was in my code. I was mixing polling MouseInput and receiving events.