CREATING COCKPIT INTERACTIONS

When it comes to creating cockpit interactions, we recommend making heavy use of the core templates that come supplied with the SDK. These can be found in the following folder that was installed with the SDK:

<SDK_ROOT>\ModelBehaviorDefs\Asobo_EX1\

You can also find versions of them that are simpler to study included in this documentation on the following page:

 

When it comes to setting up the files for interactions, we recommend that you create a hierarchy, both with the model behavior files themselves and with the contents of the files. For example, looking at the Cabri G2 sample project (included with the SDK) you will see that all of the cockpit behavior XML is found in the Function_Interior attachment, and is split into several files:

The Cockpit Model Behavior Files Used By The Cabri G2

NOTE: Due to aircraft in Microsoft Flight Simulator 2024 being modular in nature, the placement of these files will depend greatly on how you wish to setup the common folder and the accompanying presets and attachments as well, since model behavior XML can be present in all of them. This page is only going to concentrate on how the model behavior files work together and not the actual file and folder hierarchy of the aircraft, although this will be something to keep in mind when creating your own XML.

 

In this case the main model XML file (cockpit.xml) simply has the LOD info and then a <CompileBehaviors> element which uses <IncludeBase /> to call another file, cockpit_Behavior.xml. It's this file which does most of the heavy lifting and contains the main components and also adds the other files (core templates and more custom files). This structure means that you have one file for the LODs, one file for the components, and then additional files for templates and parameter functions, making everything easier to not only debug, but extend and edit at a later date.

 

The rest of this page will document the setup of cockpit interactions using the core model behavior templates that are supplied with the SDK, concentrating on the main supplementary XML file (ie: the one referenced from the main model XML file, as explained above).

 

 

Initial File Setup

The file that you'll be creating will not have any LOD data (since that will be handled by the main model XML file), and will only be used for creating interaction components. To start with in this file you will need the <ModelBehaviors> element at the top level, eg:

<ModelBehaviors>
    <!-- Everything Else Here -->
</ModelBehaviors>

 

You should then use the <Include> element to reference the core files that will contain the templates you'll need for the interactions to work:

<ModelBehaviors>
    <Include ModelBehaviorFile="ASOBO_EX1\InteriorDefs.xml"/>
</ModelBehaviors>

 

The file is simply an "index" file that then references other core templates, which in turn reference other template files. Using this file simply includes all the core templates you could possibly need when creating the interactions. The most important ones that will be included are:

 

You could include only the files you need rather than all of them, but - unless you know exactly what you are doing - it is better to simply include all of them, as that gives you the most options and the least probability of errors.

 

The final thing to add to prepare your file is a core <Component> element that will initialise certain global parameters that will be required by the other templates you'll be using:

<ModelBehaviors>
    <Include ModelBehaviorFile="ASOBO_EX1\InteriorDefs.xml"/>
    <Component ID="CONFIG">
        <Parameters Type="Override">
            <UseParametersFn Name="ASOBO_Configure_Global_Parameters"/>
        </Parameters>
    </Component>
    <!-- Future Components Here -->
</ModelBehaviors>

 

 

Interaction Templates

Once the location in the hierarchy has been decided for your files and the initial XML has been created to call the core templates, you will need to find which default interaction matches best with the instruments you aim to create an interaction for. This is obviously a subjective choice and will only affects the default properties of how your instrument will be interacted with. The main templates you will want to use are as follows:

 

