Input helpers

From FlightGear wiki
Jump to navigation Jump to search

This page is about Nasal script code for input devices like joysticks, yokes, throttle quadrands and pedals.

While small scripts can be easily added directly into joystick <binding>, larger code blocks should be organized a bit differently. As always: "do not repeat yourself". This means, to make everyones live easier, code should not be copy&pasted but put into a "central" place as functions or classes and be called whenever, wherever needed. This way, maintenance has to be done only in one place.

input_helpers namespace

Input helper code should be stored in FGDATA/Nasal/input_helpers/<myvendor>.nas

To avoid clashes, there should be one file per vendor and in each of these files a namespace (hash) for this vendor shall be created.

See honeycomb.nas for an example:

# 
# Helpers for Honeycomb input devices
#

# !!! Abbreviated sample !!! 
# Check FGDATA repository for latest full version

# namespace
var honeycomb = {};

# Helper for the Honeycomb Alpha Yoke
honeycomb["alpha"] = {
    new: func(cfgnode) {
        var m = {
            parents: [me, input_helpers.config_manager.new(cfgnode)],
        };
        return m;
    },
    # abreviated file
};

config_manager - supporting config variants for a device

The input_helpers.config_manager class is designed to allow configuration variants for an input device to be defined within a single XML config file.

Why? Take the Honeycomb Bravo throttle quadrant as an example. It supports six levers with replaceable lever "heads", one set for airliners and another one for GA single and dual engine models, so you can "configure" the hardware with levers from single throttle/mixture up to four jet engines.

Now, you need a way to tell FlightGear, what levers you put onto your throttle quadrant and how to interprete the lever inputs. To avoid juggling with XML files, we simply put the limited number of variants into the XML and let the config_manager do the rest.

If XML files containing <config-variants> are loaded during startup, config_manager will show a popup hint about this fact and open a dialog to select the desired config variant. The selection is added to aircraft.data and safed for convenience.

<?xml version="1.0"?>
<PropertyList>
  <vendor-id>honeycomb</vendor-id>
  <model-id>bravo</model-id>
  <name>Honeycomb Aeronautical Bravo Throttle Quadrant</name>

  <debug-events type="bool">false</debug-events>
  <hid-debug-raw type="bool">false</hid-debug-raw>
  
<!-- 
  we need <nasal> to load the config_manager or a vendor
  specific derived class of it
-->
  <nasal>
    <open>
      <![CDATA[
      print("Honeycomb Bravo Nasal (event) open");
      bravo = input_helpers.honeycomb.bravo.new(cmdarg());
      ]]>
    </open>
    <close>
      <![CDATA[
      print("Honeycomb Bravo Nasal (event) close");
      if (ishash(bravo) and isfunc(bravo['close']))
        bravo.close(cmdarg());
      ]]>
    </close>
  </nasal>
<!--
  now we can add <config-variants>
-->
  <config-variants>
    <variant>
<!-- id must be a single word, no special chars, useable as hash key in Nasal -->
      <id>jet2</id> 
<!-- text for the GUI dialog -->
      <description>Airliner (two engines)</description>

<!-- 
  add property mappings for this variant. 
  <input> is used in the <event> elements
  <output> is the target property input will be aliased to
-->
      <mapping>
        <input>/input/honeycomb/bravo/lever[0]</input>
        <output>/controls/flight/speed-brake</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[2]</input>
        <output>/controls/engines/engine[0]/throttle</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[3]</input>
        <output>/controls/engines/engine[1]/throttle</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever-down-button[2]</input>
        <output>/controls/engines/engine[0]/cutoff</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever-down-button[3]</input>
        <output>/controls/engines/engine[1]/cutoff</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/reverser[2]</input>
        <output>/controls/engines/engine[0]/reverser-cmd</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/reverser[3]</input>
        <output>/controls/engines/engine[1]/reverser-cmd</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[5]</input>
        <output>/controls/flaps-lever-continuous</output>
      </mapping>
    </variant>
    <variant>
      <id>jet4</id>
      <description>Airliner (four engines)</description>
      <mapping>
        <input>/input/honeycomb/bravo/lever[0]</input>
        <output>/controls/flight/speed-brake</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[1]</input>
        <output>/controls/engines/engine[0]/throttle</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[2]</input>
        <output>/controls/engines/engine[1]/throttle</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[3]</input>
        <output>/controls/engines/engine[2]/throttle</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[4]</input>
        <output>/controls/engines/engine[3]/throttle</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever-down-button[1]</input>
        <output>/controls/engines/engine[0]/cutoff</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever-down-button[2]</input>
        <output>/controls/engines/engine[1]/cutoff</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever-down-button[3]</input>
        <output>/controls/engines/engine[2]/cutoff</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever-down-button[4]</input>
        <output>/controls/engines/engine[3]/cutoff</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/reverser[1]</input>
        <output>/controls/engines/engine[0]/reverser-cmd</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/reverser[2]</input>
        <output>/controls/engines/engine[1]/reverser-cmd</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/reverser[3]</input>
        <output>/controls/engines/engine[2]/reverser-cmd</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/reverser[4]</input>
        <output>/controls/engines/engine[3]/reverser-cmd</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[5]</input>
        <output>/controls/flaps-lever-continuous</output>
      </mapping>
    </variant>
    <variant>
      <id>tm</id>
      <description>Throttle/Mixture</description>
      <mapping>
        <input>/input/honeycomb/bravo/lever[0]</input>
        <output>/controls/engines/engine[0]/throttle</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[1]</input>
        <output>/controls/engines/engine[0]/mixture</output>
      </mapping>
    </variant>
    <variant>
      <id>tpm</id>
      <description>Throttle/Prop/Mixture</description>
      <mapping>
        <input>/input/honeycomb/bravo/lever[0]</input>
        <output>/controls/engines/engine[0]/throttle</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[1]</input>
        <output>/controls/engines/engine[0]/propeller-pitch</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[2]</input>
        <output>/controls/engines/engine[0]/mixture</output>
      </mapping>
    </variant>
    <variant>
      <id>ttmm</id>
      <description>Throttle/Mixture (two engines)</description>
      <mapping>
        <input>/input/honeycomb/bravo/lever[0]</input>
        <output>/controls/engines/engine[0]/throttle</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[1]</input>
        <output>/controls/engines/engine[1]/throttle</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[2]</input>
        <output>/controls/engines/engine[0]/mixture</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[3]</input>
        <output>/controls/engines/engine[1]/mixture</output>
      </mapping>
    </variant>
    <variant>
      <id>ttppmm</id>
      <description>Throttle/Prop/Mixture (two engines)</description>
      <mapping>
        <input>/input/honeycomb/bravo/lever[0]</input>
        <output>/controls/engines/engine[0]/throttle</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[1]</input>
        <output>/controls/engines/engine[1]/throttle</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[2]</input>
        <output>/controls/engines/engine[0]/propeller-pitch</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[3]</input>
        <output>/controls/engines/engine[1]/propeller-pitch</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[4]</input>
        <output>/controls/engines/engine[0]/mixture</output>
      </mapping>
      <mapping>
        <input>/input/honeycomb/bravo/lever[5]</input>
        <output>/controls/engines/engine[1]/mixture</output>
      </mapping>
    </variant>
  </config-variants>
<!-- events cut; see latest version in FGDATA repository -->
</PropertyList>