Actioneer - An api for managing keybindings

Hello,

at first, i want to thank the developers for the monkey machine!

Now i want to present the Actioneer, which is an api to manage keybindings. It allows you to define an action and associate it with a shortcut. A shortcut is a sequence of arbitrary input triggers. The last trigger of such sequence is a “terminator” and all preceeding triggers (if any) are “modifiers”.

An action implements the de.wwg.actioneer.ShortcutAction interface (or extends the de.wwg.actioneer.AbstractShortctuAction) and defines what to do on the associated shortcut.

The Actioneer hides the input mapping and listener management from the application programmer, e.g. the following two lines enable the user to press the A-key on the keyboard to execute the action MyAction:

Actioneer actioneer = Actioneer.getActioneer(inputManager);
actioneer.addBinding(new MyAction(), new KeyTrigger(KeyInput.KEY_A));

The Actioneer API lets you:

  • Add a binding (action and associated shortcut).
  • Replace an action with another action of the same name (exchange of functionality).
  • Remove a binding from the Actioneer.
  • Change a shortcut associated with an action.
  • Backup and restore the current bindings.
  • Retrieve the localized bindings to display them e.g. in a dialog.
  • Define wether an action should receive analog input or not.
  • Use a CompositeKeyTrigger to group the L/R-Triggers, e.g. CompositeKeyTrigger.CONTROL represents KEY_LCONTROL and KEY_RCONTROL.

The source code is javadoced and the Actioneer project can be cloned from https://github.com/ekipur/wwg-actioneer.git.

A demo project is available under https://github.com/ekipur/wwg-actioneer-demo.git (Please read the README.md on how to include the required projects!).

The Actioneer is not intended to replace anything of the input system in jme3, instead it relies on it and is just another approach to handle input.

ekipur

1 Like

Hi. The project looks interesting. However, I can’t get the demo to run as it is missing a dependency: wwg-logging

The demo project would probably benefit from having your sources (actioneer, logging etc) compiled into jars and added to the repo. Then it would run once cloned.

I’ll give it another go once updated. Thanks.

Not to derail too much, but I thought I’d point out that Lemur’s InputMapper (which wraps InputManager and provides more functionality) has a similar, and slightly more flexible ability. The InputMapper is written in such a way that it can be used independently of Lemur. (You still need the jar but you can use InputMapper by itself.)

For InputMapper, you create function ID bindings which act as a logical separation between the action and the trigger.

FunctionId selectAll = new FunctionId(“Select All”);
inputMapper.map(selectAll, KeyInput.KEY_A);
inputMapper.addStateListener(new SelectAllClass(), selectAll);

Where it becomes more interesting:

  1. you can have any number of listeners for the ID.
  2. FunctionIds can also have a group ID that can be used to wholesale enable/disable entire groups of actions
  3. it supports multi-key binding, so for example: inputMapper.map(selectAll, KeyInput.LCONTROL, KeyInput.KEY_A) maps to control-A
  4. multiple triggers can be mapped to the same ID: inputMapper.map(selectAll, KeyInput.RCONTROL, KeyInput.KEY_A) now means that either ‘control’ + A will work.
  5. it supports mapping mouse and joystick buttons in a similar way.
  6. analog axis ranges and action triggers are mapped in the same way and buttons or pairs of buttons can be used like analog ranges. (ie: you can map ‘W’ and ‘S’ to the ‘move’ function as well as joystick y-axis and the same actions/analog listeners will work)
  7. you can trivially map an action to a method on some object:
    inputMapper.addDelegate(selectAll, mySelectionState, “selectAll”);
    …and therefore avoid a whole separate ‘action class’ completely.
  8. because FunctionId is the join-point from bindings to ‘actions’, you could have a screen where the user could easily remap these.

I hated to derail your thread and take away from your work as it looks really nice. But I feel like not enough people know about InputMapper and it’s a shame because it could have saved you time. There has also been talk about maybe moving this functionality into core someday.

Anyway, if you are curious sometime:
http://hub.jmonkeyengine.org/forum/board/projects/lemur/
http://hub.jmonkeyengine.org/forum/topic/lemur-gems-1-inputmapper-based-camera-movement/
http://hub.jmonkeyengine.org/forum/topic/lemur-gems-2-inputmapper-delegates/

Main InputMapper code:
https://code.google.com/p/jmonkeyplatform-contributions/source/browse/trunk/Lemur/src/com/simsilica/lemur/input/InputMapper.java

1 Like

Hello alfinete,

thanks for your response!