Template Name Description
ASOBO_CT_Simple_Interaction_Template [ASOBO_IT_Simple_Interaction_Template] An interaction without animation
ASOBO_CT_Button_Template [ASOBO_CT_Button_Template] A button interaction
ASOBO_CT_Switch_Template [ASOBO_CT_Switch_Template] A switch interaction
ASOBO_CT_Lever_Template [ASOBO_IT_Lever_Template] A lever interaction
ASOBO_CT_Knob_Template [ASOBO_CT_Knob_Template] A switch like interaction with a rotation animation
ASOBO_CT_Knob_Finite_Template [ASOBO_CT_Knob_Finite_Template] A knob interaction with a min and max rotation
ASOBO_CT_Knob_Infinite_Template [ASOBO_CT_Knob_Infinite_Template] A knob interaction without any bounds for the rotation
ASOBO_CT_Joystick_Template [ASOBO_CT_Joystick_Template] A joystick interaction (for instance a two-axis trim controller on a yoke or a joystick that controls an avionics device)
ASOBO_IT_HANDLING_Single_Yoke_Template [ASOBO_IT_HANDLING_Stick_Template, ASOBO_IT_HANDLING_Single_Stick_Template] A yoke or control stick animation
ASOBO_IT_HANDLING_Double_Yoke_Template [ASOBO_IT_HANDLING_Double_Stick_Template] A yoke or control stick animation for dual cockpit
ASOBO_IT_HANDLING_Single_Rudder_Pedals_Template [ASOBO_IT_HANDLING_Rudder_Pedals_Template] Rudder animation for independent rudder pedals
ASOBO_IT_HANDLING_Double_Helicraft_Rudder_Pedals_Template Rudder animation for helicopters with dual cockpit

 

When using these templates it should be noted that in each interaction you will have an axis. The axis can be specified using the <AXIS> parameter, where:

  • X means horizontal
  • Y means vertical

For all templates the default axis is X for knobs and Y for levers and switches, for example:

<UseTemplate Name="ASOBO_CT_Switch_Template">
    <AXIS>X</AXIS>
</UseTemplate>

 

Additionally, there will be the following common parameters that each interaction template will understand and use:

 

Parameter Name Description
IN_BASE_NAME Here you give the name of the node and animation in the model glTF. If they are different, you will instead need to specify <NODE_ID> and <ANIM_NAME> instead.
IE_NAME Here you give the name of the input event created along with this interaction.
IE_TYPE

This is the input event category used for the interaction, which defaults to UNKNOWN if not included. Note this category has no direct effect on the simulation, but is used as a prefix to identify the input event for tooltip localisation (see here for more information), as well as in the debug display. It can be any of the following:

AUTOPILOT
AUXILIARY
DEICE
ELECTRICAL
ENGINE
ROTOR
FUEL
HANDLING
HYDRAULIC
INSTRUMENT
LANDING
LIGHTING
PNEUMATICS
RADIO
AUDIO
SAFETY
COMMON
PROCEDURE
VARIABLE
UNKNOWN

IE_ID_SOURCE This is used to provide and alternative prefix for tooltip localisation (see here for more information).

 

 

Discrete State Interactions

Some interactions expect to be given a set of discrete states corresponding to the different positions the instrument can take. The positions will be defined inside a <ParametersFn>, and in the component you'll use the <GET_SETTINGS> parameter along with the name of the <ParametersFn> which defines the positions definition that you want to make use of, for example, using the ASOBO_CT_Switch_Template template:

<UseTemplate Name="ASOBO_CT_Switch_Template">
    <IN_BASE_NAME>OVHD_BELTS_SWITCH_FASTEN_1</IN_BASE_NAME>
    <IE_NAME>FASTEN_BELTS</IE_NAME>
    <GET_SETTINGS>MYFUNCTION_ON_AUTO_OFF_Settings</GET_SETTINGS>
    <SOUND_EVENT_TYPE_ID>1</SOUND_EVENT_TYPE_ID>
</UseTemplate>

 

The <ParametersFn> in this case can also go in the XML file, or - as the base MSFS 2024 aircraft do - it can go in a separate file that would be included with the package. This function will look like this:

<ParametersFn Name="MYFUNCTION_ON_AUTO_OFF_Settings">
    <ReturnParameters>
        <UseParametersFn Name="ASOBO_Auto_Define_Positions_And_Tooltips_Helper">
            <POS_0>ON</POS_0>
            <POS_1>AUTO</POS_1>
            <POS_2>OFF</POS_2>
        </UseParametersFn>
    </ReturnParameters>
</ParametersFn>

 

This function uses one of the core templates, ASOBO_Auto_Define_Positions_And_Tooltips_Helper. This is a helper function which defines positions based on the POS_# arguments with the expected syntax and a tooltip (see Creating Interaction Tooltips for more information).

 

It is worth noting that the order of the positions is given by axis. If the switch moves on the vertical axis, then the positions should be listed from the bottom to the top. If the switch moves on the horizontal axis, then the positions should be listed from the left to the right.

 

 

