Input Event Handling Improvement

Current input event handling system is appropriate for games but sometimes inconvenient to use.

I have an input abstraction layer to register composite input filter like double click, mouse+keyboard actions.

and swing-like key/mouse listeners too.

How about adding this functionality?

This class needs Predicate in google guava library.



The listener interfaces are below.

[java]

public interface MouseButtonListener {

public void mousePressed(MouseButtonEvent event);

public void mouseReleased(MouseButtonEvent event);

}



public interface MouseMotionListener {

public void mouseMove(MouseMotionEvent event);

public void mouseDrag(MouseMotionEvent event);

public void mouseWheel(MouseMotionEvent event);

}



public interface KeyListener {

public void keyPressed(KeyInputEvent event);

public void keyReleased(KeyInputEvent event);

}



// for composite input event

public interface EventListener {

public void eventDelivered(Object eventId);

}

[/java]



[java]

public class InputAbstraction implements RawInputListener {

private static final int KEY_CODE_COUNT = 0xFF;

private static final int MOUSE_BUTTON_COUNT = 3;

private static final long DOUBLE_CLICK_INTERVAL = 250;



private final KeyDispatcher keyDispatcher = new KeyDispatcher();

private final KeyInputEvent[] keyStatus = new KeyInputEvent[KEY_CODE_COUNT];

private final MouseButtonEvent[] mouseButtonStatus = new MouseButtonEvent[MOUSE_BUTTON_COUNT];

private MouseButtonEvent recentMouseButtonStatus = new MouseButtonEvent(-1, false, -1, -1);

private MouseMotionEvent recentMouseMotionStatus = new MouseMotionEvent(-1, -1, -1, -1, -1, -1);

private KeyInputEvent recentKeyStatus = new KeyInputEvent(-1, (char)0, false, false);

private int clickCount;

private long eventTime;



private final MouseButtonDispatcher mouseButtonDispatcher = new MouseButtonDispatcher();

private final MouseMotionDispatcher mouseMotionDispatcher = new MouseMotionDispatcher();

private final LinkedList<ListenerEntry> listeners = new LinkedList<ListenerEntry>();



class ListenerEntry {

EventListener l;

Predicate<InputAbstraction> predicate;

Object id;



ListenerEntry(EventListener l, Predicate<InputAbstraction> p, Object id) {

this.l = l;

this.predicate = p;

this.id = id;

}

}



public InputAbstraction(InputManager manager) {

manager.addRawInputListener(this);

}



public void addMouseButtonListener(MouseButtonListener l) {

mouseButtonDispatcher.addListener(l);

}

public void addMouseMotionListener(MouseMotionListener l) {

mouseMotionDispatcher.addListener(l);

}

public void addKeyListener(KeyListener l) {

keyDispatcher.addListener(l);

}



@Override

public void beginInput() {

}



@Override

public void endInput() {

}



@Override

public void onJoyAxisEvent(JoyAxisEvent evt) {

}



@Override

public void onJoyButtonEvent(JoyButtonEvent evt) {

}



@Override

public void onMouseMotionEvent(MouseMotionEvent evt) {

recentMouseMotionStatus = evt;

mouseMotionDispatcher.dispatch(evt);

// dispatchEvent();

}



@Override

public void onMouseButtonEvent(MouseButtonEvent evt) {

long currentTime = System.currentTimeMillis();

if (evt.isPressed() && recentMouseButtonStatus.getButtonIndex() != evt.getButtonIndex() || currentTime-eventTime>DOUBLE_CLICK_INTERVAL) {

clickCount = 0;

}

if (evt.isReleased()) {

clickCount++;

}

eventTime = currentTime;

recentMouseButtonStatus = evt;

mouseButtonStatus[evt.getButtonIndex()] = evt;

mouseMotionDispatcher.setDrag(evt.isPressed());

mouseButtonDispatcher.dispatch(evt);

dispatchEvent(evt);

}



@Override

public void onKeyEvent(KeyInputEvent evt) {

recentKeyStatus = evt;

keyStatus[evt.getKeyCode()] = evt;

keyDispatcher.dispatch(evt);

dispatchEvent(evt);

}



public KeyInputEvent getKeyStatus(int keyCode) {

return keyStatus[keyCode];

}



public MouseButtonEvent getMouseButtonStatus(int button) {

return mouseButtonStatus[button];

}



public MouseButtonEvent getRecentMouseButtonStatus() {

return recentMouseButtonStatus;

}



public KeyInputEvent getRecentKeyStatus() {

return recentKeyStatus;

}



public void addListener(Object id, Predicate<InputAbstraction> predicate, EventListener listener) {

listeners.add(new ListenerEntry(listener, predicate, id));

}



private void dispatchEvent(InputEvent event) {

for (ListenerEntry entry : listeners) {

if (entry.predicate.apply(this)) {

entry.l.eventDelivered(entry.id);

}

}

}



public int getClickCount() {

return clickCount;

}



public MouseMotionEvent getMouseMotionStatus() {

return recentMouseMotionStatus;

}

}

[/java]

So how would it work with the existing Input mapping system?

It is just a RawInputListener. Create and add it to InputManager. It’s all.

InputManager exposes only RawListener and ActionListener for now.

InputManager may expose listeners shown above also, If it’s not bad idea…

oh ok!

yeah that seems pretty neat.

Maybe we should add support for joystick too!



Thank you, once again :wink:

Then I’ll add this to InputManager and expose listeners.

Please add google guava library to NetBeans project.

I’m not using NetBeans.

Wait but its supposed to be separate from InputManager no?

And I don’t see why we need guava for this kind of simple thing

Yeah, it can be separated from InputManager. then I’ll not integrate it.

For collection library, I think it had better including one for jme3 core.

(guava, apache collection or whatever)