The project wwg-actioneer-demo contains a README.md file where i describe how to include the required projects wwg-actioneer and wwg-logging.

My intention was to keep the projects “pure” open-source, but for the demo it may indeed be the better way to bundle all related projects into a jar. I will do it soon.

ekipur

Hello pspeed,

thank you for your response, too!

At the time i started the Actioneer project, i didn’t find anything that would provide an api similar to that of the Actioneer.

My intention was to implement an api that allows me to define a keybinding with one method call (addBinding(action, Trigger…)) hiding the whole input mapping and listener management. So, with the Actioneer i can completely focus on what really is to do when an associated shortcut is “activated”. This is done by constructing an action object that implements the ShortcutAction interface or extends the AbstractShortcutAction. This action object itself is in fact the listener for the input data, be it digital:

ShortcutAction.switched(boolean on, float tpf)

or analog

ShortcutAction.receiving(float value, float tpf).

I have to emphasize that such an action is primarily identified by its name (kind of a function id) and not by the object reference. By solely extending an existing ShortcutAction you can bind the new action to another shortcut using the same functionality.

In my opinion, the main difference between the Actioneer and Lemur’s InputMapper is that the Actioneer’s ShortcutAction represents three parts of Lemur’s InputMapper:

  1. Function id
  2. Action implementation
  3. Data listener

Another feature of the Actioneer is that each kind of “terminator” trigger be it digital (boolean pressed) or analog (float value) causes the Actioneer to deliver a start resp. stop event by calling the switched(boolean on, float tpf) method of the triggered action.

The return value of the ShortcutAction.isAnalog() method decides if the Actioneer should invoke

a) an AnalogListener and
b) the ShortcutAction.receives(float value, float tpf) method or not.

I had to go a little bit into detail trying to carve out the differences between the Actioneer and Lemur’s InputMapper.

It is not my intention to compete with the Lemur’s InputMapper but to compare it.

ekipur

Hello,

the wwg-actioneer-demo repo is updated and the README.md should better describe how to build the demo from the sources.

In the wwg-actioneer-demo-bin there is a zip file containing the demo’s dist directory. This way the demo can be run without the sources.

ekipur

I have my own InputMapperUtil :D.

  • Instantiate by passing it:
  • a simpleApplication
  • a Profile
  • a String prefix (group of mappings we currently are concerned with… in my case, Car/Plane/Hoover)
  • Requires a Globals.CONTROLS_CONFIG_FILE pointing to the controls file

  • add mappings to the application by calling addMap passing it:

  • a String key
  • an inputListener

… and it will retrieve and setup the correct triggers from the controls properties file and call the linked methods on the listener when triggered.

  • saving mappings is done by saving the keys in the controls properties file.

  • supports resetting to default controls file easily

Allows:

  • using all types of input (apart from touch becose I don’t have anything with touch)
  • multiple joysticks etc
  • different mappings per profile
  • regroups mappings per profile and prefix (in my case, vehicle type)
  • can support multiple keys for the same trigger
  • can modify controls either via code/game interface or simply modifying the properties file

Does not allow:

  • using composite keys (alt-G for example)
  • using touch triggers for the aforementioned reason
  • multiple listeners per trigger

Been using it for over a year without a glitch.
Could make it into a lib but think you peeps got it covered nicely.

Hello,

the Actioneer is now updated to version 0.14.06. The api itself didn’t change, but i did some renamings and straightened the code:

Actioneer.java:

  • addAction() renamed to addBinding().
  • updateShortcut() renamed to updateBinding().
  • removeAction() renamed to removeBinding().
  • setActioneerListener() renamed to setBindingListener.
  • Interface ActioneerListener renamed to BindingListener.
    ShortcutAction.java:
  • Renamed to TriggerAction.java.
  • Methods switched() und receiving() renamed to onSwitched() und onReceiving() to indicate that they are event methods in contrast to the attribute methods getName() and isAnalog().
    AbstractShortcutAction.java:
  • Renamed to AbstractTriggerAction.java. Implements the onReceiving() method with an empty body.
  • Can be instanciated without submitting a name. In this case the name attribute is set to getClass().getSimpleName().
    Bugfix:
  • In some cases an action could have been triggered by activating the modifier after the terminator. E.g. if you have the analog action Action1 bound to key A and an (digital or analog) Action2 bound to Ctrl-A, Action2 was triggered when pressing Ctrl after key A, because the analog events for Action1 were handled as pressed events. This has been fixed, so that pressing the A-key triggers Action1 as intended, but Action2 isn’t triggered anymore when Ctrl is pressed while holding the A key down.

ekipur

1 Like