Discreet State Position Configurations

When using the ASOBO_Auto_Define_Positions_And_Tooltips_Helper there are some additional things to consider about how the positions will be used and how they can be manipulated for specific cases where the discreet states are not simple single clicks.

 

  • Position Animation

    Each position has a default animation position assigned to it. The value is expressed as a percent of the animation and will default to the position index (starting at 0) divided by the last position index multiplied by 100 (to convert it to percent). However you can override this default value by setting the parameter POS_#_ANIM_PERCENT where the value is the expected animation position in percent for the given position name (#).

 

  • Momentary Positions

    Some positions are meant to be "momentary", ie: when the switch is moved to that position it will then be switched to another position, after release, using some spring mechanism. For switches like this, you can use the parameter POS_#_MOMENTARY_RELEASE_TARGET where # is the name (index) of the position you want to make momentary. The value you supply the parameter is the position to "spring" to when the interaction is released. Here is an example:

    <ParametersFn Name="MYFUNCTION_VALVE_Settings">
        <ReturnParameters>
            <POS_CLOSE_MOMENTARY_RELEASE_TARGET>NEUTRAL</POS_CLOSE_MOMENTARY_RELEASE_TARGET>
            <POS_OPEN_MOMENTARY_RELEASE_TARGET>NEUTRAL</POS_OPEN_MOMENTARY_RELEASE_TARGET>
            <UseParametersFn Name="ASOBO_Auto_Define_Positions_And_Tooltips_Helper">
                <POS_0>CLOSE</POS_0>
                <POS_1>NEUTRAL</POS_1>
                <POS_2>OPEN</POS_2>
            </UseParametersFn>
        </ReturnParameters>
    </ParametersFn>

    If you include the POS_#_MOMENTARY_RELEASE_TARGET parameter, you get access to other parameters that can further configure the momentary behavior:

    • POS_#_MOMENTARY_MIN_DURATION
      The minimum duration - in seconds - that this position will stay in the "momentary" state before springing back to the release target (if triggered externally, or using the Inc/Dec interaction events). Note that the default value is 0.75 but it can be changed for all positions by overriding the value of DEFAULT_MOMENTARY_MIN_DURATION.

    • POS_#_MOMENTARY_CONDITION
      This defines a condition that, when it resolves as "true", will enable the momentary behavior. Input condition can be something like a SimVar or some RPN.

 

  • Position Gates

    Most discrete state templates are gated by default, which means that you can't go from the first position to the last position in a single big movement: each state will block the input for a moment to avoid unintended position change (only levers work differently, as they don’t have any gate by default). So, each position acts as a gate and can be configured as such using POS_#_GATE_DIRECTION with # being the position name (index) we want to add a gate to. The value of this parameter has to be one of the following:

    • Both - Gate will be blocking the interaction in both directions

    • Inc - Gate will be blocking the interaction when incrementing the position

    • Dec - Gate will be blocking the interaction when decrementing the position

    For example:

    <ReturnParameters>
        <Condition Valid="AUTO_DEFINE_GATE">
            <POS_#CUR_STATE_ID#_GATE_DIRECTION>Both</POS_#CUR_STATE_ID#_GATE_DIRECTION>
            <POS_#CUR_STATE_ID#_ANIM_PERCENT Process="Int">#CUR_ID# #LAST_STATE_INDEX# / 100 * near</POS_#CUR_STATE_ID#_ANIM_PERCENT>
        </Condition>
    </ReturnParameters>

 

 

Continuous State Interactions

A continuous state is a control that moves smoothly from one position to another, like when you turn a knob or move a lever. Using the core templates, you can deal with this kind of interaction in two ways: as a bounded continuous state, or an infinite continuous state. The templates used for these two types of continuous interactions are very easy to use, as shown in the examples below.

 

 

Bound State Interaction

The following is an example of a bound state continuous interaction for a lever using ASOBO_CT_Lever_Template:

<UseTemplate Name="ASOBO_CT_Lever_Template">
    <IN_BASE_NAME>MAIN_PANEL_FOOT_AIR</IN_BASE_NAME>
    <IE_NAME>FOOT_AIR</IE_NAME>
</UseTemplate>

