Skip to content

Action handlers

Gombaris edited this page Oct 16, 2024 · 7 revisions

Extended controls allow vehicles and aircraft to bind to any input actions they want to handle, while the user can configure multiple custom keyboard and joystick bindings to the actions.

As an example, a vehicle script can contain the following piece of code in it's init_chassis function to indicate it handles a certain action:

this.register_event("vehicle/lights/cabin", function() { this.light_toggle_mask(0x1f); });

Whereas the user has the "vehicle/lights/cabin" action bound to shift+L on the keyboard and also to a button on a joystick or even to an event coming from an external plugin handling a custom cockpit.

Action handlers

Action handlers are events, which are called, when binded input/object changed it's state.

Action handlers can be of two types: events and values.

  • event handlers - invoked once, on key or button press, for example a fire action would typically be an event.

  • value handlers - invoked continuously, while the tracked value changes (by default in -1..1 range). Additionally, it can define parameters that influence the changes in the value, such as velocity, minimum value, maximum value etc.

Warning: value handlers (register_axis, register_handler, etc.) get called with value 0, when the script is loaded/reloaded.

event handlers (register_event) are not called on script load/reload.

If user has the action bound to a joystick axis, the handler will receive the axis position.

If it's bound to keyboard or joystick buttons, the value is tracked internally depending on the binding modes and the handler configuration.

For keyboard control it's possible to bind one or several keys that will control the value, and the mode (a part of the binding) determines what type of operation is performed by the button.

For example, a single button assigned to an action binding can toggle the target value between min/max (normally -1/1, but script can specify custom bounds, like the often used 0/1), or pressing the button, may set the target value to 1, and after releasing, it will fall back to 0.

To register an event handler, script can call the following methods:

this.register_event("air/controls/eject", function() {...});
this.register_button("air/controls/eject", function() {...});

To register a value handler, the following method can be used:

this.register_axis("air/heli/collective", ramp, function(v,dt) {...});

Note: function register_button() is helper function using register_axis() with predefined parameters for creating buttons, that should return to default position after releasing (it is similar to using register_axis() with "positions: 1", without the need to specify additional "ramp" parameters)

Action handler parameters

Action handlers declarations:

Action handlers can have different parameters, depending on which handler you use.

register_event(name, handler, group, channels);
register_button(name, handler, group, channels);
register_axis(name, ramp, handler, defval, group);

Parameters

parameter description default
name path to action, containing input binding, e.g. "vehicle/lights/main", meaning action from vehicle.cfg, group "lights", action name "main"
handler function, which is invoked whenever given event occurs or the tracked value changes
group event group ID, in case you want to enable/disable groups of actions, for example (e.g. on seat change) 0
defval default value for axis/switch
channels number of extra channels supported by the handler 0
ramp optional parameters (can be left with empty brackets {}), that influence the changes in the value
(can be used only in value handlers, such as register_axis)

Input action "name"

Input actions are defined in bin/defaults/iomap directory, in .cfg files. There are separate files for different categories (air.cfg, vehicle.cfg, train.cfg etc.). Each configuration file contains several functional groups, for example air/controls or air/engines. Groups then contain related actions with input bindings.

Action names used are in the form "file/group/action"

  • file - refers to the config file name (without .cfg)
  • group - name of the group, which contains the desired action
  • action - action name.

For more information on IOMap configuration and list of pre-defined actions, see the IOMap-configurations page.

"handler" function

When using action handlers, to associate an event with a specific action, we need to provide a function that describes what action should be taken when the event occurs. This is the "handler" parameter.

The "handler" function is invoked, whenever given event occurs or the tracked value changes as the result of the button state.

This function has 3 parameters:

  • v - the action value itself(integer for events or floating point for values)
  • dt - elapsed time in seconds since the last frame (delta time)
  • ch - channel ID, which is useful for actions that can adress multiple channels (ID 0 should be interpreted as "all channels", so that it remains compatible with single channel bindings)).
//This code calls reverse_action function, when handled
this.register_event("vehicle/engine/reverse", reverse_action); 

"ramp" parameters

"ramp" parameters are optional parameters, that largely determine, how the action value should behave when controlled by keyboard or buttons

type parameter description
float minval minimum value to clamp to, it's often desired to have a 0..1 range instead of the default -1..1 range (should be >= -1 for compatibility with joystick)
float maxval maximum value to clamp to (should be <= +1 for compatibility with joystick)
float center (JS)
cenvel (C++)
centering speed per second (the speed of returning to default value after button release), 0 for no centering
float vel max rate of value change (saturated) per second during key press
float acc max rate of initial velocity change per second during key press (controls the key press response swiftness)
uint8 positions number of positions/steps between minval and maxval, e.g. light switch with 4 positions, has minval 0 and maxval 3, when coresponding input is pressed, the switch will jump between 0,1,2 and 3
uint8 channels (JS)
extra_channels( C++)
number of extra channels supported by the handler ( max 7 )

The vel and center values can be negative, in that case, the actual speed is multiplied by -e^(-kmh/steering_threshold). This can be used for steering, with centering going slower at slower vehicle speeds, and to slow down steering speed at higher vehicle speeds.

Binding modes

Each keyboard controlled value can have assigned several key bindings, which control, what happens with the tracked action value. For example, one button can increase the value when pressed, while another decreases it. Yet another button may be setting the value to zero/center, or there could be a button that toggles between -1/1 (or between 0/1 or 0/-1 , which is useful for turn signals). Buttons may also be set up to increment or decrement the value in positions, specified in "ramp" parameters.

All modes may be used at once, and it's also possible to have multiple keys/buttons assigned with the same mode.

Here's a list of existing modes for buttons:

code    description                 aliases                                 LSB event code
==========================================================================================
+           target to +1            (empty) plus positive 1 on up right         0x00
-           target to -1            invert minus negative down left             0x02
0           reset/center            reset center off                            0x01
++          increment               inc                                         0x10
--          decrement               dec                                         0x12
toggle      toggle min/max                                                      0x04
toggle+     toggle 0/max                                                        0x05
toggle-     toggle min/0                                                        0x07
combo       combo mode (ctrl|shift)                                             0x08

Note: these binding modes always set the desired (target) value, not the current action value. How fast the value changes to reach the target depends on, how the ramp parameters were set, when the action handler was registered.

Interactive (VR) mode

Interactive elements must be pre-defined in the model with specific attributes that dictate their behavior (referred to as "ramp" parameters). To retain these attributes, users can utilize the register_axis with empty "ramp" parameters, or use the register_handler.

register_handler is also of type "value", same as "register_axis", but it works only with pre-defined attributes.

To modify these attributes, register_axis should be used, where adjustments to the "ramp" parameters can be made.

For interactive mode it is also possible to bind to an object/knob without using input action. This can be achieved by using automatic generated name format "knob_action_[name of bone]"

this.register_handler("knob_action_front_REŽIM_LOKO", function(v){ 	
this.loco_mode = v;
if(v === 0)
{
	this.set_action_value(act_stop, 1, false);  
}
});

For more information see Interactive elements ‐ how to use them and Vehicle IK: Interactive elements

Test

Clone this wiki locally