Howto:Reassign keyboard bindings

WIP.png Work in progress
This article or section will be worked on in the upcoming hours or days.
See history for the latest developments.

A common request is how to change keys to do different commands. FlightGear makes this as easy as editing an XML file, and possibly adding a parameter to point FG to the new XML file.

In general, the list of keyboard commands is stored in the property tree and is loaded at startup or when the menu option "Debug -> Reload input" is selected. The main list of commands is available in $FG_ROOT/keyboard.xml, but each aircraft can add/change its own bindings through its -set.xml file, and additional config files can do the same.

Adding or modifying key bindings

Keyboard bindings are usually fairly simple. They consist of a <key> node (with a corresponding index), optional <name> and <desc> nodes, and one or more <binding>s. A very simple example is the default for Ctrl+V:

 <key n="22">
  <name>Ctrl-V</name>
  <desc>Select initial view (view 0)</desc>
  <binding>
   <command>property-assign</command>
   <property>/sim/current-view/view-number</property>
   <value>0</value>
  </binding>
 </key>

The initial tag (<key n="22">) is used to identify the keycode; see the next section for how to find it for other keys. If this is not specified, FG won't have an accurate view of which key it is supposed to represent. The next two tags, <name> and <desc>, simply are there to describe the key and its function, respectively. They are not required but might be used for showing keyboard help information or other user-display uses. The <binding> tag is the functional aspect that gets executed when the key is pressed. The above example would be equivalent to this Nasal code:

setprop("/sim/current-view/view-number", 0)

For more on bindings and their different commands see the article about them: bindings.

Here's a more complex binding, also from keyboard.xml, for /:

 <key n="47">
  <name>/</name>
  <desc>Open property browser</desc>
  <binding>
   <condition>
    <not>
     <property>/sim/input/property-key-handler</property>
    </not>
   </condition>
   <command>nasal</command>
   <script>gui.property_browser()</script>
  </binding>
  <binding>
   <condition>
    <property>/sim/input/property-key-handler</property>
   </condition>
   <command>nasal</command>
   <script>prop_key_handler.start()</script>
  </binding>
 </key>

This now has two bindings that execute based on a <condition> (see: conditions). The first executes if the property key handler development extension is not enabled, the second if it is enabled. Both execute a Nasal command: one to open the property browser, the other to start capturing keys (which will also open a browser if the user enters and path and hits :).

Another common element is the <mod-up> event, which happens when the button is released. For example, the S key fires the starter only as long as it is held down, via complementary commands on press and release:

 <key n="115">
  <name>s</name>
  <desc>Fire Starter on Selected Engine(s)</desc>
  <binding>
   <command>nasal</command>
   <script>controls.startEngine(1)</script>
  </binding>
  <mod-up>
   <binding>
    <command>nasal</command>
    <script>controls.startEngine(0)</script>
   </binding>
  </mod-up>
 </key>

Other similar modifiers are the following:

  • mod-up: release the key
  • mod-shift: if Shift is held down during event
  • mod-ctrl: if Ctrl is held down during event
  • mod-alt: if Alt is held down (rare)
  • mod-meta: if Meta is held down (rare)
  • mod-super: if Super is held down (very rare)
  • mod-hyper: if Hyper is held down (very rare)

(FIXME: describe more, esp. interaction with the key code...)

Finding keycodes

As mentioned in keyboard.xml, "regular keycodes go up to 255; special keys start at 256, and can be calculated by adding 256 to the GLUT key value in glut.h."

For printable/ASCII keys (e.g. any letter of the alphabet, number, or symbol found on a keyboard), this is simply the ASCII value of the key.

Using the property browser

Tip  You may want to press p to pause the simulation first in order to not mess up something.

One of the easier ways to find out the key codes is to open up the property browser by pressing / or Shift+7 and go to

  • /devices/status/keyboard/event/
    • key= 'A' (int) – The key code of the currently or last pressed key
    • modifier/ – Key modifiers of the currently or last pressed key
      • alt= 'false' (bool)
      • ctrl= 'false' (bool)
      • hyper= 'false' (bool)
      • meta= 'false' (bool)
      • shift= 'true' (bool)
      • super= 'false' (bool)
    • pressed= 'true' (bool) – True if the key is currently pressed down

The above will be the values if you hold down Shift+A.

Using a nasal script

An alternative would be to use Nasal (in the Nasal Console or REPL), with a simple script like this that will "pop up" the result:

gui.popupTip(`a`); # replace with the key you want to test

No matter what method you use, for "a" (lowercase), you should get 97; "A" (uppercase) is 67; "0" would be 48.

By looking in keyboard.xml

For non-printable characters, the simplest option is to look for the specific key (or control key) in keyboard.xml. For example, Ctrl+N is found on line 154 in keyboard.xml, which reads:

<key n="14">
  <name>Ctrl-N</name>
  ...
</key>

Thus the key code is 14 (as well as the index of the key binding).

By enabling special debugging output

If the key isn't listed in keyboard.xml, the last option is to enable some helpful output to see what the correct keycode is. Uncomment flightgear/fgdata/next/keyboard.xml#l39 and run with the --console option, if on windows, and look at the console to see each keycode for each key. Make sure you can see the output as you press keys, or you won't know which is which! When I press and release a, I get this output:

{ key: 97, modifier: { meta: 0, shift: 0, alt: 0, super: 0, ctrl: 0, hyper: 0 }, pressed: 1 }
{ key: 97, modifier: { meta: 0, shift: 0, alt: 0, super: 0, ctrl: 0, hyper: 0 }, pressed: 0 }

This shows that key 97 was pressed (without any modifiers) and then released. This view can also help with combining modifiers, like mod-meta above.

Adding custom bindings

The "easiest" option for many is to edit keyboard.xml in place, because it just works. If you do this, make sure to keep a backup of it, in case you need to revert back to the default setup, or simply download it from fgdata-old (v3.0) or fgdata cutting edge.

Another option, that ends up cleaner, is using a config file. These are specified on the commandline with --config, like this:

fgfs --config=/Users/philosopher/Documents/FlightGear/keyboard-config.xml

These can be formatted in the same way as keyboard.xml, with the exception of requiring input and keyboard tags, so it looks like this:

<?xml version="1.0"?>
<PropertyList>
<input><keyboard>
    <key n="....">...</key>
    <!-- etc. -->
</keyboard></input>
</PropertyList>

This makes sure it writes to the correct place in the tree, viz. /input/keyboard/.

This allows you to more easily keep several different files for different types of setups, without having to rename them before starting FG, you only need to change the filename passed in the --config= option.

Related content

Wiki articles

Forum topics with layouts

Several users have modified the default keyboard bindings and shared the results.

Complete layouts

Individual bindings