The following is an example of a bound state continuous interaction for a knob using ASOBO_CT_Knob_Finite_Template:

<UseTemplate Name="ASOBO_CT_Knob_Finite_Template">
    <IN_BASE_NAME>MAIN_PANEL_KNOB_LIGHT_AFDS_FLOOD_1</IN_BASE_NAME>
    <IE_NAME>AFDS_FLOOD</IE_NAME>
    <GET_SETTINGS_CONFIG>ASOBO_Glareshield_Light_Intensity_Settings_Config</GET_SETTINGS_CONFIG>
    <LIGHT_ID>@LIGHTING_Light_Glareshield_AFDS</LIGHT_ID>
</UseTemplate>

 

 

Infinite State Interaction

The following is an example of an infinite state continuous interaction for a knob using ASOBO_CT_Knob_Infinite_Template:

<UseTemplate Name="ASOBO_CT_Knob_Infinite_Template">
    <IN_BASE_NAME>GLSHD_MCP_KNOB_HEADING_SEL_1</IN_BASE_NAME>
    <IE_NAME>HEADING_SEL</IE_NAME>
    <GET_CONFIG_PARAMETERS>ASOBO_FCC_Heading_Var_Config</GET_CONFIG_PARAMETERS>
</UseTemplate>

 

 

Button Interactions

Possibly the most common interaction in any cockpit will be the simple act of pressing a button. This is also one of the simplest interactions to set up, since they are only designed to send a single event and (at their simplest) only have one state (pressed/not pressed). In the following example we use the ASOBO_CT_Button_Template where we specify what happens when the button is clicked - using ON_EVENT - and/or when the button is released - using ON_RELEASE (essentially a "stateless" button that simply does one thing when pressed and/or released):

<UseTemplate Name="ASOBO_CT_Button_Template">
    <IN_BASE_NAME>FRNT_PUSH_AT_DISENGAGE_LIGHT</IN_BASE_NAME>
    <IE_NAME>AT_DISENGAGE</IE_NAME>
    <ON_EVENT>0 @Set_AT_Disengaged</ON_EVENT>
</UseTemplate>

This template also permits the following parameters, which can be useful when you require more control over the way the button is pressed or held:

  • ON_LONG_PRESS_EVENT - This parameter takes a snippet of RPN code which will be executed after a set time has passed since the button was pressed and held down. This time is defined using the LONG_PRESS_DURATION parameter.
  • ON_BUTTON_HELD - This parameter takes a snippet of RPN code which will be executed every frame, for as long as the button is held down.

 

 

Momentary State Buttons

A momentary state button is one which has a different state depending on whether they are they are pushed or released, ie: for as long as the button is being held down then one state will be maintained, but releasing the button and it goes back to the initial state again. Test buttons usually have this behavior, for example:

<UseTemplate Name="ASOBO_CT_Button_Template">
    <IN_BASE_NAME>OVHD_LE_DEVICES_PUSH_TEST_1</IN_BASE_NAME>
    <IE_NAME>LE_DEVICES_TEST</IE_NAME>
    <GET_MOMENTARY_SETTINGS>MYFUNCTION_Test_Settings</GET_MOMENTARY_SETTINGS>
</UseTemplate>

 

 

Toggleable State Buttons

A toggleable state button is one which can be toggled between 2 or more discreet states. For example, if the button controls 3 states, then pressing the button once will change the state from 1 to 2, pressing again will go from 2 to 3 and then pressing again will go from 3 back to 1 again. For example:

<UseTemplate Name="ASOBO_CT_Button_Template">
    <IN_BASE_NAME>OVHD_LE_DEVICES_PUSH_TEST_1</IN_BASE_NAME>
    <IE_NAME>LE_DEVICES_TEST</IE_NAME>
    <GET_MOMENTARY_SETTINGS>MYFUNCTION_Test_Settings_Toggles</GET_MOMENTARY_SETTINGS>
</UseTemplate>

Note that you can create a simple two state toggle by adding the <TOGGLEABLE/> and setting it to "true". This will then make the button act in the following way:

  • pressing the button toggles from an unpressed state to a pressed state and maintains the button "locked" in a pressed state.
  • pressing the button again, "unlocks" the button and it goes from a pressed state back to an unpressed state.

 

 

Simple Interactions

In some cases, you will want to have an action happen without actually tieing it to any particular animation. This is where simple interactions are useful, as they are exclusively designed to be used for interactions with no animations. For example in many Microsoft Flight Simulator 2024 aircraft there are invisible volumes which are used to toggle the visibility of the yoke: this would be considered a simple interaction, and uses the ASOBO_CT_Simple_Interaction_Template template:

<UseTemplate Name="ASOBO_CT_Simple_Interaction_Template">
    <IN_BASE_NAME>HANDLING_YOKE_HIDER_1_STATIC</IN_BASE_NAME>
    <IE_NAME>HIDER</IE_NAME>
    <ON_EVENT>(&gt;B:VARIABLE_YOKE_HIDDEN_Toggle)</ON_EVENT>
</UseTemplate>

 

 

Merged Interactions

In many cases you will have items in the cockpit which require two or more simultaneous interaction events. For example, if you have a button tied to a knob or or a button tied to a lever. For these interactions the most important template it .

 

Some Interactions are merged together to make it simplify the interaction (ex: button on a knob or buttons tied to a lever). For these we use a parameter function called ASOBO_Add_Button_Helper, which will add a "button" interaction to any other interaction template that you use.

 

Here is a simple knob with a button example:

<UseTemplate Name="ASOBO_CT_Knob_Template">
    <IN_BASE_NAME>GLSHD_EFIS_KNOB_RANGE</IN_BASE_NAME>
    <IE_NAME>Range</IE_NAME>
    <GET_SETTINGS>MYFUNCTION_Range_Settings</GET_SETTINGS>
    <UseParametersFn Name="ASOBO_Add_Button_Helper">
        <SaveParameters ID="Append_With_Button">
            <IE_NAME>TFC</IE_NAME>
            <ANIM_NAME>GLSHD_EFIS_PUSH_TFC</ANIM_NAME>
            <GET_SETTINGS>MYFUNCTION_HIDDEN_Settings</GET_SETTINGS>
            <IE_TOOLTIP_DESCRIPTION_ID>@TT_Package_Project.ACTION.EFIS_PUSH_TFC</IE_TOOLTIP_DESCRIPTION_ID>
        </SaveParameters>
    </UseParametersFn>
</UseTemplate>

IMPORTANT! The <SaveParameters> "ID" attribute must be "Append_With_Button" otherwise the merged interaction will not work correctly.

 

 

Covered Interactions

In most cockpits there will be certain buttons or switches that have covers over them to prevent them being interacted with by accident. For these items you can create a special type of merged interaction that uses the ASOBO_Add_Cover_Helper template to add a cover that the user can flip up to be able to interact with the main button/switch, or flip down to prevent further interactions. For example:

<UseTemplate Name="ASOBO_CT_Switch_Template">
    <IN_BASE_NAME>OVHD_PASS_OXYGEN_SWITCH_MODE_1</IN_BASE_NAME>
    <IE_NAME>PASS_OXYGEN</IE_NAME>
    <UseParametersFn Name="ASOBO_Add_Cover_Helper">
        <SaveParameters ID="Append_With_Cover">
            <IN_BASE_NAME>OVHD_PASS_OXYGEN_SWITCH_MODE_COVER_1</IN_BASE_NAME>
        </SaveParameters>
    </UseParametersFn>
    <GET_SETTINGS>ASOBO_ON_NORMAL_Settings</GET_SETTINGS>
    <FORCE_POSITION_WHEN_COVER_CLOSED>NORMAL</FORCE_POSITION_WHEN_COVER_CLOSED>
</UseTemplate>

IMPORTANT! The <SaveParameters> "ID" attribute must be "Append_With_Cover" otherwise the merged interaction will not work correctly.

 

It is worth noting that the only <SaveParameters> that you need to give is the IN_BASE_NAME for the cover. The input event will be defined automatically based on the interaction it covers, which will depend on the initial template (knob, button, switch). Also note that using the ASOBO_Add_Cover_Helper template gives you access to an additional parameter: <FORCE_POSITION_WHEN_COVER_CLOSED>. This permits you to add in the state name to use as the "default" state that the knob/switch/button will be set to when the cover is closed.