<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.flightgear.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Macnab</id>
	<title>FlightGear wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.flightgear.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Macnab"/>
	<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/Special:Contributions/Macnab"/>
	<updated>2026-04-15T15:38:49Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.6</generator>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Talk:Canvas_SVG_parser&amp;diff=65290</id>
		<title>Talk:Canvas SVG parser</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Talk:Canvas_SVG_parser&amp;diff=65290"/>
		<updated>2013-12-06T04:08:09Z</updated>

		<summary type="html">&lt;p&gt;Macnab: Created page with &amp;quot;Where is Aircraft/C-130J so one can experiment? Not in fgdata. (Unless I somehow lost it.) ~~~~&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Where is Aircraft/C-130J so one can experiment? Not in fgdata. (Unless I somehow lost it.)&lt;br /&gt;
[[User:Macnab|Macnab]] ([[User talk:Macnab|talk]]) 04:08, 6 December 2013 (UTC)&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61783</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61783"/>
		<updated>2013-07-25T15:08:39Z</updated>

		<summary type="html">&lt;p&gt;Macnab: /* A practical example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
The secret is in having a method of preventing a button from repeating until our chosen time has elapsed. It is possible, but messy, especially if you are doing this with a number of buttons, to do it inside the code for each button. It is much better to create a new type of button code. For this we need a class, and then create instances of this class for each controlled button. This, incidentally, is OOP, or Object Oriented Programming.&lt;br /&gt;
&lt;br /&gt;
Here is thew code to create the new class. It is called timedControl. I have added (unnecessary) open lines between each member of the class to make understanding easier.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var timedControl = {&lt;br /&gt;
      last_busy: 0,&lt;br /&gt;
&lt;br /&gt;
      timeout_dur: 1.0,&lt;br /&gt;
&lt;br /&gt;
      new: func() {&lt;br /&gt;
          return { parents:[me] };&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      _call: func(fn, arg) {&lt;br /&gt;
        if (!arg) { me.last_busy = 0; return; }&lt;br /&gt;
        var time = systime();&lt;br /&gt;
        if (time &amp;lt; me.timeout_dur + me.last_busy) return;&lt;br /&gt;
        me.last_busy = time;&lt;br /&gt;
        return call(fn, [arg], me);&lt;br /&gt;
      }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's assume that we have a function, ''myFunction'', which must only repeat every 0.25 seconds. We create it with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var myFunction = timedControl.new();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
While creating myFunction, it sets ''last_busy'' to 0 (line 2) and ''time_dur'' to 1.0 (line 4).&lt;br /&gt;
&lt;br /&gt;
and set the repeat rate to 0.25 seconds with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
''var myFunction = timedControl.new()'' calls lines 6, 7, 8 of ''timedControl''. This creates a new instance of ''timedControl'' named ''myFunction'' and returns a pointer to it. Now, whenever you use ''myControl'' it will point to where it exists in memory.&lt;br /&gt;
&lt;br /&gt;
''myFunction.timeout_dur = 0.25''. ''myFunction'' points to the function in memory, ''.timout_dur'' then points to where ''timeout_dur'' exists in memory and changes its value to 0.25. Line 4 of the code set it to 1.0, just so it has ''a'' value.&lt;br /&gt;
&lt;br /&gt;
Now we need something for the joystick button to call. Here we are using ''do'', but you could just as easily use ''perform'', or ''activate'', or anything else.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.do =  func(step) me._call(me._do, step);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, ''step'' is 1 for button pressed, and 0 for mod-up, pretty much standard for repeatable button code.&lt;br /&gt;
&lt;br /&gt;
When ''myFunction.do'' is called it executes ''me._call(me._do, step)''. It calls lines 10 onwards of ''timedControl'', passing ''me._do'' and ''step'' as parameters. The ''me'' is the way ''timedControl'' references itself, so if you have multiple buttons using the method, using ''me'' makes sure that you are always using the right ''timeout_dur'' or ''last_busy'', etc.&lt;br /&gt;
&lt;br /&gt;
Now let's look at lines 10 onwards of ''timedControl''. &lt;br /&gt;
&lt;br /&gt;
Line 10 receives the call ''_call'' with the parameters ''me._do'' and ''step'', which it renames to ''fn'' and ''arg.'' &lt;br /&gt;
&lt;br /&gt;
Line 11: If the value of ''arg'', and hence the value of ''step'' is 0, it means mod-up (the button was released.) It sets the value of ''last_busy'' to 0 and returns. ''It does nothing further''.&lt;br /&gt;
&lt;br /&gt;
Line 12: Sets the variable ''time'' to ''systime()''. This is the current date and time, accurate to fractions of a millisecond.&lt;br /&gt;
&lt;br /&gt;
Line 13: Remember, ''last_busy'' was initialised to 0. This line checks if the sum of ''timeout_dur'' and ''last_busy'' is more than the current time. It isn't, since ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
Line 14: ''last_busy'' is set to current time.&lt;br /&gt;
&lt;br /&gt;
Line 15: The function returns, calling ''fn'' with parameter ''arg''.&lt;br /&gt;
&lt;br /&gt;
Now ''fn'' is ''me._do''. ''me'' is of course ''myFunction''. So it is going to call a function by the name of ''myFunction._do''. This is the actual code that must be executed when the joystick button is pressed. So we are going to need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction._do =  func(step) {&lt;br /&gt;
  ....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So your code gets executed. The button is still pressed. A little while later (based on system repeat rate) the button is called again and ''me._call'' is called again.&lt;br /&gt;
&lt;br /&gt;
Line 12: Updates the value of ''time''. It is now 2 milliseconds later.&lt;br /&gt;
&lt;br /&gt;
Line 13: ''last_busy'' was set to the current time last time through the call. Now ''time'' is less than ''last_busy'' + 0.25, so the call returns. Your code is not executed.&lt;br /&gt;
&lt;br /&gt;
This will continue until 0.25 seconds has elapsed. Then line 15 will not return, and your code will be executed. So, as long as the button is pressed, your code is repeated every 0.25 seconds.&lt;br /&gt;
&lt;br /&gt;
Now you release the button. mod-up passes 0 as ''step''. Now the important line is 11. ''arg'' is 0, so ''last_busy'' is reset to 0, and the call returns. If you press the button again, the whole cycle restarts again because ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
==  The joystick end of things ==&lt;br /&gt;
All this code is of course in a Nasal file which you create. Give it a suitable name, based on your joystick name, for example logitechlib.nas. Put it in the same folder as your joystick xml file.&lt;br /&gt;
&lt;br /&gt;
Then add this at the top of your xml file, just after all the &amp;lt;name&amp;gt; entries&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        if (!contains(globals, &amp;quot;logitechlib&amp;quot;)) {&lt;br /&gt;
          io.load_nasal(getprop(&amp;quot;/sim/fg-root&amp;quot;) ~ &amp;quot;/Input/Joysticks/Saitek/logitechlib.nas&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make all the affected buttons repeatable. Then use this for the bindings&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;logitechlib.myFunction.do(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
          &amp;lt;script&amp;gt;logitechlib.myFunction.do(0)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Making the declarations tidier ==&lt;br /&gt;
Currently, you need to do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = timedControl.new();&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
myFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It looks a bit neater if you have a helper function.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var createTimedControl = func(timeout, do) {&lt;br /&gt;
      var name = timedControl.new();&lt;br /&gt;
      name.timeout_dur = timeout;&lt;br /&gt;
      name.do = func(step) { name._call(do, step); };&lt;br /&gt;
      append(arrayTimedControls, name);&lt;br /&gt;
      return name;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = createTimedControl(0.25, var do = func(step) {&lt;br /&gt;
# Your code goes here&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== A practical example ==&lt;br /&gt;
We are going to use buttons to adjust the frequency of the NAV1 radio, up and down. We are going to have 3 speeds - adjust the decimals, adjust the units and adjust the tens. To do that, the joystick button passes +ve or -ve 1, or 2 for step. Mod-up is still 0, of course. It also pops the value up on the screen while adjusting. To implement all 3 steps rates, up and down, you will need (probably with the help of modifiers) 6 buttons.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
# 1 for decimals, 2 for integers&lt;br /&gt;
# +ve for up, -ve for down&lt;br /&gt;
var NAV1Freq = createTimedControl(0.25, var do = func(step) {&lt;br /&gt;
  var val = 0.05 * step;&lt;br /&gt;
  if (math.abs(step) == 2) val = val * 20;&lt;br /&gt;
  var curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr + val);&lt;br /&gt;
  curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  if (curr &amp;gt; 117.95) {&lt;br /&gt;
    curr = 108.00;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  if (curr &amp;lt; 108.00) {&lt;br /&gt;
    curr = 117.95;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  gui.popupTip(sprintf(&amp;quot;NAV1 %0.2f&amp;quot;,curr));&lt;br /&gt;
)};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61778</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61778"/>
		<updated>2013-07-25T12:14:33Z</updated>

		<summary type="html">&lt;p&gt;Macnab: /* A practical example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
The secret is in having a method of preventing a button from repeating until our chosen time has elapsed. It is possible, but messy, especially if you are doing this with a number of buttons, to do it inside the code for each button. It is much better to create a new type of button code. For this we need a class, and then create instances of this class for each controlled button. This, incidentally, is OOP, or Object Oriented Programming.&lt;br /&gt;
&lt;br /&gt;
Here is thew code to create the new class. It is called timedControl. I have added (unnecessary) open lines between each member of the class to make understanding easier.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var timedControl = {&lt;br /&gt;
      last_busy: 0,&lt;br /&gt;
&lt;br /&gt;
      timeout_dur: 1.0,&lt;br /&gt;
&lt;br /&gt;
      new: func() {&lt;br /&gt;
          return { parents:[me] };&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      _call: func(fn, arg) {&lt;br /&gt;
        if (!arg) { me.last_busy = 0; return; }&lt;br /&gt;
        var time = systime();&lt;br /&gt;
        if (time &amp;lt; me.timeout_dur + me.last_busy) return;&lt;br /&gt;
        me.last_busy = time;&lt;br /&gt;
        return call(fn, [arg], me);&lt;br /&gt;
      }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's assume that we have a function, ''myFunction'', which must only repeat every 0.25 seconds. We create it with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var myFunction = timedControl.new();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
While creating myFunction, it sets ''last_busy'' to 0 (line 2) and ''time_dur'' to 1.0 (line 4).&lt;br /&gt;
&lt;br /&gt;
and set the repeat rate to 0.25 seconds with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
''var myFunction = timedControl.new()'' calls lines 6, 7, 8 of ''timedControl''. This creates a new instance of ''timedControl'' named ''myFunction'' and returns a pointer to it. Now, whenever you use ''myControl'' it will point to where it exists in memory.&lt;br /&gt;
&lt;br /&gt;
''myFunction.timeout_dur = 0.25''. ''myFunction'' points to the function in memory, ''.timout_dur'' then points to where ''timeout_dur'' exists in memory and changes its value to 0.25. Line 4 of the code set it to 1.0, just so it has ''a'' value.&lt;br /&gt;
&lt;br /&gt;
Now we need something for the joystick button to call. Here we are using ''do'', but you could just as easily use ''perform'', or ''activate'', or anything else.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.do =  func(step) me._call(me._do, step);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, ''step'' is 1 for button pressed, and 0 for mod-up, pretty much standard for repeatable button code.&lt;br /&gt;
&lt;br /&gt;
When ''myFunction.do'' is called it executes ''me._call(me._do, step)''. It calls lines 10 onwards of ''timedControl'', passing ''me._do'' and ''step'' as parameters. The ''me'' is the way ''timedControl'' references itself, so if you have multiple buttons using the method, using ''me'' makes sure that you are always using the right ''timeout_dur'' or ''last_busy'', etc.&lt;br /&gt;
&lt;br /&gt;
Now let's look at lines 10 onwards of ''timedControl''. &lt;br /&gt;
&lt;br /&gt;
Line 10 receives the call ''_call'' with the parameters ''me._do'' and ''step'', which it renames to ''fn'' and ''arg.'' &lt;br /&gt;
&lt;br /&gt;
Line 11: If the value of ''arg'', and hence the value of ''step'' is 0, it means mod-up (the button was released.) It sets the value of ''last_busy'' to 0 and returns. ''It does nothing further''.&lt;br /&gt;
&lt;br /&gt;
Line 12: Sets the variable ''time'' to ''systime()''. This is the current date and time, accurate to fractions of a millisecond.&lt;br /&gt;
&lt;br /&gt;
Line 13: Remember, ''last_busy'' was initialised to 0. This line checks if the sum of ''timeout_dur'' and ''last_busy'' is more than the current time. It isn't, since ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
Line 14: ''last_busy'' is set to current time.&lt;br /&gt;
&lt;br /&gt;
Line 15: The function returns, calling ''fn'' with parameter ''arg''.&lt;br /&gt;
&lt;br /&gt;
Now ''fn'' is ''me._do''. ''me'' is of course ''myFunction''. So it is going to call a function by the name of ''myFunction._do''. This is the actual code that must be executed when the joystick button is pressed. So we are going to need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction._do =  func(step) {&lt;br /&gt;
  ....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So your code gets executed. The button is still pressed. A little while later (based on system repeat rate) the button is called again and ''me._call'' is called again.&lt;br /&gt;
&lt;br /&gt;
Line 12: Updates the value of ''time''. It is now 2 milliseconds later.&lt;br /&gt;
&lt;br /&gt;
Line 13: ''last_busy'' was set to the current time last time through the call. Now ''time'' is less than ''last_busy'' + 0.25, so the call returns. Your code is not executed.&lt;br /&gt;
&lt;br /&gt;
This will continue until 0.25 seconds has elapsed. Then line 15 will not return, and your code will be executed. So, as long as the button is pressed, your code is repeated every 0.25 seconds.&lt;br /&gt;
&lt;br /&gt;
Now you release the button. mod-up passes 0 as ''step''. Now the important line is 11. ''arg'' is 0, so ''last_busy'' is reset to 0, and the call returns. If you press the button again, the whole cycle restarts again because ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
==  The joystick end of things ==&lt;br /&gt;
All this code is of course in a Nasal file which you create. Give it a suitable name, based on your joystick name, for example logitechlib.nas. Put it in the same folder as your joystick xml file.&lt;br /&gt;
&lt;br /&gt;
Then add this at the top of your xml file, just after all the &amp;lt;name&amp;gt; entries&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        if (!contains(globals, &amp;quot;logitechlib&amp;quot;)) {&lt;br /&gt;
          io.load_nasal(getprop(&amp;quot;/sim/fg-root&amp;quot;) ~ &amp;quot;/Input/Joysticks/Saitek/logitechlib.nas&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make all the affected buttons repeatable. Then use this for the bindings&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;logitechlib.myFunction.do(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
          &amp;lt;script&amp;gt;logitechlib.myFunction.do(0)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Making the declarations tidier ==&lt;br /&gt;
Currently, you need to do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = timedControl.new();&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
myFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It looks a bit neater if you have a helper function.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var createTimedControl = func(timeout, do) {&lt;br /&gt;
      var name = timedControl.new();&lt;br /&gt;
      name.timeout_dur = timeout;&lt;br /&gt;
      name.do = func(step) { name._call(do, step); };&lt;br /&gt;
      append(arrayTimedControls, name);&lt;br /&gt;
      return name;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = createTimedControl(0.25, var do = func(step) {&lt;br /&gt;
# Your code goes here&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== A practical example ==&lt;br /&gt;
We are going to use buttons to adjust the frequency of the NAV1 radio, up and down. We are going to have 3 speeds - adjust the decimals, adjust the units and adjust the tens. To do that, the joystick button passes +ve or -ve 1, 2 or 3 for step. Mod-up is still 0, of course. It also pops the value up on the screen while adjusting. To implement all 3 steps rates, up and down, you will need (probably with the help of modifiers) 6 buttons.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
# 1 for decimals, 2 for integers, 3 for 10s integers&lt;br /&gt;
# +ve for up, -ve for down&lt;br /&gt;
var NAV1Freq = createTimedControl(0.25, var do = func(step) {&lt;br /&gt;
  var val = 0.05 * step;&lt;br /&gt;
  if (math.abs(step) == 2) val = val * 20;&lt;br /&gt;
  if (math.abs(step) == 3) val = val * 200;&lt;br /&gt;
  var curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr + val);&lt;br /&gt;
  curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  if (curr &amp;gt; 117.95) {&lt;br /&gt;
    curr = 108.00;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  if (curr &amp;lt; 108.00) {&lt;br /&gt;
    curr = 117.95;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  gui.popupTip(sprintf(&amp;quot;NAV1 %0.2f&amp;quot;,curr));&lt;br /&gt;
)};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61777</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61777"/>
		<updated>2013-07-25T12:10:59Z</updated>

		<summary type="html">&lt;p&gt;Macnab: /* Further expansion */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
The secret is in having a method of preventing a button from repeating until our chosen time has elapsed. It is possible, but messy, especially if you are doing this with a number of buttons, to do it inside the code for each button. It is much better to create a new type of button code. For this we need a class, and then create instances of this class for each controlled button. This, incidentally, is OOP, or Object Oriented Programming.&lt;br /&gt;
&lt;br /&gt;
Here is thew code to create the new class. It is called timedControl. I have added (unnecessary) open lines between each member of the class to make understanding easier.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var timedControl = {&lt;br /&gt;
      last_busy: 0,&lt;br /&gt;
&lt;br /&gt;
      timeout_dur: 1.0,&lt;br /&gt;
&lt;br /&gt;
      new: func() {&lt;br /&gt;
          return { parents:[me] };&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      _call: func(fn, arg) {&lt;br /&gt;
        if (!arg) { me.last_busy = 0; return; }&lt;br /&gt;
        var time = systime();&lt;br /&gt;
        if (time &amp;lt; me.timeout_dur + me.last_busy) return;&lt;br /&gt;
        me.last_busy = time;&lt;br /&gt;
        return call(fn, [arg], me);&lt;br /&gt;
      }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's assume that we have a function, ''myFunction'', which must only repeat every 0.25 seconds. We create it with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var myFunction = timedControl.new();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
While creating myFunction, it sets ''last_busy'' to 0 (line 2) and ''time_dur'' to 1.0 (line 4).&lt;br /&gt;
&lt;br /&gt;
and set the repeat rate to 0.25 seconds with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
''var myFunction = timedControl.new()'' calls lines 6, 7, 8 of ''timedControl''. This creates a new instance of ''timedControl'' named ''myFunction'' and returns a pointer to it. Now, whenever you use ''myControl'' it will point to where it exists in memory.&lt;br /&gt;
&lt;br /&gt;
''myFunction.timeout_dur = 0.25''. ''myFunction'' points to the function in memory, ''.timout_dur'' then points to where ''timeout_dur'' exists in memory and changes its value to 0.25. Line 4 of the code set it to 1.0, just so it has ''a'' value.&lt;br /&gt;
&lt;br /&gt;
Now we need something for the joystick button to call. Here we are using ''do'', but you could just as easily use ''perform'', or ''activate'', or anything else.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.do =  func(step) me._call(me._do, step);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, ''step'' is 1 for button pressed, and 0 for mod-up, pretty much standard for repeatable button code.&lt;br /&gt;
&lt;br /&gt;
When ''myFunction.do'' is called it executes ''me._call(me._do, step)''. It calls lines 10 onwards of ''timedControl'', passing ''me._do'' and ''step'' as parameters. The ''me'' is the way ''timedControl'' references itself, so if you have multiple buttons using the method, using ''me'' makes sure that you are always using the right ''timeout_dur'' or ''last_busy'', etc.&lt;br /&gt;
&lt;br /&gt;
Now let's look at lines 10 onwards of ''timedControl''. &lt;br /&gt;
&lt;br /&gt;
Line 10 receives the call ''_call'' with the parameters ''me._do'' and ''step'', which it renames to ''fn'' and ''arg.'' &lt;br /&gt;
&lt;br /&gt;
Line 11: If the value of ''arg'', and hence the value of ''step'' is 0, it means mod-up (the button was released.) It sets the value of ''last_busy'' to 0 and returns. ''It does nothing further''.&lt;br /&gt;
&lt;br /&gt;
Line 12: Sets the variable ''time'' to ''systime()''. This is the current date and time, accurate to fractions of a millisecond.&lt;br /&gt;
&lt;br /&gt;
Line 13: Remember, ''last_busy'' was initialised to 0. This line checks if the sum of ''timeout_dur'' and ''last_busy'' is more than the current time. It isn't, since ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
Line 14: ''last_busy'' is set to current time.&lt;br /&gt;
&lt;br /&gt;
Line 15: The function returns, calling ''fn'' with parameter ''arg''.&lt;br /&gt;
&lt;br /&gt;
Now ''fn'' is ''me._do''. ''me'' is of course ''myFunction''. So it is going to call a function by the name of ''myFunction._do''. This is the actual code that must be executed when the joystick button is pressed. So we are going to need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction._do =  func(step) {&lt;br /&gt;
  ....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So your code gets executed. The button is still pressed. A little while later (based on system repeat rate) the button is called again and ''me._call'' is called again.&lt;br /&gt;
&lt;br /&gt;
Line 12: Updates the value of ''time''. It is now 2 milliseconds later.&lt;br /&gt;
&lt;br /&gt;
Line 13: ''last_busy'' was set to the current time last time through the call. Now ''time'' is less than ''last_busy'' + 0.25, so the call returns. Your code is not executed.&lt;br /&gt;
&lt;br /&gt;
This will continue until 0.25 seconds has elapsed. Then line 15 will not return, and your code will be executed. So, as long as the button is pressed, your code is repeated every 0.25 seconds.&lt;br /&gt;
&lt;br /&gt;
Now you release the button. mod-up passes 0 as ''step''. Now the important line is 11. ''arg'' is 0, so ''last_busy'' is reset to 0, and the call returns. If you press the button again, the whole cycle restarts again because ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
==  The joystick end of things ==&lt;br /&gt;
All this code is of course in a Nasal file which you create. Give it a suitable name, based on your joystick name, for example logitechlib.nas. Put it in the same folder as your joystick xml file.&lt;br /&gt;
&lt;br /&gt;
Then add this at the top of your xml file, just after all the &amp;lt;name&amp;gt; entries&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        if (!contains(globals, &amp;quot;logitechlib&amp;quot;)) {&lt;br /&gt;
          io.load_nasal(getprop(&amp;quot;/sim/fg-root&amp;quot;) ~ &amp;quot;/Input/Joysticks/Saitek/logitechlib.nas&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make all the affected buttons repeatable. Then use this for the bindings&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;logitechlib.myFunction.do(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
          &amp;lt;script&amp;gt;logitechlib.myFunction.do(0)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Making the declarations tidier ==&lt;br /&gt;
Currently, you need to do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = timedControl.new();&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
myFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It looks a bit neater if you have a helper function.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var createTimedControl = func(timeout, do) {&lt;br /&gt;
      var name = timedControl.new();&lt;br /&gt;
      name.timeout_dur = timeout;&lt;br /&gt;
      name.do = func(step) { name._call(do, step); };&lt;br /&gt;
      append(arrayTimedControls, name);&lt;br /&gt;
      return name;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = createTimedControl(0.25, var do = func(step) {&lt;br /&gt;
# Your code goes here&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== A practical example ==&lt;br /&gt;
We are going to use buttons to adjust the frequency of the NAV1 radio, up and down. We are going to have 3 speeds - adjust the decimals, adjust the units and adjust the tens. To do that, the joystick button passes +ve or -ve 1, 2 or 3 for step. Mod-up is still 0, of course. It also pops the value up on the screen while adjusting. To implement all 3 steps rates, up and down, you will need (probably with the help of modifiers) 6 buttons.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var NAV1Freq = createTimedControl(0.25);&lt;br /&gt;
&lt;br /&gt;
## 1 for decimals, 2 for integers, 3 for 10s integers&lt;br /&gt;
NAV1Freq.do = func(step) me._call(me._do, step);&lt;br /&gt;
NAV1Freq._do = func(step) {&lt;br /&gt;
  var val = 0.05 * step;&lt;br /&gt;
  if (math.abs(step) == 2) val = val * 20;&lt;br /&gt;
  if (math.abs(step) == 3) val = val * 200;&lt;br /&gt;
  var curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr + val);&lt;br /&gt;
  curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  if (curr &amp;gt; 117.95) {&lt;br /&gt;
    curr = 108.00;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  if (curr &amp;lt; 108.00) {&lt;br /&gt;
    curr = 117.95;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  gui.popupTip(sprintf(&amp;quot;NAV1 %0.2f&amp;quot;,curr));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61776</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61776"/>
		<updated>2013-07-25T12:10:00Z</updated>

		<summary type="html">&lt;p&gt;Macnab: /* Making the declarations tidier */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
The secret is in having a method of preventing a button from repeating until our chosen time has elapsed. It is possible, but messy, especially if you are doing this with a number of buttons, to do it inside the code for each button. It is much better to create a new type of button code. For this we need a class, and then create instances of this class for each controlled button. This, incidentally, is OOP, or Object Oriented Programming.&lt;br /&gt;
&lt;br /&gt;
Here is thew code to create the new class. It is called timedControl. I have added (unnecessary) open lines between each member of the class to make understanding easier.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var timedControl = {&lt;br /&gt;
      last_busy: 0,&lt;br /&gt;
&lt;br /&gt;
      timeout_dur: 1.0,&lt;br /&gt;
&lt;br /&gt;
      new: func() {&lt;br /&gt;
          return { parents:[me] };&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      _call: func(fn, arg) {&lt;br /&gt;
        if (!arg) { me.last_busy = 0; return; }&lt;br /&gt;
        var time = systime();&lt;br /&gt;
        if (time &amp;lt; me.timeout_dur + me.last_busy) return;&lt;br /&gt;
        me.last_busy = time;&lt;br /&gt;
        return call(fn, [arg], me);&lt;br /&gt;
      }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's assume that we have a function, ''myFunction'', which must only repeat every 0.25 seconds. We create it with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var myFunction = timedControl.new();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
While creating myFunction, it sets ''last_busy'' to 0 (line 2) and ''time_dur'' to 1.0 (line 4).&lt;br /&gt;
&lt;br /&gt;
and set the repeat rate to 0.25 seconds with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
''var myFunction = timedControl.new()'' calls lines 6, 7, 8 of ''timedControl''. This creates a new instance of ''timedControl'' named ''myFunction'' and returns a pointer to it. Now, whenever you use ''myControl'' it will point to where it exists in memory.&lt;br /&gt;
&lt;br /&gt;
''myFunction.timeout_dur = 0.25''. ''myFunction'' points to the function in memory, ''.timout_dur'' then points to where ''timeout_dur'' exists in memory and changes its value to 0.25. Line 4 of the code set it to 1.0, just so it has ''a'' value.&lt;br /&gt;
&lt;br /&gt;
Now we need something for the joystick button to call. Here we are using ''do'', but you could just as easily use ''perform'', or ''activate'', or anything else.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.do =  func(step) me._call(me._do, step);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, ''step'' is 1 for button pressed, and 0 for mod-up, pretty much standard for repeatable button code.&lt;br /&gt;
&lt;br /&gt;
When ''myFunction.do'' is called it executes ''me._call(me._do, step)''. It calls lines 10 onwards of ''timedControl'', passing ''me._do'' and ''step'' as parameters. The ''me'' is the way ''timedControl'' references itself, so if you have multiple buttons using the method, using ''me'' makes sure that you are always using the right ''timeout_dur'' or ''last_busy'', etc.&lt;br /&gt;
&lt;br /&gt;
Now let's look at lines 10 onwards of ''timedControl''. &lt;br /&gt;
&lt;br /&gt;
Line 10 receives the call ''_call'' with the parameters ''me._do'' and ''step'', which it renames to ''fn'' and ''arg.'' &lt;br /&gt;
&lt;br /&gt;
Line 11: If the value of ''arg'', and hence the value of ''step'' is 0, it means mod-up (the button was released.) It sets the value of ''last_busy'' to 0 and returns. ''It does nothing further''.&lt;br /&gt;
&lt;br /&gt;
Line 12: Sets the variable ''time'' to ''systime()''. This is the current date and time, accurate to fractions of a millisecond.&lt;br /&gt;
&lt;br /&gt;
Line 13: Remember, ''last_busy'' was initialised to 0. This line checks if the sum of ''timeout_dur'' and ''last_busy'' is more than the current time. It isn't, since ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
Line 14: ''last_busy'' is set to current time.&lt;br /&gt;
&lt;br /&gt;
Line 15: The function returns, calling ''fn'' with parameter ''arg''.&lt;br /&gt;
&lt;br /&gt;
Now ''fn'' is ''me._do''. ''me'' is of course ''myFunction''. So it is going to call a function by the name of ''myFunction._do''. This is the actual code that must be executed when the joystick button is pressed. So we are going to need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction._do =  func(step) {&lt;br /&gt;
  ....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So your code gets executed. The button is still pressed. A little while later (based on system repeat rate) the button is called again and ''me._call'' is called again.&lt;br /&gt;
&lt;br /&gt;
Line 12: Updates the value of ''time''. It is now 2 milliseconds later.&lt;br /&gt;
&lt;br /&gt;
Line 13: ''last_busy'' was set to the current time last time through the call. Now ''time'' is less than ''last_busy'' + 0.25, so the call returns. Your code is not executed.&lt;br /&gt;
&lt;br /&gt;
This will continue until 0.25 seconds has elapsed. Then line 15 will not return, and your code will be executed. So, as long as the button is pressed, your code is repeated every 0.25 seconds.&lt;br /&gt;
&lt;br /&gt;
Now you release the button. mod-up passes 0 as ''step''. Now the important line is 11. ''arg'' is 0, so ''last_busy'' is reset to 0, and the call returns. If you press the button again, the whole cycle restarts again because ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
==  The joystick end of things ==&lt;br /&gt;
All this code is of course in a Nasal file which you create. Give it a suitable name, based on your joystick name, for example logitechlib.nas. Put it in the same folder as your joystick xml file.&lt;br /&gt;
&lt;br /&gt;
Then add this at the top of your xml file, just after all the &amp;lt;name&amp;gt; entries&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        if (!contains(globals, &amp;quot;logitechlib&amp;quot;)) {&lt;br /&gt;
          io.load_nasal(getprop(&amp;quot;/sim/fg-root&amp;quot;) ~ &amp;quot;/Input/Joysticks/Saitek/logitechlib.nas&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make all the affected buttons repeatable. Then use this for the bindings&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;logitechlib.myFunction.do(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
          &amp;lt;script&amp;gt;logitechlib.myFunction.do(0)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Making the declarations tidier ==&lt;br /&gt;
Currently, you need to do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = timedControl.new();&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
myFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It looks a bit neater if you have a helper function.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var createTimedControl = func(timeout, do) {&lt;br /&gt;
      var name = timedControl.new();&lt;br /&gt;
      name.timeout_dur = timeout;&lt;br /&gt;
      name.do = func(step) { name._call(do, step); };&lt;br /&gt;
      append(arrayTimedControls, name);&lt;br /&gt;
      return name;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = createTimedControl(0.25, var do = func(step) {&lt;br /&gt;
# Your code goes here&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Further expansion ==&lt;br /&gt;
If you have a large number of functions in your library, you can make things even neater by using the same method for functions which must repeat at the system rate.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
mySystemRateFunction = createTimedControl(nil);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If ''timeout_dur'' is nil, line 12 makes the function always be called.&lt;br /&gt;
&lt;br /&gt;
== A practical example ==&lt;br /&gt;
We are going to use buttons to adjust the frequency of the NAV1 radio, up and down. We are going to have 3 speeds - adjust the decimals, adjust the units and adjust the tens. To do that, the joystick button passes +ve or -ve 1, 2 or 3 for step. Mod-up is still 0, of course. It also pops the value up on the screen while adjusting. To implement all 3 steps rates, up and down, you will need (probably with the help of modifiers) 6 buttons.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var NAV1Freq = createTimedControl(0.25);&lt;br /&gt;
&lt;br /&gt;
## 1 for decimals, 2 for integers, 3 for 10s integers&lt;br /&gt;
NAV1Freq.do = func(step) me._call(me._do, step);&lt;br /&gt;
NAV1Freq._do = func(step) {&lt;br /&gt;
  var val = 0.05 * step;&lt;br /&gt;
  if (math.abs(step) == 2) val = val * 20;&lt;br /&gt;
  if (math.abs(step) == 3) val = val * 200;&lt;br /&gt;
  var curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr + val);&lt;br /&gt;
  curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  if (curr &amp;gt; 117.95) {&lt;br /&gt;
    curr = 108.00;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  if (curr &amp;lt; 108.00) {&lt;br /&gt;
    curr = 117.95;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  gui.popupTip(sprintf(&amp;quot;NAV1 %0.2f&amp;quot;,curr));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61774</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61774"/>
		<updated>2013-07-25T11:59:33Z</updated>

		<summary type="html">&lt;p&gt;Macnab: /* Improving usability */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
The secret is in having a method of preventing a button from repeating until our chosen time has elapsed. It is possible, but messy, especially if you are doing this with a number of buttons, to do it inside the code for each button. It is much better to create a new type of button code. For this we need a class, and then create instances of this class for each controlled button. This, incidentally, is OOP, or Object Oriented Programming.&lt;br /&gt;
&lt;br /&gt;
Here is thew code to create the new class. It is called timedControl. I have added (unnecessary) open lines between each member of the class to make understanding easier.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var timedControl = {&lt;br /&gt;
      last_busy: 0,&lt;br /&gt;
&lt;br /&gt;
      timeout_dur: 1.0,&lt;br /&gt;
&lt;br /&gt;
      new: func() {&lt;br /&gt;
          return { parents:[me] };&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      _call: func(fn, arg) {&lt;br /&gt;
        if (!arg) { me.last_busy = 0; return; }&lt;br /&gt;
        var time = systime();&lt;br /&gt;
        if (time &amp;lt; me.timeout_dur + me.last_busy) return;&lt;br /&gt;
        me.last_busy = time;&lt;br /&gt;
        return call(fn, [arg], me);&lt;br /&gt;
      }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's assume that we have a function, ''myFunction'', which must only repeat every 0.25 seconds. We create it with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var myFunction = timedControl.new();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
While creating myFunction, it sets ''last_busy'' to 0 (line 2) and ''time_dur'' to 1.0 (line 4).&lt;br /&gt;
&lt;br /&gt;
and set the repeat rate to 0.25 seconds with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
''var myFunction = timedControl.new()'' calls lines 6, 7, 8 of ''timedControl''. This creates a new instance of ''timedControl'' named ''myFunction'' and returns a pointer to it. Now, whenever you use ''myControl'' it will point to where it exists in memory.&lt;br /&gt;
&lt;br /&gt;
''myFunction.timeout_dur = 0.25''. ''myFunction'' points to the function in memory, ''.timout_dur'' then points to where ''timeout_dur'' exists in memory and changes its value to 0.25. Line 4 of the code set it to 1.0, just so it has ''a'' value.&lt;br /&gt;
&lt;br /&gt;
Now we need something for the joystick button to call. Here we are using ''do'', but you could just as easily use ''perform'', or ''activate'', or anything else.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.do =  func(step) me._call(me._do, step);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, ''step'' is 1 for button pressed, and 0 for mod-up, pretty much standard for repeatable button code.&lt;br /&gt;
&lt;br /&gt;
When ''myFunction.do'' is called it executes ''me._call(me._do, step)''. It calls lines 10 onwards of ''timedControl'', passing ''me._do'' and ''step'' as parameters. The ''me'' is the way ''timedControl'' references itself, so if you have multiple buttons using the method, using ''me'' makes sure that you are always using the right ''timeout_dur'' or ''last_busy'', etc.&lt;br /&gt;
&lt;br /&gt;
Now let's look at lines 10 onwards of ''timedControl''. &lt;br /&gt;
&lt;br /&gt;
Line 10 receives the call ''_call'' with the parameters ''me._do'' and ''step'', which it renames to ''fn'' and ''arg.'' &lt;br /&gt;
&lt;br /&gt;
Line 11: If the value of ''arg'', and hence the value of ''step'' is 0, it means mod-up (the button was released.) It sets the value of ''last_busy'' to 0 and returns. ''It does nothing further''.&lt;br /&gt;
&lt;br /&gt;
Line 12: Sets the variable ''time'' to ''systime()''. This is the current date and time, accurate to fractions of a millisecond.&lt;br /&gt;
&lt;br /&gt;
Line 13: Remember, ''last_busy'' was initialised to 0. This line checks if the sum of ''timeout_dur'' and ''last_busy'' is more than the current time. It isn't, since ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
Line 14: ''last_busy'' is set to current time.&lt;br /&gt;
&lt;br /&gt;
Line 15: The function returns, calling ''fn'' with parameter ''arg''.&lt;br /&gt;
&lt;br /&gt;
Now ''fn'' is ''me._do''. ''me'' is of course ''myFunction''. So it is going to call a function by the name of ''myFunction._do''. This is the actual code that must be executed when the joystick button is pressed. So we are going to need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction._do =  func(step) {&lt;br /&gt;
  ....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So your code gets executed. The button is still pressed. A little while later (based on system repeat rate) the button is called again and ''me._call'' is called again.&lt;br /&gt;
&lt;br /&gt;
Line 12: Updates the value of ''time''. It is now 2 milliseconds later.&lt;br /&gt;
&lt;br /&gt;
Line 13: ''last_busy'' was set to the current time last time through the call. Now ''time'' is less than ''last_busy'' + 0.25, so the call returns. Your code is not executed.&lt;br /&gt;
&lt;br /&gt;
This will continue until 0.25 seconds has elapsed. Then line 15 will not return, and your code will be executed. So, as long as the button is pressed, your code is repeated every 0.25 seconds.&lt;br /&gt;
&lt;br /&gt;
Now you release the button. mod-up passes 0 as ''step''. Now the important line is 11. ''arg'' is 0, so ''last_busy'' is reset to 0, and the call returns. If you press the button again, the whole cycle restarts again because ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
==  The joystick end of things ==&lt;br /&gt;
All this code is of course in a Nasal file which you create. Give it a suitable name, based on your joystick name, for example logitechlib.nas. Put it in the same folder as your joystick xml file.&lt;br /&gt;
&lt;br /&gt;
Then add this at the top of your xml file, just after all the &amp;lt;name&amp;gt; entries&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        if (!contains(globals, &amp;quot;logitechlib&amp;quot;)) {&lt;br /&gt;
          io.load_nasal(getprop(&amp;quot;/sim/fg-root&amp;quot;) ~ &amp;quot;/Input/Joysticks/Saitek/logitechlib.nas&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make all the affected buttons repeatable. Then use this for the bindings&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;logitechlib.myFunction.do(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
          &amp;lt;script&amp;gt;logitechlib.myFunction.do(0)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Making the declarations tidier ==&lt;br /&gt;
Currently, you need to do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = timedControl.new();&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It looks a bit neater if you have a helper function&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var createTimedControl = func(timeout) {&lt;br /&gt;
      var name = timedControl.new();&lt;br /&gt;
      name.timeout_dur = timeout;&lt;br /&gt;
      return name;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction = createTimedControl(0.25);&lt;br /&gt;
myOneShotFunction = createTimedControl(-1);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You still need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myRepeatFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
myOneShotFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myOneShotFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Further expansion ==&lt;br /&gt;
If you have a large number of functions in your library, you can make things even neater by using the same method for functions which must repeat at the system rate.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
mySystemRateFunction = createTimedControl(nil);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If ''timeout_dur'' is nil, line 12 makes the function always be called.&lt;br /&gt;
&lt;br /&gt;
== A practical example ==&lt;br /&gt;
We are going to use buttons to adjust the frequency of the NAV1 radio, up and down. We are going to have 3 speeds - adjust the decimals, adjust the units and adjust the tens. To do that, the joystick button passes +ve or -ve 1, 2 or 3 for step. Mod-up is still 0, of course. It also pops the value up on the screen while adjusting. To implement all 3 steps rates, up and down, you will need (probably with the help of modifiers) 6 buttons.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var NAV1Freq = createTimedControl(0.25);&lt;br /&gt;
&lt;br /&gt;
## 1 for decimals, 2 for integers, 3 for 10s integers&lt;br /&gt;
NAV1Freq.do = func(step) me._call(me._do, step);&lt;br /&gt;
NAV1Freq._do = func(step) {&lt;br /&gt;
  var val = 0.05 * step;&lt;br /&gt;
  if (math.abs(step) == 2) val = val * 20;&lt;br /&gt;
  if (math.abs(step) == 3) val = val * 200;&lt;br /&gt;
  var curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr + val);&lt;br /&gt;
  curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  if (curr &amp;gt; 117.95) {&lt;br /&gt;
    curr = 108.00;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  if (curr &amp;lt; 108.00) {&lt;br /&gt;
    curr = 117.95;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  gui.popupTip(sprintf(&amp;quot;NAV1 %0.2f&amp;quot;,curr));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61773</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61773"/>
		<updated>2013-07-25T11:58:44Z</updated>

		<summary type="html">&lt;p&gt;Macnab: /* How it works */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
The secret is in having a method of preventing a button from repeating until our chosen time has elapsed. It is possible, but messy, especially if you are doing this with a number of buttons, to do it inside the code for each button. It is much better to create a new type of button code. For this we need a class, and then create instances of this class for each controlled button. This, incidentally, is OOP, or Object Oriented Programming.&lt;br /&gt;
&lt;br /&gt;
Here is thew code to create the new class. It is called timedControl. I have added (unnecessary) open lines between each member of the class to make understanding easier.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var timedControl = {&lt;br /&gt;
      last_busy: 0,&lt;br /&gt;
&lt;br /&gt;
      timeout_dur: 1.0,&lt;br /&gt;
&lt;br /&gt;
      new: func() {&lt;br /&gt;
          return { parents:[me] };&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      _call: func(fn, arg) {&lt;br /&gt;
        if (!arg) { me.last_busy = 0; return; }&lt;br /&gt;
        var time = systime();&lt;br /&gt;
        if (time &amp;lt; me.timeout_dur + me.last_busy) return;&lt;br /&gt;
        me.last_busy = time;&lt;br /&gt;
        return call(fn, [arg], me);&lt;br /&gt;
      }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's assume that we have a function, ''myFunction'', which must only repeat every 0.25 seconds. We create it with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var myFunction = timedControl.new();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
While creating myFunction, it sets ''last_busy'' to 0 (line 2) and ''time_dur'' to 1.0 (line 4).&lt;br /&gt;
&lt;br /&gt;
and set the repeat rate to 0.25 seconds with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
''var myFunction = timedControl.new()'' calls lines 6, 7, 8 of ''timedControl''. This creates a new instance of ''timedControl'' named ''myFunction'' and returns a pointer to it. Now, whenever you use ''myControl'' it will point to where it exists in memory.&lt;br /&gt;
&lt;br /&gt;
''myFunction.timeout_dur = 0.25''. ''myFunction'' points to the function in memory, ''.timout_dur'' then points to where ''timeout_dur'' exists in memory and changes its value to 0.25. Line 4 of the code set it to 1.0, just so it has ''a'' value.&lt;br /&gt;
&lt;br /&gt;
Now we need something for the joystick button to call. Here we are using ''do'', but you could just as easily use ''perform'', or ''activate'', or anything else.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.do =  func(step) me._call(me._do, step);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, ''step'' is 1 for button pressed, and 0 for mod-up, pretty much standard for repeatable button code.&lt;br /&gt;
&lt;br /&gt;
When ''myFunction.do'' is called it executes ''me._call(me._do, step)''. It calls lines 10 onwards of ''timedControl'', passing ''me._do'' and ''step'' as parameters. The ''me'' is the way ''timedControl'' references itself, so if you have multiple buttons using the method, using ''me'' makes sure that you are always using the right ''timeout_dur'' or ''last_busy'', etc.&lt;br /&gt;
&lt;br /&gt;
Now let's look at lines 10 onwards of ''timedControl''. &lt;br /&gt;
&lt;br /&gt;
Line 10 receives the call ''_call'' with the parameters ''me._do'' and ''step'', which it renames to ''fn'' and ''arg.'' &lt;br /&gt;
&lt;br /&gt;
Line 11: If the value of ''arg'', and hence the value of ''step'' is 0, it means mod-up (the button was released.) It sets the value of ''last_busy'' to 0 and returns. ''It does nothing further''.&lt;br /&gt;
&lt;br /&gt;
Line 12: Sets the variable ''time'' to ''systime()''. This is the current date and time, accurate to fractions of a millisecond.&lt;br /&gt;
&lt;br /&gt;
Line 13: Remember, ''last_busy'' was initialised to 0. This line checks if the sum of ''timeout_dur'' and ''last_busy'' is more than the current time. It isn't, since ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
Line 14: ''last_busy'' is set to current time.&lt;br /&gt;
&lt;br /&gt;
Line 15: The function returns, calling ''fn'' with parameter ''arg''.&lt;br /&gt;
&lt;br /&gt;
Now ''fn'' is ''me._do''. ''me'' is of course ''myFunction''. So it is going to call a function by the name of ''myFunction._do''. This is the actual code that must be executed when the joystick button is pressed. So we are going to need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction._do =  func(step) {&lt;br /&gt;
  ....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So your code gets executed. The button is still pressed. A little while later (based on system repeat rate) the button is called again and ''me._call'' is called again.&lt;br /&gt;
&lt;br /&gt;
Line 12: Updates the value of ''time''. It is now 2 milliseconds later.&lt;br /&gt;
&lt;br /&gt;
Line 13: ''last_busy'' was set to the current time last time through the call. Now ''time'' is less than ''last_busy'' + 0.25, so the call returns. Your code is not executed.&lt;br /&gt;
&lt;br /&gt;
This will continue until 0.25 seconds has elapsed. Then line 15 will not return, and your code will be executed. So, as long as the button is pressed, your code is repeated every 0.25 seconds.&lt;br /&gt;
&lt;br /&gt;
Now you release the button. mod-up passes 0 as ''step''. Now the important line is 11. ''arg'' is 0, so ''last_busy'' is reset to 0, and the call returns. If you press the button again, the whole cycle restarts again because ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
== Improving usability ==&lt;br /&gt;
On of the problems with using modifiers with joystick buttons is that, once set, the repeatable/non-repeatable value cannot be changed. This means that you need to group functions according to whether or not they are repeatable.&lt;br /&gt;
&lt;br /&gt;
Using ''timedControl'' you can make all your buttons repeatable and use the value of ''timeout'' duration to make them one-shot, the equivalent of non-repeatable.&lt;br /&gt;
&lt;br /&gt;
You use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = -1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now let's see what happens when the button is pressed and ''me'_call' is run.&lt;br /&gt;
&lt;br /&gt;
Line 13: ''timeout_dur'' is -1, ''last_busy'' is 0, so the code continues.&lt;br /&gt;
&lt;br /&gt;
Line 16 sets ''last_busy'' to the current time, and your code is called by line 18.&lt;br /&gt;
&lt;br /&gt;
The next time round, ''last_busy'' is not 0, so line 13 makes the function return. Your code is never called again, until mod-up resets ''last_busy'' to 0 again. You now have a non-repeatable action from a repeatable button, and you can, using modifiers, group the button actions in a way that makes sense to you.&lt;br /&gt;
&lt;br /&gt;
==  The joystick end of things ==&lt;br /&gt;
All this code is of course in a Nasal file which you create. Give it a suitable name, based on your joystick name, for example logitechlib.nas. Put it in the same folder as your joystick xml file.&lt;br /&gt;
&lt;br /&gt;
Then add this at the top of your xml file, just after all the &amp;lt;name&amp;gt; entries&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        if (!contains(globals, &amp;quot;logitechlib&amp;quot;)) {&lt;br /&gt;
          io.load_nasal(getprop(&amp;quot;/sim/fg-root&amp;quot;) ~ &amp;quot;/Input/Joysticks/Saitek/logitechlib.nas&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make all the affected buttons repeatable. Then use this for the bindings&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;logitechlib.myFunction.do(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
          &amp;lt;script&amp;gt;logitechlib.myFunction.do(0)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Making the declarations tidier ==&lt;br /&gt;
Currently, you need to do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = timedControl.new();&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It looks a bit neater if you have a helper function&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var createTimedControl = func(timeout) {&lt;br /&gt;
      var name = timedControl.new();&lt;br /&gt;
      name.timeout_dur = timeout;&lt;br /&gt;
      return name;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction = createTimedControl(0.25);&lt;br /&gt;
myOneShotFunction = createTimedControl(-1);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You still need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myRepeatFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
myOneShotFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myOneShotFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Further expansion ==&lt;br /&gt;
If you have a large number of functions in your library, you can make things even neater by using the same method for functions which must repeat at the system rate.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
mySystemRateFunction = createTimedControl(nil);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If ''timeout_dur'' is nil, line 12 makes the function always be called.&lt;br /&gt;
&lt;br /&gt;
== A practical example ==&lt;br /&gt;
We are going to use buttons to adjust the frequency of the NAV1 radio, up and down. We are going to have 3 speeds - adjust the decimals, adjust the units and adjust the tens. To do that, the joystick button passes +ve or -ve 1, 2 or 3 for step. Mod-up is still 0, of course. It also pops the value up on the screen while adjusting. To implement all 3 steps rates, up and down, you will need (probably with the help of modifiers) 6 buttons.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var NAV1Freq = createTimedControl(0.25);&lt;br /&gt;
&lt;br /&gt;
## 1 for decimals, 2 for integers, 3 for 10s integers&lt;br /&gt;
NAV1Freq.do = func(step) me._call(me._do, step);&lt;br /&gt;
NAV1Freq._do = func(step) {&lt;br /&gt;
  var val = 0.05 * step;&lt;br /&gt;
  if (math.abs(step) == 2) val = val * 20;&lt;br /&gt;
  if (math.abs(step) == 3) val = val * 200;&lt;br /&gt;
  var curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr + val);&lt;br /&gt;
  curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  if (curr &amp;gt; 117.95) {&lt;br /&gt;
    curr = 108.00;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  if (curr &amp;lt; 108.00) {&lt;br /&gt;
    curr = 117.95;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  gui.popupTip(sprintf(&amp;quot;NAV1 %0.2f&amp;quot;,curr));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61772</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61772"/>
		<updated>2013-07-25T11:56:31Z</updated>

		<summary type="html">&lt;p&gt;Macnab: /* How it works */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
The secret is in having a method of preventing a button from repeating until our chosen time has elapsed. It is possible, but messy, especially if you are doing this with a number of buttons, to do it inside the code for each button. It is much better to create a new type of button code. For this we need a class, and then create instances of this class for each controlled button. This, incidentally, is OOP, or Object Oriented Programming.&lt;br /&gt;
&lt;br /&gt;
Here is thew code to create the new class. It is called timedControl. I have added (unnecessary) open lines between each member of the class to make understanding easier.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var timedControl = {&lt;br /&gt;
      last_busy: 0,&lt;br /&gt;
&lt;br /&gt;
      timeout_dur: 1.0,&lt;br /&gt;
&lt;br /&gt;
      new: func() {&lt;br /&gt;
          return { parents:[me] };&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      _call: func(fn, arg) {&lt;br /&gt;
        if (!arg) { me.last_busy = 0; return; }&lt;br /&gt;
        var time = systime();&lt;br /&gt;
        if (time &amp;lt; me.timeout_dur + me.last_busy) return;&lt;br /&gt;
        me.last_busy = time;&lt;br /&gt;
        return call(fn, [arg], me);&lt;br /&gt;
      }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's assume that we have a function, ''myFunction'', which must only repeat every 0.25 seconds. We create it with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var myFunction = timedControl.new();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
While creating myFunction, it sets ''last_busy'' to 0 (line 2) and ''time_dur'' to 1.0 (line 4).&lt;br /&gt;
&lt;br /&gt;
and set the repeat rate to 0.25 seconds with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
''var myFunction = timedControl.new()'' calls lines 6, 7, 8 of ''timedControl''. This creates a new instance of ''timedControl'' named ''myFunction'' and returns a pointer to it. Now, whenever you use ''myControl'' it will point to where it exists in memory.&lt;br /&gt;
&lt;br /&gt;
''myFunction.timeout_dur = 0.25''. ''myFunction'' points to the function in memory, ''.timout_dur'' then points to where ''timeout_dur'' exists in memory and changes its value to 0.25. Line 4 of the code set it to 1.0, just so it has ''a'' value.&lt;br /&gt;
&lt;br /&gt;
Now we need something for the joystick button to call. Here we are using ''do'', but you could just as easily use ''perform'', or ''activate'', or anything else.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.do =  func(step) me._call(me._do, step);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, ''step'' is 1 for button pressed, and 0 for mod-up, pretty much standard for repeatable button code.&lt;br /&gt;
&lt;br /&gt;
When ''myFunction.do'' is called it executes ''me._call(me._do, step)''. It calls lines 10 onwards of ''timedControl'', passing ''me._do'' and ''step'' as parameters. The ''me'' is the way ''timedControl'' references itself, so if you have multiple buttons using the method, using ''me'' makes sure that you are always using the right ''timeout_dur'' or ''last_busy'', etc.&lt;br /&gt;
&lt;br /&gt;
Now let's look at lines 10 onwards of ''timedControl''. &lt;br /&gt;
&lt;br /&gt;
Line 10 receives the call ''_call'' with the parameters ''me._do'' and ''step'', which it renames to ''fn'' and ''arg.'' &lt;br /&gt;
&lt;br /&gt;
Line 11: If the value of ''arg'', and hence the value of ''step'' is 0, it means mod-up (the button was released.) It sets the value of ''last_busy'' to 0 and returns. ''It does nothing further''.&lt;br /&gt;
&lt;br /&gt;
Line 12: Sets the variable ''time'' to ''systime()''. This is the current date and time, accurate to fractions of a millisecond.&lt;br /&gt;
&lt;br /&gt;
Line 13: Remember, ''last_busy'' was initialised to 0. This line checks if the sum of ''timeout_dur'' and ''last_busy'' is more than the current time. It isn't, since ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
Line 14: ''last_busy'' is set to current time.&lt;br /&gt;
&lt;br /&gt;
Line 15: The function returns, calling ''fn'' with parameter ''arg''.&lt;br /&gt;
&lt;br /&gt;
Now ''fn'' is ''me._do''. ''me'' is of course ''myFunction''. So it is going to call a function by the name of ''myFunction._do''. This is the actual code that must be executed when the joystick button is pressed. So we are going to need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction._do =  func(step) {&lt;br /&gt;
  ....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So your code gets executed. The button is still pressed. A little while later (based on system repeat rate) the button is called again and ''me._call'' is called again.&lt;br /&gt;
&lt;br /&gt;
Line 14: Updates the value of ''time''. It is now 2 milliseconds later.&lt;br /&gt;
&lt;br /&gt;
Line 15: ''last_busy'' was set to the current time last time through the call. Now ''time'' is less than ''last_busy'' + 0.25, so the call returns. Your code is not executed.&lt;br /&gt;
&lt;br /&gt;
This will continue until 0.25 seconds has elapsed. Then line 15 will not return, and your code will be executed. So, as long as the button is pressed, your code is repeated every 0.25 seconds.&lt;br /&gt;
&lt;br /&gt;
Now you release the button. mod-up passes 0 as ''step''. Now the important line is 11. ''arg'' is 0, so ''last_busy'' is reset to 0, and the call returns. If you press the button again, the whole cycle restarts again because ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
== Improving usability ==&lt;br /&gt;
On of the problems with using modifiers with joystick buttons is that, once set, the repeatable/non-repeatable value cannot be changed. This means that you need to group functions according to whether or not they are repeatable.&lt;br /&gt;
&lt;br /&gt;
Using ''timedControl'' you can make all your buttons repeatable and use the value of ''timeout'' duration to make them one-shot, the equivalent of non-repeatable.&lt;br /&gt;
&lt;br /&gt;
You use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = -1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now let's see what happens when the button is pressed and ''me'_call' is run.&lt;br /&gt;
&lt;br /&gt;
Line 13: ''timeout_dur'' is -1, ''last_busy'' is 0, so the code continues.&lt;br /&gt;
&lt;br /&gt;
Line 16 sets ''last_busy'' to the current time, and your code is called by line 18.&lt;br /&gt;
&lt;br /&gt;
The next time round, ''last_busy'' is not 0, so line 13 makes the function return. Your code is never called again, until mod-up resets ''last_busy'' to 0 again. You now have a non-repeatable action from a repeatable button, and you can, using modifiers, group the button actions in a way that makes sense to you.&lt;br /&gt;
&lt;br /&gt;
==  The joystick end of things ==&lt;br /&gt;
All this code is of course in a Nasal file which you create. Give it a suitable name, based on your joystick name, for example logitechlib.nas. Put it in the same folder as your joystick xml file.&lt;br /&gt;
&lt;br /&gt;
Then add this at the top of your xml file, just after all the &amp;lt;name&amp;gt; entries&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        if (!contains(globals, &amp;quot;logitechlib&amp;quot;)) {&lt;br /&gt;
          io.load_nasal(getprop(&amp;quot;/sim/fg-root&amp;quot;) ~ &amp;quot;/Input/Joysticks/Saitek/logitechlib.nas&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make all the affected buttons repeatable. Then use this for the bindings&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;logitechlib.myFunction.do(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
          &amp;lt;script&amp;gt;logitechlib.myFunction.do(0)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Making the declarations tidier ==&lt;br /&gt;
Currently, you need to do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = timedControl.new();&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It looks a bit neater if you have a helper function&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var createTimedControl = func(timeout) {&lt;br /&gt;
      var name = timedControl.new();&lt;br /&gt;
      name.timeout_dur = timeout;&lt;br /&gt;
      return name;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction = createTimedControl(0.25);&lt;br /&gt;
myOneShotFunction = createTimedControl(-1);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You still need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myRepeatFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
myOneShotFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myOneShotFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Further expansion ==&lt;br /&gt;
If you have a large number of functions in your library, you can make things even neater by using the same method for functions which must repeat at the system rate.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
mySystemRateFunction = createTimedControl(nil);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If ''timeout_dur'' is nil, line 12 makes the function always be called.&lt;br /&gt;
&lt;br /&gt;
== A practical example ==&lt;br /&gt;
We are going to use buttons to adjust the frequency of the NAV1 radio, up and down. We are going to have 3 speeds - adjust the decimals, adjust the units and adjust the tens. To do that, the joystick button passes +ve or -ve 1, 2 or 3 for step. Mod-up is still 0, of course. It also pops the value up on the screen while adjusting. To implement all 3 steps rates, up and down, you will need (probably with the help of modifiers) 6 buttons.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var NAV1Freq = createTimedControl(0.25);&lt;br /&gt;
&lt;br /&gt;
## 1 for decimals, 2 for integers, 3 for 10s integers&lt;br /&gt;
NAV1Freq.do = func(step) me._call(me._do, step);&lt;br /&gt;
NAV1Freq._do = func(step) {&lt;br /&gt;
  var val = 0.05 * step;&lt;br /&gt;
  if (math.abs(step) == 2) val = val * 20;&lt;br /&gt;
  if (math.abs(step) == 3) val = val * 200;&lt;br /&gt;
  var curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr + val);&lt;br /&gt;
  curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  if (curr &amp;gt; 117.95) {&lt;br /&gt;
    curr = 108.00;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  if (curr &amp;lt; 108.00) {&lt;br /&gt;
    curr = 117.95;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  gui.popupTip(sprintf(&amp;quot;NAV1 %0.2f&amp;quot;,curr));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61771</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61771"/>
		<updated>2013-07-25T11:53:50Z</updated>

		<summary type="html">&lt;p&gt;Macnab: /* How it is done */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
The secret is in having a method of preventing a button from repeating until our chosen time has elapsed. It is possible, but messy, especially if you are doing this with a number of buttons, to do it inside the code for each button. It is much better to create a new type of button code. For this we need a class, and then create instances of this class for each controlled button. This, incidentally, is OOP, or Object Oriented Programming.&lt;br /&gt;
&lt;br /&gt;
Here is thew code to create the new class. It is called timedControl. I have added (unnecessary) open lines between each member of the class to make understanding easier.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var timedControl = {&lt;br /&gt;
      last_busy: 0,&lt;br /&gt;
&lt;br /&gt;
      timeout_dur: 1.0,&lt;br /&gt;
&lt;br /&gt;
      new: func() {&lt;br /&gt;
          return { parents:[me] };&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      _call: func(fn, arg) {&lt;br /&gt;
        if (!arg) { me.last_busy = 0; return; }&lt;br /&gt;
        var time = systime();&lt;br /&gt;
        if (time &amp;lt; me.timeout_dur + me.last_busy) return;&lt;br /&gt;
        me.last_busy = time;&lt;br /&gt;
        return call(fn, [arg], me);&lt;br /&gt;
      }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's assume that we have a function, ''myFunction'', which must only repeat every 0.25 seconds. We create it with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var myFunction = timedControl.new();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
While creating myFunction, it sets ''last_busy'' to 0 (line 2) and ''time_dur'' to 1.0 (line 4).&lt;br /&gt;
&lt;br /&gt;
and set the repeat rate to 0.25 seconds with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
''var myFunction = timedControl.new()'' calls lines 6, 7, 8 of ''timedControl''. This creates a new instance of ''timedControl'' named ''myFunction'' and returns a pointer to it. Now, whenever you use ''myControl'' it will point to where it exists in memory.&lt;br /&gt;
&lt;br /&gt;
''myFunction.timeout_dur = 0.25''. ''myFunction'' points to the function in memory, ''.timout_dur'' then points to where ''timeout_dur'' exists in memory and changes its value to 0.25. Line 4 of the code set it to 1.0, just so it has ''a'' value.&lt;br /&gt;
&lt;br /&gt;
Now we need something for the joystick button to call. Here we are using ''do'', but you could just as easily use ''perform'', or ''activate'', or anything else.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.do =  func(step) me._call(me._do, step);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, ''step'' is 1 for button pressed, and 0 for mod-up, pretty much standard for repeatable button code.&lt;br /&gt;
&lt;br /&gt;
When ''myFunction.do'' is called it executes ''me._call(me._do, step)''. It calls lines 10 onwards of ''timedControl'', passing ''me._do'' and ''step'' as parameters. The ''me'' is the way ''timedControl'' references itself, so if you have multiple buttons using the method, using ''me'' makes sure that you are always using the right ''timeout_dur'' or ''last_busy'', etc.&lt;br /&gt;
&lt;br /&gt;
Now let's look at lines 10 onwards of ''timedControl''. &lt;br /&gt;
&lt;br /&gt;
Line 10 receives the call ''_call'' with the parameters ''me._do'' and ''step'', which it renames to ''fn'' and ''arg.'' &lt;br /&gt;
&lt;br /&gt;
Line 11: If the value of ''arg'', and hence the value of ''step'' is 0, it means mod-up (the button was released.) It sets the value of ''last_busy'' to 0 and returns. ''It does nothing further''.&lt;br /&gt;
&lt;br /&gt;
Line 12: Ignore for the moment.&lt;br /&gt;
&lt;br /&gt;
Line 13: Ignore for the moment.&lt;br /&gt;
&lt;br /&gt;
Line 14: Sets the variable ''time'' to ''system''. This is the current date and time, accurate to fractions of a millisecond.&lt;br /&gt;
&lt;br /&gt;
Line 15: Remember, ''last_busy'' was initialised to 0. This line checks if the sum of ''timeout_dur'' and ''last_busy'' is more than the current time. It isn't, since ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
Line 16: ''last_busy'' is set to current time.&lt;br /&gt;
&lt;br /&gt;
Line 18: The function returns, calling ''fn'' with parameter ''arg''.&lt;br /&gt;
&lt;br /&gt;
Now ''fn'' is ''me._do''. ''me'' is of course ''myFunction''. So it is going to call a function by the name of ''myFunction._do''. This is the actual code that must be executed when the joystick button is pressed. So we are going to need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction._do =  func(step) {&lt;br /&gt;
  ....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So your code gets executed. The button is still pressed. A little while later (based on system repeat rate) the button is called again and ''me._call'' is called again.&lt;br /&gt;
&lt;br /&gt;
Line 14: Updates the value of ''time''. It is now 2 milliseconds later.&lt;br /&gt;
&lt;br /&gt;
Line 15: ''last_busy'' was set to the current time last time through the call. Now ''time'' is less than ''last_busy'' + 0.25, so the call returns. Your code is not executed.&lt;br /&gt;
&lt;br /&gt;
This will continue until 0.25 seconds has elapsed. Then line 15 will not return, and your code will be executed. So, as long as the button is pressed, your code is repeated every 0.25 seconds.&lt;br /&gt;
&lt;br /&gt;
Now you release the button. mod-up passes 0 as ''step''. Now the important line is 11. ''arg'' is 0, so ''last_busy'' is reset to 0, and the call returns. If you press the button again, the whole cycle restarts again because ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
== Improving usability ==&lt;br /&gt;
On of the problems with using modifiers with joystick buttons is that, once set, the repeatable/non-repeatable value cannot be changed. This means that you need to group functions according to whether or not they are repeatable.&lt;br /&gt;
&lt;br /&gt;
Using ''timedControl'' you can make all your buttons repeatable and use the value of ''timeout'' duration to make them one-shot, the equivalent of non-repeatable.&lt;br /&gt;
&lt;br /&gt;
You use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = -1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now let's see what happens when the button is pressed and ''me'_call' is run.&lt;br /&gt;
&lt;br /&gt;
Line 13: ''timeout_dur'' is -1, ''last_busy'' is 0, so the code continues.&lt;br /&gt;
&lt;br /&gt;
Line 16 sets ''last_busy'' to the current time, and your code is called by line 18.&lt;br /&gt;
&lt;br /&gt;
The next time round, ''last_busy'' is not 0, so line 13 makes the function return. Your code is never called again, until mod-up resets ''last_busy'' to 0 again. You now have a non-repeatable action from a repeatable button, and you can, using modifiers, group the button actions in a way that makes sense to you.&lt;br /&gt;
&lt;br /&gt;
==  The joystick end of things ==&lt;br /&gt;
All this code is of course in a Nasal file which you create. Give it a suitable name, based on your joystick name, for example logitechlib.nas. Put it in the same folder as your joystick xml file.&lt;br /&gt;
&lt;br /&gt;
Then add this at the top of your xml file, just after all the &amp;lt;name&amp;gt; entries&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        if (!contains(globals, &amp;quot;logitechlib&amp;quot;)) {&lt;br /&gt;
          io.load_nasal(getprop(&amp;quot;/sim/fg-root&amp;quot;) ~ &amp;quot;/Input/Joysticks/Saitek/logitechlib.nas&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make all the affected buttons repeatable. Then use this for the bindings&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;logitechlib.myFunction.do(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
          &amp;lt;script&amp;gt;logitechlib.myFunction.do(0)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Making the declarations tidier ==&lt;br /&gt;
Currently, you need to do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = timedControl.new();&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It looks a bit neater if you have a helper function&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var createTimedControl = func(timeout) {&lt;br /&gt;
      var name = timedControl.new();&lt;br /&gt;
      name.timeout_dur = timeout;&lt;br /&gt;
      return name;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction = createTimedControl(0.25);&lt;br /&gt;
myOneShotFunction = createTimedControl(-1);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You still need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myRepeatFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
myOneShotFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myOneShotFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Further expansion ==&lt;br /&gt;
If you have a large number of functions in your library, you can make things even neater by using the same method for functions which must repeat at the system rate.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
mySystemRateFunction = createTimedControl(nil);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If ''timeout_dur'' is nil, line 12 makes the function always be called.&lt;br /&gt;
&lt;br /&gt;
== A practical example ==&lt;br /&gt;
We are going to use buttons to adjust the frequency of the NAV1 radio, up and down. We are going to have 3 speeds - adjust the decimals, adjust the units and adjust the tens. To do that, the joystick button passes +ve or -ve 1, 2 or 3 for step. Mod-up is still 0, of course. It also pops the value up on the screen while adjusting. To implement all 3 steps rates, up and down, you will need (probably with the help of modifiers) 6 buttons.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var NAV1Freq = createTimedControl(0.25);&lt;br /&gt;
&lt;br /&gt;
## 1 for decimals, 2 for integers, 3 for 10s integers&lt;br /&gt;
NAV1Freq.do = func(step) me._call(me._do, step);&lt;br /&gt;
NAV1Freq._do = func(step) {&lt;br /&gt;
  var val = 0.05 * step;&lt;br /&gt;
  if (math.abs(step) == 2) val = val * 20;&lt;br /&gt;
  if (math.abs(step) == 3) val = val * 200;&lt;br /&gt;
  var curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr + val);&lt;br /&gt;
  curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  if (curr &amp;gt; 117.95) {&lt;br /&gt;
    curr = 108.00;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  if (curr &amp;lt; 108.00) {&lt;br /&gt;
    curr = 117.95;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  gui.popupTip(sprintf(&amp;quot;NAV1 %0.2f&amp;quot;,curr));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61711</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61711"/>
		<updated>2013-07-22T08:30:23Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
The secret is in having a method of preventing a button from repeating until our chosen time has elapsed. It is possible, but messy, especially if you are doing this with a number of buttons, to do it inside the code for each button. It is much better to create a new type of button code. For this we need a class, and then create instances of this class for each controlled button. This, incidentally, is OOP, or Object Oriented Programming.&lt;br /&gt;
&lt;br /&gt;
Here is thew code to create the new class. It is called timedControl. I have added (unnecessary) open lines between each member of the class to make understanding easier.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var timedControl = {&lt;br /&gt;
      last_busy: 0,&lt;br /&gt;
&lt;br /&gt;
      timeout_dur: 1.0,&lt;br /&gt;
&lt;br /&gt;
      new: func() {&lt;br /&gt;
          return { parents:[me] };&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      _call: func(fn, arg) {&lt;br /&gt;
        if (!arg) { me.last_busy = 0; return; }&lt;br /&gt;
        if (me.timeout_dur != nil) {&lt;br /&gt;
          if ((me.timeout_dur == -1) and me.last_busy != 0) return;&lt;br /&gt;
          var time = systime();&lt;br /&gt;
          if (time &amp;lt; me.timeout_dur + me.last_busy) return;&lt;br /&gt;
          me.last_busy = time;&lt;br /&gt;
        }&lt;br /&gt;
        return call(fn, [arg], me);&lt;br /&gt;
      }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's assume that we have a function, ''myFunction'', which must only repeat every 0.25 seconds. We create it with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var myFunction = timedControl.new();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
While creating myFunction, it sets ''last_busy'' to 0 (line 2) and ''time_dur'' to 1.0 (line 4).&lt;br /&gt;
&lt;br /&gt;
and set the repeat rate to 0.25 seconds with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
''var myFunction = timedControl.new()'' calls lines 6, 7, 8 of ''timedControl''. This creates a new instance of ''timedControl'' named ''myFunction'' and returns a pointer to it. Now, whenever you use ''myControl'' it will point to where it exists in memory.&lt;br /&gt;
&lt;br /&gt;
''myFunction.timeout_dur = 0.25''. ''myFunction'' points to the function in memory, ''.timout_dur'' then points to where ''timeout_dur'' exists in memory and changes its value to 0.25. Line 4 of the code set it to 1.0, just so it has ''a'' value.&lt;br /&gt;
&lt;br /&gt;
Now we need something for the joystick button to call. Here we are using ''do'', but you could just as easily use ''perform'', or ''activate'', or anything else.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.do =  func(step) me._call(me._do, step);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, ''step'' is 1 for button pressed, and 0 for mod-up, pretty much standard for repeatable button code.&lt;br /&gt;
&lt;br /&gt;
When ''myFunction.do'' is called it executes ''me._call(me._do, step)''. It calls lines 10 onwards of ''timedControl'', passing ''me._do'' and ''step'' as parameters. The ''me'' is the way ''timedControl'' references itself, so if you have multiple buttons using the method, using ''me'' makes sure that you are always using the right ''timeout_dur'' or ''last_busy'', etc.&lt;br /&gt;
&lt;br /&gt;
Now let's look at lines 10 onwards of ''timedControl''. &lt;br /&gt;
&lt;br /&gt;
Line 10 receives the call ''_call'' with the parameters ''me._do'' and ''step'', which it renames to ''fn'' and ''arg.'' &lt;br /&gt;
&lt;br /&gt;
Line 11: If the value of ''arg'', and hence the value of ''step'' is 0, it means mod-up (the button was released.) It sets the value of ''last_busy'' to 0 and returns. ''It does nothing further''.&lt;br /&gt;
&lt;br /&gt;
Line 12: Ignore for the moment.&lt;br /&gt;
&lt;br /&gt;
Line 13: Ignore for the moment.&lt;br /&gt;
&lt;br /&gt;
Line 14: Sets the variable ''time'' to ''system''. This is the current date and time, accurate to fractions of a millisecond.&lt;br /&gt;
&lt;br /&gt;
Line 15: Remember, ''last_busy'' was initialised to 0. This line checks if the sum of ''timeout_dur'' and ''last_busy'' is more than the current time. It isn't, since ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
Line 16: ''last_busy'' is set to current time.&lt;br /&gt;
&lt;br /&gt;
Line 18: The function returns, calling ''fn'' with parameter ''arg''.&lt;br /&gt;
&lt;br /&gt;
Now ''fn'' is ''me._do''. ''me'' is of course ''myFunction''. So it is going to call a function by the name of ''myFunction._do''. This is the actual code that must be executed when the joystick button is pressed. So we are going to need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction._do =  func(step) {&lt;br /&gt;
  ....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So your code gets executed. The button is still pressed. A little while later (based on system repeat rate) the button is called again and ''me._call'' is called again.&lt;br /&gt;
&lt;br /&gt;
Line 14: Updates the value of ''time''. It is now 2 milliseconds later.&lt;br /&gt;
&lt;br /&gt;
Line 15: ''last_busy'' was set to the current time last time through the call. Now ''time'' is less than ''last_busy'' + 0.25, so the call returns. Your code is not executed.&lt;br /&gt;
&lt;br /&gt;
This will continue until 0.25 seconds has elapsed. Then line 15 will not return, and your code will be executed. So, as long as the button is pressed, your code is repeated every 0.25 seconds.&lt;br /&gt;
&lt;br /&gt;
Now you release the button. mod-up passes 0 as ''step''. Now the important line is 11. ''arg'' is 0, so ''last_busy'' is reset to 0, and the call returns. If you press the button again, the whole cycle restarts again because ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
== Improving usability ==&lt;br /&gt;
On of the problems with using modifiers with joystick buttons is that, once set, the repeatable/non-repeatable value cannot be changed. This means that you need to group functions according to whether or not they are repeatable.&lt;br /&gt;
&lt;br /&gt;
Using ''timedControl'' you can make all your buttons repeatable and use the value of ''timeout'' duration to make them one-shot, the equivalent of non-repeatable.&lt;br /&gt;
&lt;br /&gt;
You use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = -1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now let's see what happens when the button is pressed and ''me'_call' is run.&lt;br /&gt;
&lt;br /&gt;
Line 13: ''timeout_dur'' is -1, ''last_busy'' is 0, so the code continues.&lt;br /&gt;
&lt;br /&gt;
Line 16 sets ''last_busy'' to the current time, and your code is called by line 18.&lt;br /&gt;
&lt;br /&gt;
The next time round, ''last_busy'' is not 0, so line 13 makes the function return. Your code is never called again, until mod-up resets ''last_busy'' to 0 again. You now have a non-repeatable action from a repeatable button, and you can, using modifiers, group the button actions in a way that makes sense to you.&lt;br /&gt;
&lt;br /&gt;
==  The joystick end of things ==&lt;br /&gt;
All this code is of course in a Nasal file which you create. Give it a suitable name, based on your joystick name, for example logitechlib.nas. Put it in the same folder as your joystick xml file.&lt;br /&gt;
&lt;br /&gt;
Then add this at the top of your xml file, just after all the &amp;lt;name&amp;gt; entries&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        if (!contains(globals, &amp;quot;logitechlib&amp;quot;)) {&lt;br /&gt;
          io.load_nasal(getprop(&amp;quot;/sim/fg-root&amp;quot;) ~ &amp;quot;/Input/Joysticks/Saitek/logitechlib.nas&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make all the affected buttons repeatable. Then use this for the bindings&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;logitechlib.myFunction.do(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
          &amp;lt;script&amp;gt;logitechlib.myFunction.do(0)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Making the declarations tidier ==&lt;br /&gt;
Currently, you need to do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = timedControl.new();&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It looks a bit neater if you have a helper function&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var createTimedControl = func(timeout) {&lt;br /&gt;
      var name = timedControl.new();&lt;br /&gt;
      name.timeout_dur = timeout;&lt;br /&gt;
      return name;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction = createTimedControl(0.25);&lt;br /&gt;
myOneShotFunction = createTimedControl(-1);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You still need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myRepeatFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
myOneShotFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myOneShotFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Further expansion ==&lt;br /&gt;
If you have a large number of functions in your library, you can make things even neater by using the same method for functions which must repeat at the system rate.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
mySystemRateFunction = createTimedControl(nil);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If ''timeout_dur'' is nil, line 12 makes the function always be called.&lt;br /&gt;
&lt;br /&gt;
== A practical example ==&lt;br /&gt;
We are going to use buttons to adjust the frequency of the NAV1 radio, up and down. We are going to have 3 speeds - adjust the decimals, adjust the units and adjust the tens. To do that, the joystick button passes +ve or -ve 1, 2 or 3 for step. Mod-up is still 0, of course. It also pops the value up on the screen while adjusting. To implement all 3 steps rates, up and down, you will need (probably with the help of modifiers) 6 buttons.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var NAV1Freq = createTimedControl(0.25);&lt;br /&gt;
&lt;br /&gt;
## 1 for decimals, 2 for integers, 3 for 10s integers&lt;br /&gt;
NAV1Freq.do = func(step) me._call(me._do, step);&lt;br /&gt;
NAV1Freq._do = func(step) {&lt;br /&gt;
  var val = 0.05 * step;&lt;br /&gt;
  if (math.abs(step) == 2) val = val * 20;&lt;br /&gt;
  if (math.abs(step) == 3) val = val * 200;&lt;br /&gt;
  var curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr + val);&lt;br /&gt;
  curr = getprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;);&lt;br /&gt;
  if (curr &amp;gt; 117.95) {&lt;br /&gt;
    curr = 108.00;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  if (curr &amp;lt; 108.00) {&lt;br /&gt;
    curr = 117.95;&lt;br /&gt;
    setprop(&amp;quot;/instrumentation/nav/frequencies/standby-mhz&amp;quot;, curr)&lt;br /&gt;
  }&lt;br /&gt;
  gui.popupTip(sprintf(&amp;quot;NAV1 %0.2f&amp;quot;,curr));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61710</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61710"/>
		<updated>2013-07-22T08:13:12Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
The secret is in having a method of preventing a button from repeating until our chosen time has elapsed. It is possible, but messy, especially if you are doing this with a number of buttons, to do it inside the code for each button. It is much better to create a new type of button code. For this we need a class, and then create instances of this class for each controlled button. This, incidentally, is OOP, or Object Oriented Programming.&lt;br /&gt;
&lt;br /&gt;
Here is thew code to create the new class. It is called timedControl. I have added (unnecessary) open lines between each member of the class to make understanding easier.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var timedControl = {&lt;br /&gt;
      last_busy: 0,&lt;br /&gt;
&lt;br /&gt;
      timeout_dur: 1.0,&lt;br /&gt;
&lt;br /&gt;
      new: func() {&lt;br /&gt;
          return { parents:[me] };&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      _call: func(fn, arg) {&lt;br /&gt;
        if (!arg) { me.last_busy = 0; return; }&lt;br /&gt;
        if (me.timeout_dur != nil) {&lt;br /&gt;
          if ((me.timeout_dur == -1) and me.last_busy != 0) return;&lt;br /&gt;
          var time = systime();&lt;br /&gt;
          if (time &amp;lt; me.timeout_dur + me.last_busy) return;&lt;br /&gt;
          me.last_busy = time;&lt;br /&gt;
        }&lt;br /&gt;
        return call(fn, [arg], me);&lt;br /&gt;
      }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's assume that we have a function, ''myFunction'', which must only repeat every 0.25 seconds. We create it with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var myFunction = timedControl.new();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
While creating myFunction, it sets ''last_busy'' to 0 (line 2) and ''time_dur'' to 1.0 (line 4).&lt;br /&gt;
&lt;br /&gt;
and set the repeat rate to 0.25 seconds with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
''var myFunction = timedControl.new()'' calls lines 6, 7, 8 of ''timedControl''. This creates a new instance of ''timedControl'' named ''myFunction'' and returns a pointer to it. Now, whenever you use ''myControl'' it will point to where it exists in memory.&lt;br /&gt;
&lt;br /&gt;
''myFunction.timeout_dur = 0.25''. ''myFunction'' points to the function in memory, ''.timout_dur'' then points to where ''timeout_dur'' exists in memory and changes its value to 0.25. Line 4 of the code set it to 1.0, just so it has ''a'' value.&lt;br /&gt;
&lt;br /&gt;
Now we need something for the joystick button to call. Here we are using ''do'', but you could just as easily use ''perform'', or ''activate'', or anything else.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.do =  func(step) me._call(me._do, step);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, ''step'' is 1 for button pressed, and 0 for mod-up, pretty much standard for repeatable button code.&lt;br /&gt;
&lt;br /&gt;
When ''myFunction.do'' is called it executes ''me._call(me._do, step)''. It calls lines 10 onwards of ''timedControl'', passing ''me._do'' and ''step'' as parameters. The ''me'' is the way ''timedControl'' references itself, so if you have multiple buttons using the method, using ''me'' makes sure that you are always using the right ''timeout_dur'' or ''last_busy'', etc.&lt;br /&gt;
&lt;br /&gt;
Now let's look at lines 10 onwards of ''timedControl''. &lt;br /&gt;
&lt;br /&gt;
Line 10 receives the call ''_call'' with the parameters ''me._do'' and ''step'', which it renames to ''fn'' and ''arg.'' &lt;br /&gt;
&lt;br /&gt;
Line 11: If the value of ''arg'', and hence the value of ''step'' is 0, it means mod-up (the button was released.) It sets the value of ''last_busy'' to 0 and returns. ''It does nothing further''.&lt;br /&gt;
&lt;br /&gt;
Line 12: Ignore for the moment.&lt;br /&gt;
&lt;br /&gt;
Line 13: Ignore for the moment.&lt;br /&gt;
&lt;br /&gt;
Line 14: Sets the variable ''time'' to ''system''. This is the current date and time, accurate to fractions of a millisecond.&lt;br /&gt;
&lt;br /&gt;
Line 15: Remember, ''last_busy'' was initialised to 0. This line checks if the sum of ''timeout_dur'' and ''last_busy'' is more than the current time. It isn't, since ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
Line 16: ''last_busy'' is set to current time.&lt;br /&gt;
&lt;br /&gt;
Line 18: The function returns, calling ''fn'' with parameter ''arg''.&lt;br /&gt;
&lt;br /&gt;
Now ''fn'' is ''me._do''. ''me'' is of course ''myFunction''. So it is going to call a function by the name of ''myFunction._do''. This is the actual code that must be executed when the joystick button is pressed. So we are going to need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction._do =  func(step) {&lt;br /&gt;
  ....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So your code gets executed. The button is still pressed. A little while later (based on system repeat rate) the button is called again and ''me._call'' is called again.&lt;br /&gt;
&lt;br /&gt;
Line 14: Updates the value of ''time''. It is now 2 milliseconds later.&lt;br /&gt;
&lt;br /&gt;
Line 15: ''last_busy'' was set to the current time last time through the call. Now ''time'' is less than ''last_busy'' + 0.25, so the call returns. Your code is not executed.&lt;br /&gt;
&lt;br /&gt;
This will continue until 0.25 seconds has elapsed. Then line 15 will not return, and your code will be executed. So, as long as the button is pressed, your code is repeated every 0.25 seconds.&lt;br /&gt;
&lt;br /&gt;
Now you release the button. mod-up passes 0 as ''step''. Now the important line is 11. ''arg'' is 0, so ''last_busy'' is reset to 0, and the call returns. If you press the button again, the whole cycle restarts again because ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
== Improving usability ==&lt;br /&gt;
On of the problems with using modifiers with joystick buttons is that, once set, the repeatable/non-repeatable value cannot be changed. This means that you need to group functions according to whether or not they are repeatable.&lt;br /&gt;
&lt;br /&gt;
Using ''timedControl'' you can make all your buttons repeatable and use the value of ''timeout'' duration to make them one-shot, the equivalent of non-repeatable.&lt;br /&gt;
&lt;br /&gt;
You use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = -1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now let's see what happens when the button is pressed and ''me'_call' is run.&lt;br /&gt;
&lt;br /&gt;
Line 13: ''timeout_dur'' is -1, ''last_busy'' is 0, so the code continues.&lt;br /&gt;
&lt;br /&gt;
Line 16 sets ''last_busy'' to the current time, and your code is called by line 18.&lt;br /&gt;
&lt;br /&gt;
The next time round, ''last_busy'' is not 0, so line 13 makes the function return. Your code is never called again, until mod-up resets ''last_busy'' to 0 again. You now have a non-repeatable action from a repeatable button, and you can, using modifiers, group the button actions in a way that makes sense to you.&lt;br /&gt;
&lt;br /&gt;
==  The joystick end of things ==&lt;br /&gt;
All this code is of course in a Nasal file which you create. Give it a suitable name, based on your joystick name, for example logitechlib.nas. Put it in the same folder as your joystick xml file.&lt;br /&gt;
&lt;br /&gt;
Then add this at the top of your xml file, just after all the &amp;lt;name&amp;gt; entries&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        if (!contains(globals, &amp;quot;logitechlib&amp;quot;)) {&lt;br /&gt;
          io.load_nasal(getprop(&amp;quot;/sim/fg-root&amp;quot;) ~ &amp;quot;/Input/Joysticks/Saitek/logitechlib.nas&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make all the affected buttons repeatable. Then use this for the bindings&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;logitechlib.myFunction.do(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
          &amp;lt;script&amp;gt;logitechlib.myFunction.do(0)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Making the declarations tidier ==&lt;br /&gt;
Currently, you need to do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = timedControl.new();&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It looks a bit neater if you have a helper function&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var createTimedControl = func(timeout) {&lt;br /&gt;
      var name = timedControl.new();&lt;br /&gt;
      name.timeout_dur = timeout;&lt;br /&gt;
      return name;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction = createTimedControl(0.25);&lt;br /&gt;
myOneShotFunction = createTimedControl(-1);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You still need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myRepeatFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
myOneShotFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myOneShotFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Further expansion ==&lt;br /&gt;
If you have a large &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61709</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61709"/>
		<updated>2013-07-22T08:08:30Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
The secret is in having a method of preventing a button from repeating until our chosen time has elapsed. It is possible, but messy, especially if you are doing this with a number of buttons, to do it inside the code for each button. It is much better to create a new type of button code. For this we need a class, and then create instances of this class for each controlled button. This, incidentally, is OOP, or Object Oriented Programming.&lt;br /&gt;
&lt;br /&gt;
Here is thew code to create the new class. It is called timedControl. I have added (unnecessary) open lines between each member of the class to make understanding easier.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var timedControl = {&lt;br /&gt;
      last_busy: 0,&lt;br /&gt;
&lt;br /&gt;
      timeout_dur: 1.0,&lt;br /&gt;
&lt;br /&gt;
      new: func() {&lt;br /&gt;
          return { parents:[me] };&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      _call: func(fn, arg) {&lt;br /&gt;
        if (!arg) { me.last_busy = 0; return; }&lt;br /&gt;
        if (me.timeout_dur != nil) {&lt;br /&gt;
          if ((me.timeout_dur == -1) and me.last_busy != 0) return;&lt;br /&gt;
          var time = systime();&lt;br /&gt;
          if (time &amp;lt; me.timeout_dur + me.last_busy) return;&lt;br /&gt;
          me.last_busy = time;&lt;br /&gt;
        }&lt;br /&gt;
        return call(fn, [arg], me);&lt;br /&gt;
      }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's assume that we have a function, ''myFunction'', which must only repeat every 0.25 seconds. We create it with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var myFunction = timedControl.new();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
While creating myFunction, it sets ''last_busy'' to 0 (line 2) and ''time_dur'' to 1.0 (line 4).&lt;br /&gt;
&lt;br /&gt;
and set the repeat rate to 0.25 seconds with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
''var myFunction = timedControl.new()'' calls lines 6, 7, 8 of ''timedControl''. This creates a new instance of ''timedControl'' named ''myFunction'' and returns a pointer to it. Now, whenever you use ''myControl'' it will point to where it exists in memory.&lt;br /&gt;
&lt;br /&gt;
''myFunction.timeout_dur = 0.25''. ''myFunction'' points to the function in memory, ''.timout_dur'' then points to where ''timeout_dur'' exists in memory and changes its value to 0.25. Line 4 of the code set it to 1.0, just so it has ''a'' value.&lt;br /&gt;
&lt;br /&gt;
Now we need something for the joystick button to call. Here we are using ''do'', but you could just as easily use ''perform'', or ''activate'', or anything else.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.do =  func(step) me._call(me._do, step);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, ''step'' is 1 for button pressed, and 0 for mod-up, pretty much standard for repeatable button code.&lt;br /&gt;
&lt;br /&gt;
When ''myFunction.do'' is called it executes ''me._call(me._do, step)''. It calls lines 10 onwards of ''timedControl'', passing ''me._do'' and ''step'' as parameters. The ''me'' is the way ''timedControl'' references itself, so if you have multiple buttons using the method, using ''me'' makes sure that you are always using the right ''timeout_dur'' or ''last_busy'', etc.&lt;br /&gt;
&lt;br /&gt;
Now let's look at lines 10 onwards of ''timedControl''. &lt;br /&gt;
&lt;br /&gt;
Line 10 receives the call ''_call'' with the parameters ''me._do'' and ''step'', which it renames to ''fn'' and ''arg.'' &lt;br /&gt;
&lt;br /&gt;
Line 11: If the value of ''arg'', and hence the value of ''step'' is 0, it means mod-up (the button was released.) It sets the value of ''last_busy'' to 0 and returns. ''It does nothing further''.&lt;br /&gt;
&lt;br /&gt;
Line 12: Ignore for the moment.&lt;br /&gt;
&lt;br /&gt;
Line 13: Ignore for the moment.&lt;br /&gt;
&lt;br /&gt;
Line 14: Sets the variable ''time'' to ''system''. This is the current date and time, accurate to fractions of a millisecond.&lt;br /&gt;
&lt;br /&gt;
Line 15: Remember, ''last_busy'' was initialised to 0. This line checks if the sum of ''timeout_dur'' and ''last_busy'' is more than the current time. It isn't, since ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
Line 16: ''last_busy'' is set to current time.&lt;br /&gt;
&lt;br /&gt;
Line 18: The function returns, calling ''fn'' with parameter ''arg''.&lt;br /&gt;
&lt;br /&gt;
Now ''fn'' is ''me._do''. ''me'' is of course ''myFunction''. So it is going to call a function by the name of ''myFunction._do''. This is the actual code that must be executed when the joystick button is pressed. So we are going to need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction._do =  func(step) {&lt;br /&gt;
  ....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So your code gets executed. The button is still pressed. A little while later (based on system repeat rate) the button is called again and ''me._call'' is called again.&lt;br /&gt;
&lt;br /&gt;
Line 14: Updates the value of ''time''. It is now 2 milliseconds later.&lt;br /&gt;
&lt;br /&gt;
Line 15: ''last_busy'' was set to the current time last time through the call. Now ''time'' is less than ''last_busy'' + 0.25, so the call returns. Your code is not executed.&lt;br /&gt;
&lt;br /&gt;
This will continue until 0.25 seconds has elapsed. Then line 15 will not return, and your code will be executed. So, as long as the button is pressed, your code is repeated every 0.25 seconds.&lt;br /&gt;
&lt;br /&gt;
Now you release the button. mod-up passes 0 as ''step''. Now the important line is 11. ''arg'' is 0, so ''last_busy'' is reset to 0, and the call returns. If you press the button again, the whole cycle restarts again because ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
== Improving usability ==&lt;br /&gt;
On of the problems with using modifiers with joystick buttons is that, once set, the repeatable/non-repeatable value cannot be changed. This means that you need to group functions according to whether or not they are repeatable.&lt;br /&gt;
&lt;br /&gt;
Using ''timedControl'' you can make all your buttons repeatable and use the value of ''timeout'' duration to make them one-shot, the equivalent of non-repeatable.&lt;br /&gt;
&lt;br /&gt;
You use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = -1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now let's see what happens when the button is pressed and ''me'_call' is run.&lt;br /&gt;
&lt;br /&gt;
Line 13: ''timeout_dur'' is -1, ''last_busy'' is 0, so the code continues.&lt;br /&gt;
&lt;br /&gt;
Line 16 sets ''last_busy'' to the current time, and your code is called by line 18.&lt;br /&gt;
&lt;br /&gt;
The next time round, ''last_busy'' is not 0, so line 13 makes the function return. Your code is never called again, until mod-up resets ''last_busy'' to 0 again. You now have a non-repeatable action from a repeatable button, and you can, using modifiers, group the button actions in a way that makes sense to you.&lt;br /&gt;
&lt;br /&gt;
==  The joystick end of things ==&lt;br /&gt;
All this code is of course in a Nasal file which you create. Give it a suitable name, based on your joystick name, for example logitechlib.nas. Put it in the same folder as your joystick xml file.&lt;br /&gt;
&lt;br /&gt;
Then add this at the top of your xml file, just after all the &amp;lt;name&amp;gt; entries&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot; line&amp;gt;&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        if (!contains(globals, &amp;quot;logitechlib&amp;quot;)) {&lt;br /&gt;
          io.load_nasal(getprop(&amp;quot;/sim/fg-root&amp;quot;) ~ &amp;quot;/Input/Joysticks/Saitek/logitechlib.nas&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Making the declarations tidier ==&lt;br /&gt;
Currently, you need to do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = timedControl.new();&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It looks a bit neater if you have a helper function&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var createTimedControl = func(timeout) {&lt;br /&gt;
      var name = timedControl.new();&lt;br /&gt;
      name.timeout_dur = timeout;&lt;br /&gt;
      return name;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction = createTimedControl(0.25);&lt;br /&gt;
myOneShotFunction = createTimedControl(-1);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You still need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myRepeatFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
myOneShotFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myOneShotFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Further expansion ==&lt;br /&gt;
If you have a large &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61708</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61708"/>
		<updated>2013-07-22T07:55:34Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
The secret is in having a method of preventing a button from repeating until our chosen time has elapsed. It is possible, but messy, especially if you are doing this with a number of buttons, to do it inside the code for each button. It is much better to create a new type of button code. For this we need a class, and then create instances of this class for each controlled button. This, incidentally, is OOP, or Object Oriented Programming.&lt;br /&gt;
&lt;br /&gt;
Here is thew code to create the new class. It is called timedControl. I have added (unnecessary) open lines between each member of the class to make understanding easier.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var timedControl = {&lt;br /&gt;
      last_busy: 0,&lt;br /&gt;
&lt;br /&gt;
      timeout_dur: 1.0,&lt;br /&gt;
&lt;br /&gt;
      new: func() {&lt;br /&gt;
          return { parents:[me] };&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      _call: func(fn, arg) {&lt;br /&gt;
        if (!arg) { me.last_busy = 0; return; }&lt;br /&gt;
        if (me.timeout_dur != nil) {&lt;br /&gt;
          if ((me.timeout_dur == -1) and me.last_busy != 0) return;&lt;br /&gt;
          var time = systime();&lt;br /&gt;
          if (time &amp;lt; me.timeout_dur + me.last_busy) return;&lt;br /&gt;
          me.last_busy = time;&lt;br /&gt;
        }&lt;br /&gt;
        return call(fn, [arg], me);&lt;br /&gt;
      }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's assume that we have a function, ''myFunction'', which must only repeat every 0.25 seconds. We create it with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var myFunction = timedControl.new();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
While creating myFunction, it sets ''last_busy'' to 0 (line 2) and ''time_dur'' to 1.0 (line 4).&lt;br /&gt;
&lt;br /&gt;
and set the repeat rate to 0.25 seconds with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
''var myFunction = timedControl.new()'' calls lines 6, 7, 8 of ''timedControl''. This creates a new instance of ''timedControl'' named ''myFunction'' and returns a pointer to it. Now, whenever you use ''myControl'' it will point to where it exists in memory.&lt;br /&gt;
&lt;br /&gt;
''myFunction.timeout_dur = 0.25''. ''myFunction'' points to the function in memory, ''.timout_dur'' then points to where ''timeout_dur'' exists in memory and changes its value to 0.25. Line 4 of the code set it to 1.0, just so it has ''a'' value.&lt;br /&gt;
&lt;br /&gt;
Now we need something for the joystick button to call. Here we are using ''do'', but you could just as easily use ''perform'', or ''activate'', or anything else.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.do =  func(step) me._call(me._do, step);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, ''step'' is 1 for button pressed, and 0 for mod-up, pretty much standard for repeatable button code.&lt;br /&gt;
&lt;br /&gt;
When ''myFunction.do'' is called it executes ''me._call(me._do, step)''. It calls lines 10 onwards of ''timedControl'', passing ''me._do'' and ''step'' as parameters. The ''me'' is the way ''timedControl'' references itself, so if you have multiple buttons using the method, using ''me'' makes sure that you are always using the right ''timeout_dur'' or ''last_busy'', etc.&lt;br /&gt;
&lt;br /&gt;
Now let's look at lines 10 onwards of ''timedControl''. &lt;br /&gt;
&lt;br /&gt;
Line 10 receives the call ''_call'' with the parameters ''me._do'' and ''step'', which it renames to ''fn'' and ''arg.'' &lt;br /&gt;
&lt;br /&gt;
Line 11: If the value of ''arg'', and hence the value of ''step'' is 0, it means mod-up (the button was released.) It sets the value of ''last_busy'' to 0 and returns. ''It does nothing further''.&lt;br /&gt;
&lt;br /&gt;
Line 12: Ignore for the moment.&lt;br /&gt;
&lt;br /&gt;
Line 13: Ignore for the moment.&lt;br /&gt;
&lt;br /&gt;
Line 14: Sets the variable ''time'' to ''system''. This is the current date and time, accurate to fractions of a millisecond.&lt;br /&gt;
&lt;br /&gt;
Line 15: Remember, ''last_busy'' was initialised to 0. This line checks if the sum of ''timeout_dur'' and ''last_busy'' is more than the current time. It isn't, since ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
Line 16: ''last_busy'' is set to current time.&lt;br /&gt;
&lt;br /&gt;
Line 18: The function returns, calling ''fn'' with parameter ''arg''.&lt;br /&gt;
&lt;br /&gt;
Now ''fn'' is ''me._do''. ''me'' is of course ''myFunction''. So it is going to call a function by the name of ''myFunction._do''. This is the actual code that must be executed when the joystick button is pressed. So we are going to need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction._do =  func(step) {&lt;br /&gt;
  ....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So your code gets executed. The button is still pressed. A little while later (based on system repeat rate) the button is called again and ''me._call'' is called again.&lt;br /&gt;
&lt;br /&gt;
Line 14: Updates the value of ''time''. It is now 2 milliseconds later.&lt;br /&gt;
&lt;br /&gt;
Line 15: ''last_busy'' was set to the current time last time through the call. Now ''time'' is less than ''last_busy'' + 0.25, so the call returns. Your code is not executed.&lt;br /&gt;
&lt;br /&gt;
This will continue until 0.25 seconds has elapsed. Then line 15 will not return, and your code will be executed. So, as long as the button is pressed, your code is repeated every 0.25 seconds.&lt;br /&gt;
&lt;br /&gt;
Now you release the button. mod-up passes 0 as ''step''. Now the important line is 11. ''arg'' is 0, so ''last_busy'' is reset to 0, and the call returns. If you press the button again, the whole cycle restarts again because ''last_busy'' is 0.&lt;br /&gt;
&lt;br /&gt;
== Improving usability ==&lt;br /&gt;
On of the problems with using modifiers with joystick buttons is that, once set, the repeatable/non-repeatable value cannot be changed. This means that you need to group functions according to whether or not they are repeatable.&lt;br /&gt;
&lt;br /&gt;
Using ''timedControl'' you can make all your buttons repeatable and use the value of ''timeout'' duration to make them one-shot, the equivalent of non-repeatable.&lt;br /&gt;
&lt;br /&gt;
You use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = -1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now let's see what happens when the button is pressed and ''me'_call' is run.&lt;br /&gt;
&lt;br /&gt;
Line 13: ''timeout_dur'' is -1, ''last_busy'' is 0, so the code continues.&lt;br /&gt;
&lt;br /&gt;
Line 16 sets ''last_busy'' to the current time, and your code is called by line 18.&lt;br /&gt;
&lt;br /&gt;
The next time round, ''last_busy'' is not 0, so line 13 makes the function return. Your code is never called again, until mod-up resets ''last_busy'' to 0 again. You now have a non-repeatable action from a repeatable button, and you can, using modifiers, group the button actions in a way that makes sense to you.&lt;br /&gt;
&lt;br /&gt;
== Making the declarations tidier ==&lt;br /&gt;
Currently, you need to do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction = timedControl.new();&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It looks a bit neater if you have a helper function&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var createTimedControl = func(timeout) {&lt;br /&gt;
      var name = timedControl.new();&lt;br /&gt;
      name.timeout_dur = timeout;&lt;br /&gt;
      return name;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction = createTimedControl(0.25);&lt;br /&gt;
myOneShotFunction = createTimedControl(-1);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You still need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myRepeatFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myRepeatFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
myOneShotFunction.do = func(step) me._call(me._do, step);&lt;br /&gt;
myOneShotFunction._do = func(step) {&lt;br /&gt;
  ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
myOneShotFunction = createTimedControl(-1);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61707</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61707"/>
		<updated>2013-07-22T07:11:19Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
The secret is in having a method of preventing a button from repeating until our chosen time has elapsed. It is possible, but messy, especially if you are doing this with a number of buttons, to do it inside the code for each button. It is much better to create a new type of button code. For this we need a class, and then create instances of this class for each controlled button. This, incidentally, is OOP, or Object Oriented Programming.&lt;br /&gt;
&lt;br /&gt;
Here is thew code to create the new class. It is called timedControl. I have added (unnecessary) open lines between each member of the class to make understanding easier.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var timedControl = {&lt;br /&gt;
      last_busy: 0,&lt;br /&gt;
&lt;br /&gt;
      timeout_dur: 1.0,&lt;br /&gt;
&lt;br /&gt;
      new: func() {&lt;br /&gt;
          return { parents:[me] };&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      _call: func(fn, arg) {&lt;br /&gt;
        if (!arg) { me.last_busy = 0; return; }&lt;br /&gt;
        if (me.timeout_dur != nil) {&lt;br /&gt;
          if ((me.timeout_dur == -1) and me.last_busy != 0) return;&lt;br /&gt;
          var time = systime();&lt;br /&gt;
          if (time &amp;lt; me.timeout_dur + me.last_busy) return;&lt;br /&gt;
          me.last_busy = time;&lt;br /&gt;
        }&lt;br /&gt;
        return call(fn, [arg], me);&lt;br /&gt;
      }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's assume that we have a function, ''myFunction'', which must only repeat every 0.25 seconds. We create it with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var myFunction = timedControl.new();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
While creating myFunction, it sets ''last_busy'' to 0 (line 2) and ''time_dur'' to 1.0 (line 4).&lt;br /&gt;
&lt;br /&gt;
and set the repeat rate to 0.25 seconds with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
''var myFunction = timedControl.new()'' calls lines 6, 7, 8 of ''timedControl''. This creates a new instance of ''timedControl'' named ''myFunction'' and returns a pointer to it. Now, whenever you use ''myControl'' it will point to where it exists in memory.&lt;br /&gt;
&lt;br /&gt;
''myFunction.timeout_dur = 0.25''. ''myFunction'' points to the function in memory, ''.timout_dur'' then points to where ''timeout_dur'' exists in memory and changes its value to 0.25. Line 4 of the code set it to 1.0, just so it has ''a'' value.&lt;br /&gt;
&lt;br /&gt;
Now we need something for the joystick button to call. Here we are using ''do'', but you could just as easily use ''perform'', or ''activate'', or anything else.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.do =  func(step) me._call(me._do, step);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, ''step'' is 1 for button pressed, and 0 for mod-up, pretty much standard for repeatable button code.&lt;br /&gt;
&lt;br /&gt;
When ''myFunction.do'' is called it executes ''me._call(me._do, step)''. It calls lines 10 onwards of ''timedControl'', passing ''me._do'' and ''step'' as parameters. The ''me'' is the way ''timedControl'' references itself, so if you have multiple buttons using the method, using ''me'' makes sure that you are always using the right ''timeout_dur'' or ''last_busy'', etc.&lt;br /&gt;
&lt;br /&gt;
Now let's look at lines 10 onwards of ''timedControl''. &lt;br /&gt;
Line 10 receives the call ''_call'' with the parameters ''me._do'' and ''step'', which it renames to ''fn'' and ''arg.'' &lt;br /&gt;
Line 11: If the value of ''arg'', and hence the value of ''step'' is 0, it means mod-up (the button was released.) It sets the value of ''last_busy'' to 0 and returns. ''It does nothing further''.&lt;br /&gt;
Line 12: Ignore for the moment.&lt;br /&gt;
Line 13: Ignore for the moment.&lt;br /&gt;
Line 14: Sets the variable ''time'' to ''system''. This is the current date and time, accurate to fractions of a millisecond.&lt;br /&gt;
Line 15: Remember, ''last_busy';' was initialised to 0. This line checks if the sum of ''timeout_dur'' and ''last_busy'' is more than the current time. It isn't, since ''last_busy'' is 0.&lt;br /&gt;
Line 16: ''last_busy'' is set to current time.&lt;br /&gt;
Line 18: The function returns, calling ''fn'' with parameter ''arg''.&lt;br /&gt;
&lt;br /&gt;
Now ''fn'' is ''me._do''. ''me'' is of course ''myFunction''. So it is going to call a function by the name of ''myFunction._do''. This is the actual code that must be executed when the joystick button is pressed. So we are going to need&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction._do =  func(step) {&lt;br /&gt;
  ....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61706</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61706"/>
		<updated>2013-07-22T06:35:05Z</updated>

		<summary type="html">&lt;p&gt;Macnab: /* How it is done */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
The secret is in having a method of preventing a button from repeating until our chosen time has elapsed. It is possible, but messy, especially if you are doing this with a number of buttons, to do it inside the code for each button. It is much better to create a new type of button code. For this we need a class, and then create instances of this class for each controlled button. This, incidentally, is OOP, or Object Oriented Programming.&lt;br /&gt;
&lt;br /&gt;
Here is thew code to create the new class. It is called timedControl. I have added (unnecessary) open lines between each member of the class to make understanding easier.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var timedControl = {&lt;br /&gt;
      last_busy: 0,&lt;br /&gt;
&lt;br /&gt;
      timeout_dur: 1.0,&lt;br /&gt;
&lt;br /&gt;
      new: func() {&lt;br /&gt;
          return { parents:[me] };&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      _call: func(fn, arg) {&lt;br /&gt;
        if (!arg) { me.last_busy = 0; return; }&lt;br /&gt;
        if (me.timeout_dur != nil) {&lt;br /&gt;
          if ((me.timeout_dur == -1) and me.last_busy != 0) return;&lt;br /&gt;
          var time = systime();&lt;br /&gt;
          if (time &amp;lt; me.timeout_dur + me.last_busy) return;&lt;br /&gt;
          me.last_busy = time;&lt;br /&gt;
        }&lt;br /&gt;
        return call(fn, [arg], me);&lt;br /&gt;
      }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let's assume that we have a function, ''myFunction'', which must only repeat every 0.25 seconds. We create it with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var myFunction = timedControl.new();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and set the repeat rate to 0.25 seconds with&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
myFunction.timeout_dur = 0.25;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
''var myFunction = timedControl.new()'' calls lines 6, 7, 8 of ''timedControl''. This creates a new instance of ''timedControl'' named ''myFunction'' and returns a pointer to it. Now, whenever you use ''myControl'' it will point to where it exists in memory.&lt;br /&gt;
&lt;br /&gt;
''myFunction.timeout_dur = 0.25''. ''myFunction'' points to the function in memory, ''.timout_dur'' then points to where ''timeout_dur'' exists in memory and changes its value to 0.25. Line 4 of the code set it to 1.0, just so it has ''a'' value.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61705</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61705"/>
		<updated>2013-07-22T06:14:26Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
The secret is in having a method of preventing a button from repeating until our chosen time has elapsed. It is possible, but messy, especially if you are doing this with a number of buttons, to do it inside the code for each button. It is much better to create a new type of button code. For this we need a class, and then create instances of this class for each controlled button. This, incidentally, is OOP, or Object Oriented Programming.&lt;br /&gt;
&lt;br /&gt;
Here is thew code to create the new class. It is called timedControl. I have added (unnecessary) open lines between each member of the class to make understanding easier. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot; line&amp;gt;&lt;br /&gt;
var timedControl = {&lt;br /&gt;
      last_busy: 0,&lt;br /&gt;
&lt;br /&gt;
      timeout_dur: 1.0,&lt;br /&gt;
&lt;br /&gt;
      new: func() {&lt;br /&gt;
          return { parents:[me] };&lt;br /&gt;
      },&lt;br /&gt;
&lt;br /&gt;
      _call: func(fn, arg) {&lt;br /&gt;
        if (!arg) { me.last_busy = 0; me.tap = 0; return; } # Stop if arg = 0. Clear values.&lt;br /&gt;
        if (me.timeout_dur != nil) {&lt;br /&gt;
          if ((me.timeout_dur == -1) and me.last_busy != 0) return; # One-shot&lt;br /&gt;
          var time = systime();&lt;br /&gt;
          if (time &amp;lt; me.timeout_dur + me.last_busy) return; # check timeout_dur has elapsed&lt;br /&gt;
          me.last_busy = time;&lt;br /&gt;
        }&lt;br /&gt;
        return call(fn, [arg], me);&lt;br /&gt;
      }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61704</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61704"/>
		<updated>2013-07-22T06:00:10Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
Sometimes you might want to have control over the speed that a repeatable button works - maybe you want it to repeat ''exactly'' every 1.325 seconds, or you just want to slow it down. At the end of this article you will be shown how to use a button to set the frequency of a radio. This is certainly a time when the default (system) repeat rate of a button is too fast.&lt;br /&gt;
&lt;br /&gt;
== How it is done ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61703</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61703"/>
		<updated>2013-07-22T05:43:55Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
{{Navbar}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61702</id>
		<title>Accurate control of button repeat rate</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Accurate_control_of_button_repeat_rate&amp;diff=61702"/>
		<updated>2013-07-22T05:39:25Z</updated>

		<summary type="html">&lt;p&gt;Macnab: Created page with &amp;quot;{{WIP}} {{Navbar}} {{Transclude}}     Category:Hardware Category:Howto&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
{{Navbar}}&lt;br /&gt;
{{Transclude}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Convert_objects_from_X-Plane&amp;diff=61678</id>
		<title>Howto:Convert objects from X-Plane</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Convert_objects_from_X-Plane&amp;diff=61678"/>
		<updated>2013-07-19T15:27:34Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This [[:Category:Howto|tutorial]] explains how to '''convert X-Plane scenery objects''' to the [[File Formats#.2A.ac|AC3D format]] (.ac) used by [[FlightGear]] (mostly) automatically using the xplane2fg collection of scripts. To convert '''Microsoft (R) Flight Simulator scenery objects''', first convert them to X-Plane format using [http://marginal.org.uk/x-planescenery/tools.html FS2XPlane], then follow the method described below.&lt;br /&gt;
&lt;br /&gt;
These scripts were developed on Linux and should work fine on any Unix system including Mac ([[Howto: Convert objects from MSFS#Note to Windows Users|note to Windows users]]).&lt;br /&gt;
&lt;br /&gt;
The conversion consists of three steps, all conveniently handled by scripts:&lt;br /&gt;
* convert the actual 3-D objects from .obj to .ac format using blender,&lt;br /&gt;
* extract position of objects (longitude, latitude, altitude, and heading) from .dsf file(s) and write them to FlightGear's .stg file(s),&lt;br /&gt;
* copy the objects and their textures to the respective tile folders.&lt;br /&gt;
&lt;br /&gt;
This Howto assumes that you&lt;br /&gt;
* are able to use the command line to enter basic commands&lt;br /&gt;
* know where FlightGear, its scenery, and its source code are installed&lt;br /&gt;
&lt;br /&gt;
'''Please note: objects that are uploaded to the [[FlightGear Scenery Database]] (and thus official FG scenery) must be released under the [[GNU GPL]] license. Most X-Plane/MSFS scenery does ''not'' comply with this license. Therefore, it cannot be included with the official scenery, unless the author granted you permission to release his work under GNU GPL. Basically, it mostly means that it is for your own private use only.'''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Installation and setup ==&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
Besides a Unix environment, you'll need the following tools:&lt;br /&gt;
&lt;br /&gt;
* [http://ubuntuone.com/0sAOY4lB1OVCWP3zy8jfn8 xplane2fg]&lt;br /&gt;
* [http://www.blender.org Blender] (tested with ver. 2.48a-r3)&lt;br /&gt;
* XPlane2blender from [http://marginal.org.uk/x-planescenery/tools.html Jonathan Harris' page], tested with ver. 3.09&lt;br /&gt;
* [http://winehq.com Wine]&lt;br /&gt;
* [http://scenery.x-plane.com/tools.php X-Plane scenery tools]&lt;br /&gt;
* [[FlightGear]]&lt;br /&gt;
* perl helpers from FlightGear's [http://www.flightgear.org/Downloads/source.shtml source code]:&lt;br /&gt;
** calc-tile.pl&lt;br /&gt;
** find_elevations.pl&lt;br /&gt;
* telnet&lt;br /&gt;
&lt;br /&gt;
Optionally (if the scenery to convert contains .dds textures)&lt;br /&gt;
* convert (from [http://www.imagemagick.org ImageMagick])&lt;br /&gt;
&lt;br /&gt;
=== Installation ===&lt;br /&gt;
Install xplane2fg:&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/fgfs/convert/&lt;br /&gt;
 cd ~/fgfs/convert/&lt;br /&gt;
 tar xzf /path/to/xplane2fg.tgz&lt;br /&gt;
&lt;br /&gt;
Copy the autoimport.py helper to Blender's scripts folder:&lt;br /&gt;
 cp ~/fgfs/convert/xplane2fg/lib/autoimport.py ~/.blender/scripts&lt;br /&gt;
&lt;br /&gt;
Install X-Plane tools in $HOME/convert/xptools&lt;br /&gt;
&lt;br /&gt;
=== Hack the tools ===&lt;br /&gt;
For the first step - importing objects into blender - we use Jonathan Harris' XPlane2Blender import filter. The .ac export filter shipped with Blender does the export. As we will batch convert a large number of objects, both import and export filters need to be 'hacked' as to not stop and wait for user interaction on warnings etc:&lt;br /&gt;
&lt;br /&gt;
Open XPlaneImport.py in a text editor, change line 466 (of ver. 3.09) to: &lt;br /&gt;
 self.verbose = 0&lt;br /&gt;
Save this file as XPlaneImportVerbose0.py&lt;br /&gt;
&lt;br /&gt;
Open ac3d_export.py (part of Blender, located for example in /usr/share/blender/scripts/) in a text editor, replace line 823: &lt;br /&gt;
 Blender.Draw.PupMenu('ERROR: no objects selected')&lt;br /&gt;
with &lt;br /&gt;
 pass&lt;br /&gt;
Make sure you keep indention. Save this file as ac3d_export_hack.py&lt;br /&gt;
&lt;br /&gt;
=== Setting up the environment according to your system ===&lt;br /&gt;
The xplane2fg scripts glue together a number of tools. To have the scripts find these tools, you have to adjust the paths in $HOME/fgfs/convert/xplane2fg/profile according to your system (using a text editor).&lt;br /&gt;
&lt;br /&gt;
Now everything should be set up to actually convert scenery!&lt;br /&gt;
&lt;br /&gt;
== Conversion ==&lt;br /&gt;
First load xplane2fg's environment profile:&lt;br /&gt;
 source $HOME/fgfs/convert/xplane2fg/profile&lt;br /&gt;
&lt;br /&gt;
=== Prepare X-Plane scenery ===&lt;br /&gt;
In the following, we assume the X-Plane scenery we want to convert is named EDDN (make sure it contains no spaces!) and lives in&lt;br /&gt;
  $HOME/fgfs/convert/EDDN/&lt;br /&gt;
with the following sub folders&lt;br /&gt;
    Earth nav data&lt;br /&gt;
    objects&lt;br /&gt;
    textures&lt;br /&gt;
&lt;br /&gt;
Those sub folders may have slightly different names. If so, rename them to fit the above scheme. Remember that Unix file names are case sensitive.&lt;br /&gt;
&lt;br /&gt;
=== Prepare FlightGear ===&lt;br /&gt;
X-Plane objects are positioned using [http://en.wikipedia.org/wiki/Above_ground_level AGL], while FlightGear's .stg files expect [http://en.wikipedia.org/wiki/Above_mean_sea_level AMSL]. We will use FlightGear to automatically query the elevation at the object's postition. Therefore, the corresponding scenery tile must be installed. Find out on which tile the scenery you want to convert is located. See [[Howto: Install scenery]] for details on how to install FlightGear scenery. The most convenient way may be to use [[TerraSync]].&lt;br /&gt;
&lt;br /&gt;
=== Convert ===&lt;br /&gt;
Now run the main conversion script:&lt;br /&gt;
 cd $HOME/fgfs/convert/&lt;br /&gt;
 xplane2fg.sh  EDDN  EDDN.fg&lt;br /&gt;
&lt;br /&gt;
The converted scenery will be written to the path indicated by the second argument, EDDN.fg. It should '''not''' point to FG's actual scenery paths.&lt;br /&gt;
&lt;br /&gt;
After some seconds, this will stop and ask you to run blender. By that time, it should have created an input file for blender named&lt;br /&gt;
 blender-autoimport-source.py&lt;br /&gt;
in the current directory.&lt;br /&gt;
  &lt;br /&gt;
Now open a second terminal and run blender from that directory.&lt;br /&gt;
 cd $HOME/fgfs/convert&lt;br /&gt;
 blender&lt;br /&gt;
&lt;br /&gt;
Click file -&amp;gt; import -&amp;gt; autoimport, it should now convert all objects, this may take a while.&lt;br /&gt;
When finished, close blender (and the second terminal), and press {{Key press|Enter}} in the xplane2fg terminal.&lt;br /&gt;
  &lt;br /&gt;
xplane2fg will now fire up FlightGear. Press {{Key press|Enter}} when FlightGear is up and running.&lt;br /&gt;
The script then queries the elevation for all objects; this might take a while.&lt;br /&gt;
During this process, .stg files are written to their respective tile paths under EDDN.fg. Also, xplane2fg searches for texture files used by the scenery objects, copies them to EDDN.fg or complains in case they're missing.&lt;br /&gt;
  &lt;br /&gt;
When xplane2fg is finished, you should have something like&lt;br /&gt;
  ls $HOME/fgfs/convert/EDDN.fg/Objects/e000n40/e006n46/&lt;br /&gt;
      3056136.stg&lt;br /&gt;
      3056139.stg&lt;br /&gt;
      Terminal.ac&lt;br /&gt;
      ...&lt;br /&gt;
&lt;br /&gt;
We're almost done!&lt;br /&gt;
&lt;br /&gt;
=== Check textures ===&lt;br /&gt;
X-Plane may use .dds textures, which '''can''' be converted to .png format. However, following recent discussion on the developers mailing list, FlightGear/OSG can also use .dds textures. Hence, you may also skip this step. I have not tested using .dds textures with FlightGear. Your milage may vary.&lt;br /&gt;
&lt;br /&gt;
Go to the converted scenery folder&lt;br /&gt;
 cd EDDN.fg/Objects/e000n40/e006n46/&lt;br /&gt;
and run&lt;br /&gt;
 check_and_fix_textures.sh  *.ac&lt;br /&gt;
You may want to remove .dds files afterwards to save space:&lt;br /&gt;
 rm *.dds&lt;br /&gt;
&lt;br /&gt;
=== Integrate the converted files into FlightGear scenery ===&lt;br /&gt;
Finally you have to copy the converted scenery to FlightGear's scenery folder. Make sure to backup the respective scenery folder beforehand.&lt;br /&gt;
&lt;br /&gt;
The .stg files should be '''appended''' instead of overwritten should they exist already in FlightGear's Scenery folder; otherwise you'll lose previously defined scenery objects. You may want to use a file manager such as Konqueror, Nautilus, or Midnight Commander for this step, as they tend to ask whether to overwrite or append existing files.&lt;br /&gt;
&lt;br /&gt;
Now you can fire up FlightGear and enjoy the converted scenery!&lt;br /&gt;
&lt;br /&gt;
== Final steps ==&lt;br /&gt;
=== Cleanup ===&lt;br /&gt;
Temporary files were written to $HOME/fgfs/convert/tmp. You can remove them now:&lt;br /&gt;
 rm -rf $HOME/fgfs/convert/tmp&lt;br /&gt;
&lt;br /&gt;
=== Share the converted scenery ===&lt;br /&gt;
If you want to publish the scenery you need to obtain authorization to do so from the scenery's original authors.&lt;br /&gt;
&lt;br /&gt;
If you want it to be included in FlightGear's official scenery via the [[FlightGear Scenery Database]], the converted scenery (including all textures) must comply with the [[GNU GPL]].&lt;br /&gt;
&lt;br /&gt;
=== Optional ===&lt;br /&gt;
You may use&lt;br /&gt;
&lt;br /&gt;
 xplane2fg.sh --prefix EDDN_  EDDN  EDDN.fg&lt;br /&gt;
&lt;br /&gt;
to prepend all converted objects with a prefix, e.g., EDDN_objectname.ac&lt;br /&gt;
&lt;br /&gt;
=== Troubleshooting ===&lt;br /&gt;
xplane2fg.sh may complain about funny elevations reported by FlightGear:&lt;br /&gt;
&lt;br /&gt;
 WARNING: Zero alt for LSGS-grasss-1.ac?&lt;br /&gt;
 &lt;br /&gt;
I suspect this happens when a tile is just being loaded in background, as subsequent calls would return correct elevation. However, since we might query objects floating on water, I did not implement automatic retrying (yet). Instead, you should manually query these objects. Start Flightgear&lt;br /&gt;
&lt;br /&gt;
 xplane2fg.sh --run-fgfs&lt;br /&gt;
&lt;br /&gt;
then run&lt;br /&gt;
&lt;br /&gt;
 xplane2fg.sh --query-alt LSGS-grasss-1.ac&lt;br /&gt;
&lt;br /&gt;
which would return something like&lt;br /&gt;
&lt;br /&gt;
 OBJECT_STATIC LSGS-grasss-1.ac 7.3416857 46.2201743 482.24 357.99&lt;br /&gt;
 in /e000n40/e007n46/3072521.stg&lt;br /&gt;
&lt;br /&gt;
and correct the respective line in the indicated .stg file.&lt;br /&gt;
&lt;br /&gt;
=== Note to Windows Users ===&lt;br /&gt;
I developed these scripts on Linux. They are written in bash and make heavy use of GNU utilities (sed, awk, grep etc.). Some helpers require Perl. &lt;br /&gt;
To run these scripts on Windows, you will need to install cygwin and perl (at least). You will have to fix some further issues yourself; the wine part, for example, is probably not necessary on Windows ;)&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto|Convert objects from X-Plane]]&lt;br /&gt;
[[Category:Scenery enhancement|Convert objects from X-Plane]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Improving_the_Joystick_GUI&amp;diff=61396</id>
		<title>Improving the Joystick GUI</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Improving_the_Joystick_GUI&amp;diff=61396"/>
		<updated>2013-07-10T07:04:54Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Mentored Volunteer Effort&lt;br /&gt;
|mentors= macnab, Philosopher, Hooray, Stuart (review/commit), Zakalawe (C++ hooks [http://flightgear.org/forums/viewtopic.php?f=18&amp;amp;t=18530#p172461])&lt;br /&gt;
|skills=[[PropertyList XML File]], [[Property Tree]], [[Nasal|Nasal scripting]], fgcommands, [[Howto:Making HTTP Requests from Nasal|Nasal/Web scripting]]}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
We once talked about integrating the various Nasal capabilities added by Macnab and Philosopher right into Stuart's new JS config dialog - back then, Stuart &amp;amp; Zakalawe actually seemed supportive of the idea. And it would indeed not require many customizations to allow bindings to become fully runtime-configurable, including Nasal bindings and a standard library of general-purpose Nasal/JS APIs. UI-wise, we could simply reuse/integrate the existing Nasal console, so that bindings can be dynamically added and edited. At the end of the day, it's all XML, Nasal and the property tree, and some fgcommands to reinit stuff - so if people still think, that'd be useful, please speak-up and share your feature requests / ideas here.&lt;br /&gt;
&lt;br /&gt;
Also see [[User:Philosopher/Advanced Input Programming]].&lt;br /&gt;
&lt;br /&gt;
== Status 07/2013 ==&lt;br /&gt;
Stuart being the developer and maintainer of the latest Joystick GUI, here's his feedback:&lt;br /&gt;
&lt;br /&gt;
'''Stuart''':&lt;br /&gt;
Adding the ability to write Nasal for a given button was something I considered, but didn't implement. Partly this was due to time constraints, but it was also because I didn't think there was a use-case for it. The joystick configuration dialog is really targeted at new users who don't have any XML or Nasal experience. IMO anyone who knows enough to write Nasal joystick bindings will have enough knowledge to edit the joystick XML files directly and use the Nasal Console.&lt;br /&gt;
&lt;br /&gt;
On a different note, I'm interested to see what bindings people are using on joysticks, to check that the set of button bindings that are supported in the configuration dialog are sufficient. &lt;br /&gt;
&lt;br /&gt;
At present the dialog supports trim settings, but sets the button to be repeatable. Is there are a particular reason for not using the repeatable flag, or is it purely for people who have mode-switches and might have another (non-repeatable) function assigned to the button?&lt;br /&gt;
&lt;br /&gt;
I'm very happy if someone wants to expand the Joystick GUI to include advanced features such as modifier keys, and support for arbritary Nasal snippets. I also very much like the idea of re-implementing it in Canvas, as I had to make some design decisions purely on the basis of what was possible through the XML GUI code. &lt;br /&gt;
&lt;br /&gt;
If someone is working on this, it would be good to add support to allow setting of the joystick deadband - this is something that I simply haven't had the time to add.&lt;br /&gt;
&lt;br /&gt;
Finally, one point that I'm sure you will bear in mind: It's critical that it remains easy to use for new users. In particular, I spent some time determining the minimum set of bindings that were really required so that someone programming their joystick for the first time wouldn't be overloaded by a massive list of possible key bindings. It might be worth having an &amp;quot;Advanced bindings&amp;quot; option that enables modifier keys and the more esoteric bindings. For example, my yoke has a slider switch that I use to control the sensitivity of the view movement control. That's really useful for my yoke in particular, but probably doesn't generalize.&lt;br /&gt;
&lt;br /&gt;
Finally, I'm very happy to review any code that people want to submit, though I apologize in advance if it takes me a little time.&lt;br /&gt;
&lt;br /&gt;
== Roadmap ==&lt;br /&gt;
&lt;br /&gt;
=== Misc ===&lt;br /&gt;
* To me the first step would be to have the UI include at least one &amp;quot;Modifier&amp;quot; button and/or keyboard modifiers. Then the UI can have the option of switching views between modified/not modified. This will give more available actions.&lt;br /&gt;
&lt;br /&gt;
=== repeatable flag ===&lt;br /&gt;
* Between us we can come up with the &amp;quot;actions&amp;quot; and code. If we can get &amp;quot;on the fly&amp;quot; switching between repeatable/non-repeatable that would make a great addition/change for Version 3.&lt;br /&gt;
** To make this work we definitely need to get around the repeatable/non-repeatable limitation first.&lt;br /&gt;
** making the repeatable flag runtime configurable should be pretty straightforward for anybody familiar with the JS code and property tree listeners (SGPropertyChangeListener).&lt;br /&gt;
** Without on-the-fly switching between repeatable/non-repeatable switching to modified view would have to limit the available actions to repeatable/non-repeatable based on the unmodified action.&lt;br /&gt;
** It will need FGCommands to do it. Then the specific joystick code can set/clear it according to needs. If no FGCommand is sent it must stay the way it is for compatibility with existing joystick xml files.&lt;br /&gt;
** there are obviously several ways to skin this cat - no matter if it's fgcommands or listeners - I just believe listeners to be more &amp;quot;direct&amp;quot;, i.e. by simply replicating the whole config file through the property tree and just waiting for events that change things, and automatically reparsing/re-initializing things - that's after all, how the AP, AI system or the canvas work, without necessarily requiring fgcommands. On the other hand, Stuart -as the author of the JS dialog- seems to prefer fgcommands over listeners (see his clouds API). So at the end of the day it all boils down to who gets around to implementing it. It doesn't really matter if it's through listeners or fgcommands (or even something else).&lt;br /&gt;
** Note that the upcoming FG releases (beyond 2.12+) will include a new Nasal API for registering invididual Nasal functions as fgcommands, so that you can have very compact joystick bindings by making up new, joystick-specific, fgcommands&lt;br /&gt;
** it's basically the same, except obviously more universal (C++ code can use it too). It also looks better (to me) as it just used the &amp;lt;command&amp;gt; tag instead of a function call with all those tags around it (&amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&amp;lt;script&amp;gt;call_function()&amp;lt;/script&amp;gt;), and it of course requires &amp;quot;arguments&amp;quot; to be in the property tree (they can be retrieved using cmdarg() or the first argument passed to the callback function). For example, I could register a &amp;quot;Cyborg-X-axis&amp;quot; fgcommand&lt;br /&gt;
**  this is probably going to be what bindings will look like in the future, simply because we can easily maintain a generic standard Nasal library for joystick code, without individual bindings having to be aware of implementation details - so this is pretty much the &amp;quot;frontend&amp;quot;, and what things will look like to end-users, or the joystick GUI, while the backend would be based on generic and unified Nasal snippets dealing with Joystick/Yokes, Pedals etc - that would allow us provide a &amp;quot;stable frontend API&amp;quot; through Nasal-based fgcommands, whereas the back-end could evolve as needed - and the front-end would be easily editable through a corresponding GUI dialog. It would then even be possible to merge the Nasal console into everything, so that backend snippets become also customizable at runtime. Basically, more flexibility, with less coding required for people who do not want to look into scripting - also, no need for cdata or XML escaping&lt;br /&gt;
&lt;br /&gt;
* Being able to edit the generated code would be nice for those who are capable of tweaking it. (Such as a personal preference for slew-rate.) Dynamic re-inits would also be good.&lt;br /&gt;
&lt;br /&gt;
=== GUI ===&lt;br /&gt;
* The UI can be worded carefully so that less-experienced users can understand the concept of doubling-up on button actions.&lt;br /&gt;
* And for doing it in Canvas. And for all buttons to be implemented in a nas file, not the xml file. (Standard axes can stay in the xml file.)&lt;br /&gt;
* For the axes, along with deadband, power as well. (With a slider in the GUI?)&lt;br /&gt;
* Maybe the start page with only the basic bindings, and 3 buttons: Basic, Medium and Advanced that change the view? &lt;br /&gt;
&lt;br /&gt;
=== Updating ===&lt;br /&gt;
* Something that occurs to me is that once the system is out there people will make requests for bindings that don't exist yet. If these are implemented, unless the people use Git, they will have to wait for a new release to see them. So maybe a system where they can download just the necessary files, which be the GUI and the new glorified version of controls.nas.&lt;br /&gt;
** You could provide custom bindings as self-contained PropertyList-encoded XML files with embedded Nasal sections - FlightGear already supports loading PropertyList XML files via network, which is how the multiplayer list is loaded dynamically. In other words, you could take these building blocks and load/share arbitrary stuff via network, including custom joystick bindings. For details, see: Howto:Making HTTP Requests from Nasal. The tutorial also demonstrates how to use a simple web server (in fact, a single line in python) to serve a FG GUI XML file that shows a FG GUI dialog with a custom message (&amp;quot;Hello World&amp;quot;).&lt;br /&gt;
** the tutorial uses the official fgdata repository to dynamically download the latest XML/Nasal stuff - and we've been talking about using such a method for automatically updating the Nasal APIs of the Canvas system. Also, Zakalawe is planning to provide a feature to allow aircraft to be downloaded at runtime using WebDAV (see the wiki)&lt;br /&gt;
**  we could simply use $FG_HOME for persistence/caching - either by using the &amp;quot;userarchive&amp;quot; attribute on all JS-related snippets, so that they become persistent between sessions (see $FG_HOME/autosave.xml) or by using a custom PropertyList-XML file that stores downloaded snippets and uses a hash to check if they were already downloaded and/or need to be updated. Thus, you would only need to be online when downloading things - later on, everything would be persistent/cached.&lt;br /&gt;
** also, by convention, fgdata has usually been considered (and installed) as read-only - especially on &amp;quot;true&amp;quot; multi-user systems, so this should be kept in mind - it simply makes sense to have user-specific stuff in $FG_HOME, i.e. a user-specific directory for application settings. Just look at how TerraSync solves the same problem basically - because it also cannot modify $FG_ROOT, but still needs to download and store tons of data.&lt;br /&gt;
** The library and GUI will have to be put in a read/write folder. It does mean making FG look for it in the correct place - non-standard.&lt;br /&gt;
** There are a bunch of Nasal wrappers available in io.nas for loading Nasal code from different places, and there are helpers in gui.nas to load GUI dialogs from non-standard places. Keep in mind how we have a bunch of Nasal code and custom GUI dialogs in most aircraft folders, which are also &amp;quot;non-standard&amp;quot; - so that's a no-brainer.&lt;br /&gt;
&lt;br /&gt;
== Team ==&lt;br /&gt;
Please feel free to add your name to this list if you are willing and able to help.&lt;br /&gt;
&lt;br /&gt;
=== Mentors ===&lt;br /&gt;
* Hooray&lt;br /&gt;
&lt;br /&gt;
=== Joystick GUI ===&lt;br /&gt;
* Philosopher&lt;br /&gt;
&lt;br /&gt;
=== Nasal Joystick Routines ===&lt;br /&gt;
* macnab. I already have a large collection of of what would be classified as Advanced (or even Esoteric) functions written in Nasal.&lt;br /&gt;
&lt;br /&gt;
=== C++ Code ===&lt;br /&gt;
* Zakalawe&lt;br /&gt;
&lt;br /&gt;
=== Review/Commit ===&lt;br /&gt;
* Stuart&lt;br /&gt;
&lt;br /&gt;
== Ideas/Suggestions ==&lt;br /&gt;
Please add any ideas or suggestions you may have which are not listed above.&lt;br /&gt;
&lt;br /&gt;
== Related ==&lt;br /&gt;
* http://flightgear.org/forums/viewtopic.php?f=24&amp;amp;t=20324&lt;br /&gt;
* http://flightgear.org/forums/viewtopic.php?f=18&amp;amp;t=18530&lt;br /&gt;
* http://flightgear.org/forums/viewtopic.php?f=24&amp;amp;t=17892&lt;br /&gt;
&lt;br /&gt;
[[Category:Core development projects]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Talk:TerraSync&amp;diff=59850</id>
		<title>Talk:TerraSync</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Talk:TerraSync&amp;diff=59850"/>
		<updated>2013-05-03T04:54:47Z</updated>

		<summary type="html">&lt;p&gt;Macnab: Created page with &amp;quot;Shouldn't there be a link to download Terrasync? It is not (or no longer) in the daily CMake set.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Shouldn't there be a link to download Terrasync? It is not (or no longer) in the daily CMake set.&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57681</id>
		<title>Using a Nasal file with a joystick Part 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57681"/>
		<updated>2013-02-04T07:53:56Z</updated>

		<summary type="html">&lt;p&gt;Macnab: /* Nasal equivalents to xml code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In [[Using a Nasal file with a joystick]] you saw how to get started. &lt;br /&gt;
This article goes into it in more depth.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  First Steps  ==&lt;br /&gt;
Backup your xml file. &lt;br /&gt;
Print it, you need to know which button does what.&lt;br /&gt;
If you have a Nasal file, back it up too. &lt;br /&gt;
If you haven't read the first part, read it and do the basic implementation now.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Modifying your xml file ==&lt;br /&gt;
This seems like a lot of work, but it is worth it in the end.&lt;br /&gt;
You need to use the labels of the buttons on your joystick. &lt;br /&gt;
You will use these labels for the name of the Nasal function to call in your nasal file.&lt;br /&gt;
For each button in your xml file, change your code. Here, the button is labelled &amp;quot;1&amp;quot;. &lt;br /&gt;
And remember, we are talking about the label printed on the joystick, not the button number &lt;br /&gt;
&lt;br /&gt;
assigned by the operating system.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1()&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Of course, nasfilename is the name of your Nasal file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you have a modifier button, named ''mymod'', then do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(mymod)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you use the keyboard Shift, Ctrl or Alt buttons as a modifier, you do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-shift&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(2)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-shift&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you use 2 keyboard buttons then you would need another &amp;lt;mod-...&amp;gt; section, and pass the value 3. &lt;br /&gt;
To help you remember, add a comment at the top of your Nasal file to remind you what the values mean.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If your button needs a mod-up, then do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1()&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;nasfilename.button1Up()&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
but this is very seldom needed. Of course, if you use modifiers you need to pass the number of the modifier in the brackets.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You could use 2 modifiers simultaneously. The Saitek Pro Flight Yoke has a Mode Switch, which needs special methods to access it - see [[Using Saitek Pro Flight Yoke Mode Switch]], then could have a case where you have these modes (which simulate using the keyboard Shift, Ctrl and Alt keys) as well as a modifier button on the joystick.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In such a case do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;6&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as C1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;repeatable&amp;gt;true&amp;lt;/repeatable&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;saitekyoke.buttonC1(saitekAlter, 1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-shift&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;saitekyoke.buttonC2(saitekAlter, 2)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-shift&amp;gt;&lt;br /&gt;
    &amp;lt;mod-ctrl&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;saitekyoke.buttonC1(saitekAlter, 3)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-ctrl&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, saitekAlter is the value (0 or 1) of the modifier button, and the 1, 2 and 3 represent the position of the Mode Switch.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now do this for all the buttons.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Contents of the Nasal file  ==&lt;br /&gt;
&lt;br /&gt;
===  The blank file  ===&lt;br /&gt;
For each button you need a function defined. In our simplest example above you need&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func {&lt;br /&gt;
        ... code goes here ...&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you pass the value of a modifier button then it is slightly different. &lt;br /&gt;
&lt;br /&gt;
Assuming that your modifier button is 0 for not pressed and 1 for pressed, we can make use of the fact that in Nasal 0 represents false, and any other value represents true.&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func(mod) {&lt;br /&gt;
    if (mod) {&lt;br /&gt;
      ... code for modifier button pressed goes here ...&lt;br /&gt;
    } else {&lt;br /&gt;
      ... code for modifier not pressed goes here ...&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When have values other than just 0 and 1 then you need specific if clauses&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func(mod) {&lt;br /&gt;
    if (mod == 1) {&lt;br /&gt;
      ... code for modifier value 1 goes here ...&lt;br /&gt;
    } &lt;br /&gt;
    if (mod == 2) {&lt;br /&gt;
      ... code for modifier value 2 goes here ...&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you have 2 modifiers, as in the case of the Saitek Yoke with modes and a modifier button, then you need to nest the if clauses.&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func(alter, mode) {&lt;br /&gt;
    if (mode == 1) {&lt;br /&gt;
       if (alter) {&lt;br /&gt;
         ... Mode 1, mod button pressed ...&lt;br /&gt;
       } else {&lt;br /&gt;
         ... Mode 1, mod button not pressed ...&lt;br /&gt;
       }&lt;br /&gt;
    } &lt;br /&gt;
    if (mode == 2) {&lt;br /&gt;
      if (alter) {&lt;br /&gt;
         ... Mode 2, mod button pressed ...&lt;br /&gt;
      } else {&lt;br /&gt;
         ... Mode 2, mod button not pressed ...&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
    if (mode == 3) {&lt;br /&gt;
      if (alter) {&lt;br /&gt;
         ... Mode 3, mod button pressed ...&lt;br /&gt;
      } else {&lt;br /&gt;
         ... Mode 3, mod button not pressed ...&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===  Populating the Nasal file  ===&lt;br /&gt;
&lt;br /&gt;
Now you need to put in all the code.&lt;br /&gt;
Have the printout of the xml file handy, it is easier than switching between files.&lt;br /&gt;
The equivalent code for most actions is available in numerous places, but some equivalents will be supplied below. And you can always ask on the Hardware forum for the Nasal equivalents of xml code.&lt;br /&gt;
&lt;br /&gt;
Enter all the code.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Testing your code  ===&lt;br /&gt;
&lt;br /&gt;
If you use an editor such as gedit (multi-platform, free) which has line-numbers, it makes the task soooo much easier.&lt;br /&gt;
&lt;br /&gt;
Run FG, keeping an eye on the &amp;quot;black window.&amp;quot; If you don't see Loading myfilename.nas, then there is a mistake in the xml file.&lt;br /&gt;
If you get a parse error when starting FG, then you have a basic mistake in your Nasal file. The first entry after parse error is the line number to look for.&lt;br /&gt;
If you get a parse when pressing a button, then the error is in the code for that button.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Nasal equivalents to xml code ==&lt;br /&gt;
&lt;br /&gt;
If your xml code has&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
  &amp;lt;script&amp;gt;blah blah&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
then you can use the bit between &amp;lt;script&amp;gt; and &amp;lt;/script&amp;gt; as is.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Elevator Trim&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;command&amp;gt;property-scale&amp;lt;/command&amp;gt;&lt;br /&gt;
  &amp;lt;property&amp;gt;/controls/flight/elevator&amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;factor type=&amp;quot;double&amp;quot;&amp;gt;1.0&amp;lt;/factor&amp;gt;&lt;br /&gt;
  &amp;lt;squared type=&amp;quot;bool&amp;quot;&amp;gt;true&amp;lt;/squared&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  controls.elevatorTrim(1);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The 1 becomes -1 for the other direction. Just substitute ''ruder'' and ''aileron'' for the others.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
View Direction&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;command&amp;gt;property-adjust&amp;lt;/command&amp;gt;&lt;br /&gt;
  &amp;lt;property&amp;gt;/sim/current-view/goal-heading-offset-deg&amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;step type=&amp;quot;double&amp;quot;&amp;gt;1.0&amp;lt;/step&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  controls.slewProp(&amp;quot;/sim/current-view/goal-heading-offset-deg&amp;quot;, 15);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can fiddle with the 15 to make it slower or faster. Make it -15 for the other direction. Change ''goal-heading'' to ''goal-pitch'' for up and down.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Zoom&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;command&amp;gt;property-adjust&amp;lt;/command&amp;gt;&lt;br /&gt;
  &amp;lt;property&amp;gt;/sim/current-view/field-of-view&amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;step type=&amp;quot;double&amp;quot;&amp;gt;0.5&amp;lt;/step&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
becomes&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  view.increase(0.5);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Use view.decrease to zoom out.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57680</id>
		<title>Using a Nasal file with a joystick Part 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57680"/>
		<updated>2013-02-04T07:26:46Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In [[Using a Nasal file with a joystick]] you saw how to get started. &lt;br /&gt;
This article goes into it in more depth.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  First Steps  ==&lt;br /&gt;
Backup your xml file. &lt;br /&gt;
Print it, you need to know which button does what.&lt;br /&gt;
If you have a Nasal file, back it up too. &lt;br /&gt;
If you haven't read the first part, read it and do the basic implementation now.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Modifying your xml file ==&lt;br /&gt;
This seems like a lot of work, but it is worth it in the end.&lt;br /&gt;
You need to use the labels of the buttons on your joystick. &lt;br /&gt;
You will use these labels for the name of the Nasal function to call in your nasal file.&lt;br /&gt;
For each button in your xml file, change your code. Here, the button is labelled &amp;quot;1&amp;quot;. &lt;br /&gt;
And remember, we are talking about the label printed on the joystick, not the button number &lt;br /&gt;
&lt;br /&gt;
assigned by the operating system.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1()&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Of course, nasfilename is the name of your Nasal file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you have a modifier button, named ''mymod'', then do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(mymod)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you use the keyboard Shift, Ctrl or Alt buttons as a modifier, you do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-shift&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(2)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-shift&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you use 2 keyboard buttons then you would need another &amp;lt;mod-...&amp;gt; section, and pass the value 3. &lt;br /&gt;
To help you remember, add a comment at the top of your Nasal file to remind you what the values mean.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If your button needs a mod-up, then do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1()&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;nasfilename.button1Up()&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
but this is very seldom needed. Of course, if you use modifiers you need to pass the number of the modifier in the brackets.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You could use 2 modifiers simultaneously. The Saitek Pro Flight Yoke has a Mode Switch, which needs special methods to access it - see [[Using Saitek Pro Flight Yoke Mode Switch]], then could have a case where you have these modes (which simulate using the keyboard Shift, Ctrl and Alt keys) as well as a modifier button on the joystick.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In such a case do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;6&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as C1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;repeatable&amp;gt;true&amp;lt;/repeatable&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;saitekyoke.buttonC1(saitekAlter, 1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-shift&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;saitekyoke.buttonC2(saitekAlter, 2)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-shift&amp;gt;&lt;br /&gt;
    &amp;lt;mod-ctrl&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;saitekyoke.buttonC1(saitekAlter, 3)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-ctrl&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, saitekAlter is the value (0 or 1) of the modifier button, and the 1, 2 and 3 represent the position of the Mode Switch.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now do this for all the buttons.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Contents of the Nasal file  ==&lt;br /&gt;
&lt;br /&gt;
===  The blank file  ===&lt;br /&gt;
For each button you need a function defined. In our simplest example above you need&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func {&lt;br /&gt;
        ... code goes here ...&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you pass the value of a modifier button then it is slightly different. &lt;br /&gt;
&lt;br /&gt;
Assuming that your modifier button is 0 for not pressed and 1 for pressed, we can make use of the fact that in Nasal 0 represents false, and any other value represents true.&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func(mod) {&lt;br /&gt;
    if (mod) {&lt;br /&gt;
      ... code for modifier button pressed goes here ...&lt;br /&gt;
    } else {&lt;br /&gt;
      ... code for modifier not pressed goes here ...&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When have values other than just 0 and 1 then you need specific if clauses&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func(mod) {&lt;br /&gt;
    if (mod == 1) {&lt;br /&gt;
      ... code for modifier value 1 goes here ...&lt;br /&gt;
    } &lt;br /&gt;
    if (mod == 2) {&lt;br /&gt;
      ... code for modifier value 2 goes here ...&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you have 2 modifiers, as in the case of the Saitek Yoke with modes and a modifier button, then you need to nest the if clauses.&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func(alter, mode) {&lt;br /&gt;
    if (mode == 1) {&lt;br /&gt;
       if (alter) {&lt;br /&gt;
         ... Mode 1, mod button pressed ...&lt;br /&gt;
       } else {&lt;br /&gt;
         ... Mode 1, mod button not pressed ...&lt;br /&gt;
       }&lt;br /&gt;
    } &lt;br /&gt;
    if (mode == 2) {&lt;br /&gt;
      if (alter) {&lt;br /&gt;
         ... Mode 2, mod button pressed ...&lt;br /&gt;
      } else {&lt;br /&gt;
         ... Mode 2, mod button not pressed ...&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
    if (mode == 3) {&lt;br /&gt;
      if (alter) {&lt;br /&gt;
         ... Mode 3, mod button pressed ...&lt;br /&gt;
      } else {&lt;br /&gt;
         ... Mode 3, mod button not pressed ...&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===  Populating the Nasal file  ===&lt;br /&gt;
&lt;br /&gt;
Now you need to put in all the code.&lt;br /&gt;
Have the printout of the xml file handy, it is easier than switching between files.&lt;br /&gt;
The equivalent code for most actions is available in numerous places, but some equivalents will be supplied below. And you can always ask on the Hardware forum for the Nasal equivalents of xml code.&lt;br /&gt;
&lt;br /&gt;
Enter all the code.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Testing your code  ===&lt;br /&gt;
&lt;br /&gt;
If you use an editor such as gedit (multi-platform, free) which has line-numbers, it makes the task soooo much easier.&lt;br /&gt;
&lt;br /&gt;
Run FG, keeping an eye on the &amp;quot;black window.&amp;quot; If you don't see Loading myfilename.nas, then there is a mistake in the xml file.&lt;br /&gt;
If you get a parse error when starting FG, then you have a basic mistake in your Nasal file. The first entry after parse error is the line number to look for.&lt;br /&gt;
If you get a parse when pressing a button, then the error is in the code for that button.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Nasal equivalents to xml code ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57675</id>
		<title>Using a Nasal file with a joystick Part 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57675"/>
		<updated>2013-02-04T07:13:16Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In [[Using a Nasal file with a joystick]] you saw how to get started. &lt;br /&gt;
This article goes into it in more depth.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  First Steps  ==&lt;br /&gt;
Backup your xml file. &lt;br /&gt;
Print it, you need to know which button does what.&lt;br /&gt;
&lt;br /&gt;
If you have a Nasal file, back it up too. &lt;br /&gt;
&lt;br /&gt;
If you haven't read the first part, read it and do the basic implementation now.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Modifying your xml file ==&lt;br /&gt;
This seems like a lot of work, but it is worth it in the end.&lt;br /&gt;
&lt;br /&gt;
You need to use the labels of the buttons on your joystick. &lt;br /&gt;
&lt;br /&gt;
You will use these labels for the name of the Nasal function to call in your nasal file.&lt;br /&gt;
&lt;br /&gt;
For each button in your xml file, change your code. Here, the button is labelled &amp;quot;1&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
And remember, we are talking about the label printed on the joystick, not the button number &lt;br /&gt;
&lt;br /&gt;
assigned by the operating system.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1()&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Of course, nasfilename is the name of your Nasal file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you have a modifier button, named ''mymod'', then do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(mymod)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you use the keyboard Shift, Ctrl or Alt buttons as a modifier, you do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-shift&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(2)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-shift&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you use 2 keyboard buttons then you would need another &amp;lt;mod-...&amp;gt; section, and pass the value 3. &lt;br /&gt;
&lt;br /&gt;
To help you remember, add a comment at the top of your Nasal file to remind you what the values mean.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If your button needs a mod-up, then do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1()&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;nasfilename.button1Up()&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
but this is very seldom needed. Of course, if you use modifiers you need to pass the number &lt;br /&gt;
&lt;br /&gt;
of the modifier in the brackets.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You could use 2 modifiers simultaneously. The Saitek Pro Flight Yoke has a Mode Switch, which &lt;br /&gt;
&lt;br /&gt;
needs special methods to access it - see [[Using Saitek Pro Flight Yoke Mode Switch]], then could &lt;br /&gt;
&lt;br /&gt;
have a case where you have these modes (which simulate using the keyboard Shift, Ctrl and Alt keys) &lt;br /&gt;
&lt;br /&gt;
as well as a modifier button on the joystick.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
In such a case do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;6&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as C1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;repeatable&amp;gt;true&amp;lt;/repeatable&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;saitekyoke.buttonC1(saitekAlter, 1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-shift&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;saitekyoke.buttonC2(saitekAlter, 2)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-shift&amp;gt;&lt;br /&gt;
    &amp;lt;mod-ctrl&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;saitekyoke.buttonC1(saitekAlter, 3)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-ctrl&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, saitekAlter is the value (0 or 1) of the modifier button, and the 1, 2 and 3 &lt;br /&gt;
&lt;br /&gt;
represent the position of the Mode Switch.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now do this for all the buttons.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Contents of the Nasal file  ==&lt;br /&gt;
&lt;br /&gt;
===  The blank file  ===&lt;br /&gt;
For each button you need a function defined. In our simplest example above you need&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func {&lt;br /&gt;
        ... code goes here ...&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you pass the value of a modifier button then it is slightly different. &lt;br /&gt;
&lt;br /&gt;
Assuming that your modifier button is 0 for not pressed and 1 for pressed, we can make use of the fact &lt;br /&gt;
&lt;br /&gt;
that in Nasal 0 represents false, and any other value represents true&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func(mod) {&lt;br /&gt;
    if (mod) {&lt;br /&gt;
      ... code for modifier button pressed goes here ...&lt;br /&gt;
    } else {&lt;br /&gt;
      ... code for modifier not pressed goes here ...&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When have values other than just 0 and 1 then you need specific if clauses&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func(mod) {&lt;br /&gt;
    if (mod == 1) {&lt;br /&gt;
      ... code for modifier value 1 goes here ...&lt;br /&gt;
    } &lt;br /&gt;
    if (mod == 2) {&lt;br /&gt;
      ... code for modifier value 2 goes here ...&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you have 2 modifiers, as in the case of the Saitek Yoke with modes and a modifier button, &lt;br /&gt;
&lt;br /&gt;
then you need to nest the if clauses&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func(alter, mode) {&lt;br /&gt;
    if (mode == 1) {&lt;br /&gt;
       if (alter) {&lt;br /&gt;
         ... Mode 1, mod button pressed ...&lt;br /&gt;
       } else {&lt;br /&gt;
         ... Mode 1, mod button not pressed ...&lt;br /&gt;
       }&lt;br /&gt;
    } &lt;br /&gt;
    if (mode == 2) {&lt;br /&gt;
      if (alter) {&lt;br /&gt;
         ... Mode 2, mod button pressed ...&lt;br /&gt;
      } else {&lt;br /&gt;
         ... Mode 2, mod button not pressed ...&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
    if (mode == 3) {&lt;br /&gt;
      if (alter) {&lt;br /&gt;
         ... Mode 3, mod button pressed ...&lt;br /&gt;
      } else {&lt;br /&gt;
         ... Mode 3, mod button not pressed ...&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57674</id>
		<title>Using a Nasal file with a joystick Part 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57674"/>
		<updated>2013-02-04T07:02:50Z</updated>

		<summary type="html">&lt;p&gt;Macnab: /* Modifying your xml file */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In [[Using a Nasal file with a joystick]] you saw how to get started. &lt;br /&gt;
This article goes into it in more depth.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  First Steps  ==&lt;br /&gt;
Backup your xml file. &lt;br /&gt;
Print it, you need to know which button does what.&lt;br /&gt;
If you have a Nasal file, back it up too. &lt;br /&gt;
If you haven't read the first part, read it and do the basic implementation now.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Modifying your xml file ==&lt;br /&gt;
This seems like a lot of work, but it is worth it in the end.&lt;br /&gt;
&lt;br /&gt;
You need to use the labels of the buttons on your joystick. &lt;br /&gt;
You will use these labels for the name of the Nasal function to call in your nasal file.&lt;br /&gt;
&lt;br /&gt;
For each button in your xml file, change your code. Here, the button is labelled &amp;quot;1&amp;quot;. &lt;br /&gt;
And remember, we are talking about the label printed on the joystick, not the button number &lt;br /&gt;
assigned by the operating system.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1()&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Of course, nasfilename is the name of your Nasal file.&lt;br /&gt;
&lt;br /&gt;
If you have a modifier button, named ''mymod'', then do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(mymod)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you use the keyboard Shift, Ctrl or Alt buttons as a modifier, you do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-shift&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(2)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-shift&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you use 2 keyboard buttons then you would need another &amp;lt;mod-...&amp;gt; section, and pass the value 3. &lt;br /&gt;
To help you remember, add a comment at the top of your Nasal file to remind you what the values mean.&lt;br /&gt;
&lt;br /&gt;
If your button needs a mod-up, then do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1()&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;nasfilename.button1Up()&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
but this is very seldom needed. Of course, if you use modifiers you need to pass the number &lt;br /&gt;
of the modifier in the brackets.&lt;br /&gt;
&lt;br /&gt;
You could use 2 modifiers simultaneously. The Saitek Pro Flight Yoke has a Mode Switch, which &lt;br /&gt;
needs special methods to access it - see [[Using Saitek Pro Flight Yoke Mode Switch]], then could &lt;br /&gt;
have a case where you have these modes (which simulate using the keyboard Shift, Ctrl and Alt keys) &lt;br /&gt;
as well as a modifier button on the joystick.&lt;br /&gt;
&lt;br /&gt;
In such a case do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;6&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as C1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;repeatable&amp;gt;true&amp;lt;/repeatable&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;saitekyoke.buttonC1(saitekAlter, 1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-shift&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;saitekyoke.buttonC2(saitekAlter, 2)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-shift&amp;gt;&lt;br /&gt;
    &amp;lt;mod-ctrl&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;saitekyoke.buttonC1(saitekAlter, 3)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-ctrl&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Here, saitekAlter is the value (0 or 1) of the modifier button, and the 1, 2 and 3 &lt;br /&gt;
represent the position of the Mode Switch.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now do this for all the buttons.&lt;br /&gt;
&lt;br /&gt;
==  Contents of the Nasal file  ==&lt;br /&gt;
&lt;br /&gt;
===  The blank file  ===&lt;br /&gt;
For each button you need a function defined. In our simplest example above you need&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func {&lt;br /&gt;
        ... code goes here ...&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you pass the value of a modifier button then it is slightly different. &lt;br /&gt;
Assuming that your modifier button is 0 for not pressed and 1 for pressed, we can make use of the fact &lt;br /&gt;
that in Nasal 0 represents false, and any other value represents true&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func(mod) {&lt;br /&gt;
    if (mod) {&lt;br /&gt;
      ... code for modifier button pressed goes here ...&lt;br /&gt;
    } else {&lt;br /&gt;
      ... code for modifier not pressed goes here ...&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57673</id>
		<title>Using a Nasal file with a joystick Part 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57673"/>
		<updated>2013-02-04T06:59:39Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In [[Using a Nasal file with a joystick]] you saw how to get started. &lt;br /&gt;
This article goes into it in more depth.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  First Steps  ==&lt;br /&gt;
Backup your xml file. &lt;br /&gt;
Print it, you need to know which button does what.&lt;br /&gt;
If you have a Nasal file, back it up too. &lt;br /&gt;
If you haven't read the first part, read it and do the basic implementation now.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Modifying your xml file ==&lt;br /&gt;
This seems like a lot of work, but it is worth it in the end.&lt;br /&gt;
&lt;br /&gt;
You need to use the labels of the buttons on your joystick. &lt;br /&gt;
You will use these labels for the name of the Nasal function to call in your nasal file.&lt;br /&gt;
&lt;br /&gt;
For each button in your xml file, change your code. Here, the button is labelled &amp;quot;1&amp;quot;. &lt;br /&gt;
And remember, we are talking about the label printed on the joystick, not the button number &lt;br /&gt;
assigned by the operating system.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1()&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Of course, nasfilename is the name of your Nasal file.&lt;br /&gt;
&lt;br /&gt;
If you have a modifier button, named ''mymod'', then do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(mymod)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you use the keyboard Shift, Ctrl or Alt buttons as a modifier, you do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-shift&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(2)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-shift&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you use 2 keyboard buttons then you would need another &amp;lt;mod-...&amp;gt; section, and pass the value 3. &lt;br /&gt;
To help you remember, add a comment at the top of your Nasal file to remind you what the values mean.&lt;br /&gt;
&lt;br /&gt;
If your button needs a mod-up, then do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1()&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;nasfilename.button1Up()&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
but this is very seldom needed. Of course, if you use modifiers you need to pass the number &lt;br /&gt;
of the modifier in the brackets.&lt;br /&gt;
&lt;br /&gt;
You could use 2 modifiers simultaneously. The Saitek Pro Flight Yoke has a Mode Switch, which &lt;br /&gt;
needs special methods to access it - see [[Using Saitek Pro Flight Yoke Mode Switch]], then could &lt;br /&gt;
have a case where you have these modes (which simulate using the keyboard Shift, Ctrl and Alt keys) &lt;br /&gt;
as well as a modifier button on the joystick.&lt;br /&gt;
&lt;br /&gt;
In such a case do this&lt;br /&gt;
&amp;lt;syntaxhightlight land=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;6&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as C1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;repeatable&amp;gt;true&amp;lt;/repeatable&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;saitekyoke.buttonC1(saitekAlter, 1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-shift&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;saitekyoke.buttonC2(saitekAlter, 2)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-shift&amp;gt;&lt;br /&gt;
    &amp;lt;mod-ctrl&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;saitekyoke.buttonC1(saitekAlter, 3)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-ctrl&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhightlight&amp;gt;&lt;br /&gt;
Here, saitekAlter is the value (0 or 1) of the modifier button, and the 1, 2 and 3 &lt;br /&gt;
represent the position of the Mode Switch.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now do this for all the buttons.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Contents of the Nasal file  ==&lt;br /&gt;
&lt;br /&gt;
===  The blank file  ===&lt;br /&gt;
For each button you need a function defined. In our simplest example above you need&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func {&lt;br /&gt;
        ... code goes here ...&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you pass the value of a modifier button then it is slightly different. &lt;br /&gt;
Assuming that your modifier button is 0 for not pressed and 1 for pressed, we can make use of the fact &lt;br /&gt;
that in Nasal 0 represents false, and any other value represents true&lt;br /&gt;
&amp;lt;syntaxhighlight lang =&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var button1 = func(mod) {&lt;br /&gt;
    if (mod) {&lt;br /&gt;
      ... code for modifier button pressed goes here ...&lt;br /&gt;
    } else {&lt;br /&gt;
      ... code for modifier not pressed goes here ...&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57672</id>
		<title>Using a Nasal file with a joystick Part 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57672"/>
		<updated>2013-02-04T06:47:17Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In [[Using a Nasal file with a joystick]] you saw how to get started. This article goes into it in more depth.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  First Steps  ==&lt;br /&gt;
Backup your xml file. &lt;br /&gt;
Print it, you need to know which button does what.&lt;br /&gt;
If you have a Nasal file, back it up too. &lt;br /&gt;
If you haven't read the first part, read it and do the basic implementation now.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Modifying your xml file ==&lt;br /&gt;
This seems like a lot of work, but it is worth it in the end.&lt;br /&gt;
&lt;br /&gt;
You need to use the labels of the buttons on your joystick. You will use these labels for the name of the Nasal function to call in your nasal file.&lt;br /&gt;
&lt;br /&gt;
For each button in your xml file, change your code. Here, the button is labelled &amp;quot;1&amp;quot;. And remember, we are talking about the label printed on the joystick, not the button number assigned by the operating system.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1()&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Of course, nasfilename is the name of your Nasal file.&lt;br /&gt;
&lt;br /&gt;
If you have a modifier button, named ''mymod'', then do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(mymod)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you use the keyboard Shift, Ctrl or Alt buttons as a modifier, you do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-shift&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(2)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-shift&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you use 2 keyboard buttons then you would need another &amp;lt;mod-...&amp;gt; section, and pass the value 3. To help you remember, add a comment at the top of your Nasal file to remind you what the values mean.&lt;br /&gt;
&lt;br /&gt;
If your button needs a mod-up, then do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1()&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-up&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;nasfilename.button1Up()&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-up&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
but this is very seldom needed. Of course, if you use modifiers you need to pass the number of the modifier in the brackets.&lt;br /&gt;
&lt;br /&gt;
You could use 2 modifiers simultaneously. The Saitek Pro Flight Yoke has a Mode Switch, which needs special methods to access it - see [[Using Saitek Pro Flight Yoke Mode Switch]], then could have a case where you have these modes (which simulate using the keyboard Shift, Ctrl and Alt keys) as well as a modifier button on the joystick.&lt;br /&gt;
&lt;br /&gt;
In such a case do this&lt;br /&gt;
&amp;lt;syntaxhightlight land=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;6&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as C1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;repeatable&amp;gt;true&amp;lt;/repeatable&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;saitekyoke.buttonC1(saitekAlter, 1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-shift&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;saitekyoke.buttonC2(saitekAlter, 2)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-shift&amp;gt;&lt;br /&gt;
    &amp;lt;mod-ctrl&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
        &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
        &amp;lt;script&amp;gt;saitekyoke.buttonC1(saitekAlter, 3)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-ctrl&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhightlight&amp;gt;&lt;br /&gt;
Here, saitekAlter is the value (0 or 1) of the modifier button, and the 1, 2 and 3 represent the position of the Mode Switch.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now do this for all the buttons.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Contents of the Nasal file  ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57671</id>
		<title>Using a Nasal file with a joystick Part 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57671"/>
		<updated>2013-02-04T06:34:02Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In [[Using a Nasal file with a joystick]] you saw how to get started. This article goes into it in more depth.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  First Steps  ==&lt;br /&gt;
Backup your xml file. &lt;br /&gt;
Print it, you need to know which button does what.&lt;br /&gt;
If you have a Nasal file, back it up too. &lt;br /&gt;
If you haven't read the first part, read it and do the basic implementation now.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Modifying your xml file ==&lt;br /&gt;
This seems like a lot of work, but it is worth it in the end.&lt;br /&gt;
&lt;br /&gt;
You need to use the labels of the buttons on your joystick. You will use these labels for the name of the Nasal function to call in your nasal file.&lt;br /&gt;
&lt;br /&gt;
For each button in your xml file, change your code. Here, the button is labelled &amp;quot;1&amp;quot;. And remember, we are talking about the label printed on the joystick, not the button number assigned by the operating system.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1()&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Of course, nasfilename is the name of your Nasal file.&lt;br /&gt;
&lt;br /&gt;
If you have a modifier button, named ''mymod'', then do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(mymod)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you use the keyboard Shift button as a modifier, you do this&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(1)&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;mod-shift&amp;gt;&lt;br /&gt;
      &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;nasfilename.button1(2)&amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;/binding&amp;gt;&lt;br /&gt;
    &amp;lt;/mod-shift&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57670</id>
		<title>Using a Nasal file with a joystick Part 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57670"/>
		<updated>2013-02-04T06:28:06Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In [[Using a Nasal file with a joystick]] you saw how to get started. This article goes into it in more depth.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  First Steps  ==&lt;br /&gt;
Backup your xml file. &lt;br /&gt;
Print it, you need to know which button does what.&lt;br /&gt;
If you have a Nasal file, back it up too. &lt;br /&gt;
If you haven't read the first part, read it and do the basic implementation now.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Modifying your xml file ==&lt;br /&gt;
This seems like a lot of work, but it is worth it in the end.&lt;br /&gt;
&lt;br /&gt;
You need to use the labels of the buttons on your joystick. You will use these labels for the name of the Nasal function to call in your nasal file.&lt;br /&gt;
&lt;br /&gt;
For each button in your xml file, change your code. Here, the button is labelled &amp;quot;1&amp;quot;. And remember, we are talking about the label printed on the joystick, not the button number assigned by the operating system.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;saitekyoke.button1()&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57669</id>
		<title>Using a Nasal file with a joystick Part 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57669"/>
		<updated>2013-02-04T06:26:59Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In [[Using a Nasal file with a joystick]] you saw how to get started. This article goes into it in more depth.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  First Steps  ==&lt;br /&gt;
Backup your xml file. &lt;br /&gt;
Print it, you need to know which button does what.&lt;br /&gt;
If you have a Nasal file, back it up too. &lt;br /&gt;
If you haven't read the first part, read it and do the basic implementation now.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Modifying your xml file ==&lt;br /&gt;
This seems like a lot of work, but it is worth it in the end.&lt;br /&gt;
&lt;br /&gt;
You need to use the labels of the buttons on your joystick. You will use these labels for the name of the Nasal function to call in your nasal file.&lt;br /&gt;
&lt;br /&gt;
For each button in your xml file, change your code. Here, the button is labelled &amp;quot;1&amp;quot;. And remember, we are talking about the label printed on the joystick, not the button number assigned by the operating system.&lt;br /&gt;
&amp;lt;syntaxhighlight=php&amp;gt;&lt;br /&gt;
  &amp;lt;button n=&amp;quot;xxx&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- Labled as 1 --&amp;gt;&lt;br /&gt;
    &amp;lt;desc&amp;gt;Whatever it does&amp;lt;/desc&amp;gt;&lt;br /&gt;
    &amp;lt;binding&amp;gt;&lt;br /&gt;
      &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
      &amp;lt;script&amp;gt;saitekyoke.button1()&amp;lt;/script&amp;gt;&lt;br /&gt;
    &amp;lt;/binding&amp;gt;&lt;br /&gt;
  &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57668</id>
		<title>Using a Nasal file with a joystick Part 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick_Part_2&amp;diff=57668"/>
		<updated>2013-02-04T06:13:47Z</updated>

		<summary type="html">&lt;p&gt;Macnab: Created page with &amp;quot;In Using a Nasal file with a joystick you saw how to get started. This article goes into it in more depth.    Category:Howto Category:Hardware&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In [[Using a Nasal file with a joystick]] you saw how to get started. This article goes into it in more depth.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick&amp;diff=57667</id>
		<title>Using a Nasal file with a joystick</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick&amp;diff=57667"/>
		<updated>2013-02-04T06:10:36Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
Sometimes the code for a button is quite complicated. Not only does it make your xml file larger and more difficult to go through, but writing the code in a dedicated Nasal file cane be a lot easier. There are things which are just easier that way. You may also have come across an example in the forums which you want to use, and you don't know how to do it.&lt;br /&gt;
&lt;br /&gt;
Whatever your reason for using a Nasal file, this is how to implement the Nasal file approach. Part 2, expands the idea and shows you just why it is easier.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Getting Started ==&lt;br /&gt;
&lt;br /&gt;
You are going to put your Nasal file in the same folder as your joystick's xml file. You need to choose a suitable name for the file. If your joystick is a KungFu ABC123 you could safely name the file abc123.nas. If, however, you have a Saitek yoke, you don't want to name the file yoke.nas, because in the Saitek folder is a Pro Flight Yoke and a Cessna Yoke, so you want to be more specific. Call the file cessnayoke.nas or proflightyoke.nas'&lt;br /&gt;
&lt;br /&gt;
The name you choose is visible ''everywhere'' in FG, so make sure you choose something unique.&lt;br /&gt;
&lt;br /&gt;
Notice that there are no capital letters.&lt;br /&gt;
&lt;br /&gt;
So open up your favourite text-editor, create a new file, and save it in your joystick's folder with the chosen filename. Don't forget that the extension must be .nas, and make sure your editor doesn't make it .nas.txt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Changes to your joystick's xml file  ==&lt;br /&gt;
&lt;br /&gt;
'''Save a copy of your xml file in a safe place, one that you will remember.'''&lt;br /&gt;
&lt;br /&gt;
For the sake of this exercise we will assume that you have a KungFu ABC123 joystick. So your nasal file is abc123.nas. &lt;br /&gt;
&lt;br /&gt;
Open the xml file.&lt;br /&gt;
&lt;br /&gt;
At the top, just after all the &amp;lt;name&amp;gt; entries, add this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
      ## begin of custom section&lt;br /&gt;
      var modulename = &amp;quot;abc123&amp;quot;; # customize this according to the namespace used&lt;br /&gt;
      var module_path = &amp;quot;/Input/Joysticks/KungFu/abc123.nas&amp;quot;; # customize this according to the file name/path&lt;br /&gt;
      ## end of custom section&lt;br /&gt;
&lt;br /&gt;
      var is_loaded = func (name) contains(globals,name);&lt;br /&gt;
&lt;br /&gt;
      if (!is_loaded(modulename)) {&lt;br /&gt;
        io.load_nasal(getprop(&amp;quot;/sim/fg-root&amp;quot;) ~ module_path);&lt;br /&gt;
      }&lt;br /&gt;
  &lt;br /&gt;
      abc123.initABC123(); # customize init routine&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ''if (!contains...'' bit (if not contains) makes sure that the nas file is loaded only once.&lt;br /&gt;
&lt;br /&gt;
The ''abc123.initABC123'' cals an initialise routine in the nas file. We haven't created it yet. Notice the ''abc123''. This tells FG which nas file to use. The ''initABC123'' is which routine in that nas file to call. The ''()'' is because it is a function.&lt;br /&gt;
&lt;br /&gt;
Save your xml file and open the nas file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Adding routines to the nas file  ==&lt;br /&gt;
&lt;br /&gt;
We have just told the xml file to call initABC123, so we better add it to the nas file.&lt;br /&gt;
&lt;br /&gt;
At the top of the file add&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var initABC123 = func() {&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Every new thing in Nasal starts with '''var'''. That is followed by its name (initABC123). Then we must assign it to something. In this case it is a function, so we write '''= func()'''. If you want to pass a value to the function (we aren't here), you give a name to the value between the brackets, and place the value to pass between the brackets in the xml file. The '''{''' and '''}''' mark the start and end of the function (what it does.) It doesn't currently do anything, so there is nothing between them.&lt;br /&gt;
&lt;br /&gt;
Now we need to make at least one button call a function in the nas file. Let's assume you have a button labelled D on your joystick. So we will have a function called buttonD. If it is the only red button, you could call the function redButton.&lt;br /&gt;
&lt;br /&gt;
So we add&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var buttonD = func() {&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once again, it doesn't do anything yet.&lt;br /&gt;
&lt;br /&gt;
Save the nas file and open the xml file. Go to where the D button is handled.&lt;br /&gt;
&lt;br /&gt;
Between the &amp;lt;binding&amp;gt; and &amp;lt;/binding&amp;gt; we add our call to the nas file. We get&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
    &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;abc123.buttonD()&amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, when button D is pressed, it will call the function '''buttonD''' in abc123.nas. You just need to put the correct code in the function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To make your nas file a bit more use-friendly, open it and at right at the top add&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
print(&amp;quot;Loading abc123.nas&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, when you run FG, along with all the other info in the &amp;quot;black window&amp;quot; you will see ''Loading abc123.nas'' when the joystick xml file loads. This not only confirms that it has loaded, but if you have a parse error in your nas file it will be reported, and you can fix it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Notes  ==&lt;br /&gt;
&lt;br /&gt;
This article does not supply any coding for actions, it is just to get you started. A sort of template. See Part 2 for more details.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When naming Nasal functions, the convention is to use camel coding. That is, the first word in the name starts with a lower-case letter, all subsequent words star with an upper-case letter. The can be no spaces in the name. If you want to separate words use an underscore (_).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So valid names would be startDividingByThree, start_Dividing_By_Three, adjRadioFrequency.&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Changing_repeat_rate_of_joystick_buttons&amp;diff=57639</id>
		<title>Changing repeat rate of joystick buttons</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Changing_repeat_rate_of_joystick_buttons&amp;diff=57639"/>
		<updated>2013-02-03T08:14:56Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
If you are new to writing Nasal functions for joysticks, read [[Using a Nasal file with a joystick]] first.&lt;br /&gt;
&lt;br /&gt;
==  Background ==&lt;br /&gt;
&lt;br /&gt;
Sometimes the repeat rate of joystick buttons is too high. The value changes so fast that you can't set it accurately. In your joystick xml file you could use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;whatever&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;interval-sec&amp;gt;x.xx&amp;lt;/interval-sec&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where x.xx is the time between button action repeats. This has the problem that the delay is implemented at the start of the button press, as well as between repeats. It is also not as versatile as using this method.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Changes (additions) to the Nasal file ==&lt;br /&gt;
&lt;br /&gt;
You must have set up everything according to [[Using a Nasal file with a joystick]] so that your joystick button calls a routine in a Nasal file, as per the next paragraph.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assume that the button in question is labelled &amp;quot;C&amp;quot;. The property we want to change with the button is '''/mythical/telescope-colour'''. Our nas file is called mynasfile.nas. We will use a flag called busyTelescope to control the repeat rate.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Start off by adding the function for the button&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var buttonC = func {&lt;br /&gt;
        if (getprop(&amp;quot;/busyTelescope&amp;quot;)) return;&lt;br /&gt;
  &lt;br /&gt;
        setprop(&amp;quot;/busyTelescope&amp;quot;, 1);&lt;br /&gt;
  &lt;br /&gt;
        ... Code to adjust telescope property goes here  ..&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now when the button is pressed the busy flag will be set, the code will be called. As soon as FG repeats the button, the set state of the busy flag will make the routine return. So far so good.&lt;br /&gt;
&lt;br /&gt;
We still need to create the busy flag, set the repeat rate we want, and clear the busy flag between (our) repeats.&lt;br /&gt;
&lt;br /&gt;
At the top of the nas file add&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var buttonRate = 0.1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is the number of seconds we want ''between'' repeats. In this case it is 100 milliseconds.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Then we need to create the busy flag. This must be done in an init routine. Add to the init routine&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  props.globals.getNode(&amp;quot;/busyTelescope&amp;quot;, 1);&lt;br /&gt;
  setprop(&amp;quot;/busyTelescope&amp;quot;, 0);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
We now have the flag, and it is cleared.&lt;br /&gt;
&lt;br /&gt;
We still need to clear it at our required repeat rate. Add to the init routine&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  setlistener(&amp;quot;/busyTelescopy&amp;quot;, func { if (getprop(&amp;quot;/mythical/busyTelescope&amp;quot;)) settimer(busyTelescopeClear, buttonRate, 1); });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and add this function&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var busyTelescopeClear = func {&lt;br /&gt;
        setprop(&amp;quot;/busyTelescope&amp;quot;, 0);&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now, whenever the button is pressed, the flag gets set. The listener detects this and starts a timer, with delay buttonRate. When the delay elapses, busyTelescopeClear is called, which clears the flag, and the button will repeat.&lt;br /&gt;
&lt;br /&gt;
We now can control the repeat rate of the button.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Making the code safe ==&lt;br /&gt;
To avoid the busy flag possibly getting stuck in the true state, make the mod-up of your joystick call ''mynasfile.buttonCUp()''.&lt;br /&gt;
&lt;br /&gt;
Then add this to the nas file&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var buttonCUp = func {&lt;br /&gt;
        busyTelescopeClear()&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Other uses  ==&lt;br /&gt;
It is of course possible to use this technique for adding a delay in any nasal code, with appropriate changes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Changing_repeat_rate_of_joystick_buttons&amp;diff=57637</id>
		<title>Changing repeat rate of joystick buttons</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Changing_repeat_rate_of_joystick_buttons&amp;diff=57637"/>
		<updated>2013-02-03T08:14:27Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
If you are new to writing Nasal functions for joysticks, read [[Using a Nasal file with a joystick]] first.&lt;br /&gt;
&lt;br /&gt;
==  Background ==&lt;br /&gt;
&lt;br /&gt;
Sometimes the repeat rate of joystick buttons is too high. The value changes so fast that you can't set it accurately. In your joystick xml file you could use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;whatever&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;interval-sec&amp;gt;x.xx&amp;lt;/interval-sec&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where x.xx is the time between button action repeats. This has the problem that the delay is implemented at the start of the button press, as well as between repeats. It is also not as versatile as using this method.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Changes (additions) to the Nasal file ==&lt;br /&gt;
&lt;br /&gt;
You must have set up everything according to [[Using a Nasal file with a joystick]] so that your joystick button calls a routine in a Nasal file, as per the next paragraph.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assume that the button in question is labelled &amp;quot;C&amp;quot;. The property we want to change with the button is '''/mythical/telescope-colour'''. Our nas file is called mynasfile.nas. We will use a flag called busyTelescope to control the repeat rate.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Start off by adding the function for the button&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var buttonC = func {&lt;br /&gt;
        if (getprop(&amp;quot;/busyTelescope&amp;quot;)) return;&lt;br /&gt;
  &lt;br /&gt;
        setprop(&amp;quot;/busyTelescope&amp;quot;, 1);&lt;br /&gt;
  &lt;br /&gt;
        ... Code to adjust telescope property goes here  ..&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now when the button is pressed the busy flag will be set, the code will be called. As soon as FG repeats the button, the set state of the busy flag will make the routine return. So far so good.&lt;br /&gt;
&lt;br /&gt;
We still need to create the busy flag, set the repeat rate we want, and clear the busy flag between (our) repeats.&lt;br /&gt;
&lt;br /&gt;
At the top of the nas file add&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var buttonRate = 0.1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is the number of seconds we want ''between'' repeats. In this case it is 100 milliseconds.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Then we need to create the busy flag. This must be done in an init routine. Add to the init routine&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  props.globals.getNode(&amp;quot;/busyTelescope&amp;quot;, 1);&lt;br /&gt;
  setprop(&amp;quot;/busyTelescope&amp;quot;, 0);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
We now have the flag, and it is cleared.&lt;br /&gt;
&lt;br /&gt;
We still need to clear it at our required repeat rate. Add to the init routine&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  setlistener(&amp;quot;/busyTelescopy&amp;quot;, func { if (getprop(&amp;quot;/mythical/busyTelescope&amp;quot;)) settimer(busyTelescopeClear, buttonRate, 1); });&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and add this function&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var busyTelescopeClear = func {&lt;br /&gt;
        setprop(&amp;quot;/busyTelescope&amp;quot;, 0);&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now, whenever the button is pressed, the flag gets set. The listener detects this and starts a timer, with delay buttonRate. When the delay elapses, busyTelescopeClear is called, which clears the flag, and the button will repeat.&lt;br /&gt;
&lt;br /&gt;
We now can control the repeat rate of the button.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Making the code safe ==&lt;br /&gt;
To avoid the busy flag possibly getting stuck in the true state, make the mod-up of your joystick call ''mynasfile.buttonCUp()''.&lt;br /&gt;
&lt;br /&gt;
Then add this to the nas file&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
  var buttonCUp = func {&lt;br /&gt;
        busyTelescopeClear()&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Other uses  ==&lt;br /&gt;
It is of course possible to use this technique for adding a delay in any nasal code, with appropriate changes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Changing_repeat_rate_of_joystick_buttons&amp;diff=57636</id>
		<title>Changing repeat rate of joystick buttons</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Changing_repeat_rate_of_joystick_buttons&amp;diff=57636"/>
		<updated>2013-02-03T08:02:29Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
If you are new to writing Nasal functions for joysticks, read [[Using a Nasal file with a joystick]] first.&lt;br /&gt;
&lt;br /&gt;
==  Background ==&lt;br /&gt;
&lt;br /&gt;
Sometimes the repeat rate of joystick buttons is too high. The value changes so fast that you can't set it accurately. In your joystick xml file you could use&lt;br /&gt;
  &amp;lt;desc&amp;gt;whatever&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;interval-sec&amp;gt;x.xx&amp;lt;/interval-sec&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where x.xx is the time between button action repeats. This has the problem that the delay is implemented at the start of the button press, as well as between repeats. It is also not as versatile as using this method.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Changes (additions) to the Nasal file ==&lt;br /&gt;
&lt;br /&gt;
You must have set up everything according to [[Using a Nasal file with a joystick]] so that your joystick button calls a routine in a Nasal file, as per the next paragraph.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Assume that the button in question is labelled &amp;quot;C&amp;quot;. The property we want to change with the button is '''/mythical/telescope-colour'''. Our nas file is called mynasfile.nas. We will use a flag called busyTelescope to control the repeat rate.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Start off by adding the function for the button&lt;br /&gt;
  var buttonC = func {&lt;br /&gt;
        if (getprop(&amp;quot;/busyTelescope&amp;quot;)) return;&lt;br /&gt;
  &lt;br /&gt;
        setprop(&amp;quot;/busyTelescope&amp;quot;, 1);&lt;br /&gt;
  &lt;br /&gt;
        ... Code to adjust telescope property goes here  ..&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Now when the button is pressed the busy flag will be set, the code will be called. As soon as FG repeats the button, the set state of the busy flag will make the routine return. So far so good.&lt;br /&gt;
&lt;br /&gt;
We still need to create the busy flag, set the repeat rate we want, and clear the busy flag between (our) repeats.&lt;br /&gt;
&lt;br /&gt;
At the top of the nas file add&lt;br /&gt;
  var buttonRate = 0.1;&lt;br /&gt;
This is the number of seconds we want ''between'' repeats. In this case it is 100 milliseconds.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Then we need to create the busy flag. This must be done in an init routine. Add to the init routine&lt;br /&gt;
  props.globals.getNode(&amp;quot;/busyTelescope&amp;quot;, 1);&lt;br /&gt;
  setprop(&amp;quot;/busyTelescope&amp;quot;, 0);&lt;br /&gt;
We now have the flag, and it is cleared.&lt;br /&gt;
&lt;br /&gt;
We still need to clear it at our required repeat rate. Add to the init routine&lt;br /&gt;
  setlistener(&amp;quot;/busyTelescopy&amp;quot;, func { if (getprop(&amp;quot;/mythical/busyTelescope&amp;quot;)) settimer(busyTelescopeClear, buttonRate, 1); });&lt;br /&gt;
&lt;br /&gt;
and add this function&lt;br /&gt;
  var busyTelescopeClear = func {&lt;br /&gt;
        setprop(&amp;quot;/busyTelescope&amp;quot;, 0);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Now, whenever the button is pressed, the flag gets set. The listener detects this and starts a timer, with delay buttonRate. When the delay elapses, busyTelescopeClear is called, which clears the flag, and the button will repeat.&lt;br /&gt;
&lt;br /&gt;
We now can control the repeat rate of the button.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Making the code safe ==&lt;br /&gt;
To avoid the busy flag possibly getting stuck in the true state, make the mod-up of your joystick call ''mynasfile.buttonCUp()''.&lt;br /&gt;
&lt;br /&gt;
Then add this to the nas file&lt;br /&gt;
  var buttonCUp = func {&lt;br /&gt;
        busyTelescopeClear()&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Other uses  ==&lt;br /&gt;
It is of course possible to use this technique for adding a delay in any nasal code, with appropriate changes.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Changing_repeat_rate_of_joystick_buttons&amp;diff=57635</id>
		<title>Changing repeat rate of joystick buttons</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Changing_repeat_rate_of_joystick_buttons&amp;diff=57635"/>
		<updated>2013-02-03T07:37:07Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
If you are new to writing Nasal functions for joysticks, read [[Using a Nasal file with a joystick]] first.&lt;br /&gt;
&lt;br /&gt;
==  Background ==&lt;br /&gt;
&lt;br /&gt;
Sometimes the repeat rate of joystick buttons is too high. The value changes so fast that you can't set it accurately. You could use&lt;br /&gt;
  &amp;lt;desc&amp;gt;whatever&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;interval-sec&amp;gt;x.xx&amp;lt;/interval-sec&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where x.xx is the time between button action repeats. This has the problem that the delay is implemented at the start of the button press, as well as between repeats. It is also not as versatile as using this method.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Changes (additions) to the Nasal file ==&lt;br /&gt;
&lt;br /&gt;
You must have set up everything according to [[Using a Nasal file with a joystick]].&lt;br /&gt;
&lt;br /&gt;
Assume that the button in question is labelled &amp;quot;C&amp;quot;. The property we want to change with the button is '''/mythical/telescope-colour'''. It has an integer value. Our nas file is called mynasfile.nas. We will use a flag called busyTelescope to control the repeat rate.&lt;br /&gt;
&lt;br /&gt;
Start off by adding the function for the button&lt;br /&gt;
  var adjTelescopeColour = func {&lt;br /&gt;
        if (getprop(&amp;quot;/mythical/busyTelescope&amp;quot;)) return;&lt;br /&gt;
  &lt;br /&gt;
        setprop(&amp;quot;/mythical/busyTelescope&amp;quot;, 1);&lt;br /&gt;
  &lt;br /&gt;
        ... Code to adjust telescope property goes here  ..&lt;br /&gt;
    &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Changing_repeat_rate_of_joystick_buttons&amp;diff=57634</id>
		<title>Changing repeat rate of joystick buttons</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Changing_repeat_rate_of_joystick_buttons&amp;diff=57634"/>
		<updated>2013-02-03T07:19:28Z</updated>

		<summary type="html">&lt;p&gt;Macnab: Created page with &amp;quot;{{WIP}}  If you are new to writing Nasal functions for joysticks, read Using a Nasal file with a joystick first.   Category:Howto Category:Hardware&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
If you are new to writing Nasal functions for joysticks, read [[Using a Nasal file with a joystick]] first.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_Saitek_Pro_Flight_Yoke_Mode_Switch&amp;diff=57632</id>
		<title>Using Saitek Pro Flight Yoke Mode Switch</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_Saitek_Pro_Flight_Yoke_Mode_Switch&amp;diff=57632"/>
		<updated>2013-02-03T07:10:05Z</updated>

		<summary type="html">&lt;p&gt;Macnab: /* Very Important */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Before you start ==&lt;br /&gt;
&lt;br /&gt;
To use the Mode Switch you need to install the Smart Technology software that came on the CD with your yoke. Install it ''after'' installing the drivers.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Running the Profile Editor ==&lt;br /&gt;
If the Profile Editor does not run after installation, you can run it from the Start Menu - Start - All Programs - Smart Technology (folder) - Profile Editor.&lt;br /&gt;
If you have the rudder pedals as well as the yoke you will have to select the yoke in the first dialog box that appears.&lt;br /&gt;
At the top right is ''Product Programming Support''. Click on 'Programming'. Here is the top left corner of the page that appears:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Saitek Yoke - Top Left Blank.jpg | 550px]]&lt;br /&gt;
&lt;br /&gt;
                                                                              &lt;br /&gt;
&lt;br /&gt;
== Creating a blank safety profile ==&lt;br /&gt;
The first thing to do is create a profile that does nothing, i.e. does not interfere in any way with the current working of the yoke. This is your &amp;quot;safety&amp;quot; backup.  Click on (Create) Profile. This generates the file that will be saved and opens the Save as dialog. Give the profile a suitable name (such as Blank) and save it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  What the software does ==&lt;br /&gt;
It simulates keystrokes. You can assign different keystrokes to specific yoke buttons for each mode. Then, when you select a mode and press a button, that/those keystroke(s) are sent to Flightgear. Just as if you had typed them at the keyboard.&lt;br /&gt;
But this does have the limitation of only being able to use commands that exist on keyboard.xml and multikey.xml. And that also means no 'repeatable' actions, such as 'Trim' Elevator'.  So we will not discuss it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Mod-Key style of use ==&lt;br /&gt;
What we are going to do is make the Mode Switch act as if we are pressing the Shift, Ctrl or Alt keys while pressing a yoke button - emulating &amp;lt;mod-shift&amp;gt;, &amp;lt;mod-ctrl&amp;gt; and &amp;lt;mod-alt&amp;gt;. Mode 1 is none of the above pressed. Choose which 2 of the 3 mod conditions you want to use. In this article we will use Shift in Mode 2 and Ctrl in Mode 3. It really doesn't matter unless you already have your yoke programmed with mods.&lt;br /&gt;
To make Mode 2 emulate pressing the Shift key, hold your mouse pointer in the large blank rectangle under Mode 2, and then click on the little arrow that appears.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Saitek Yoke - To make little arrow appear.jpg | 400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                                             &lt;br /&gt;
A popup menu appears. Click on &amp;quot;New Key Presses...&amp;quot;. You now see this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Saitek Yoke - New Key Presses clicked.jpg | 400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                                              &lt;br /&gt;
Ignore where the cursor is (this is just for a name) and click in the bigger rectangle. Then give the Shift key a tap. An icon of the Shift key will appear in the rectangle. Click on the little green tick mark. (If you got it wrong, click on the little red cross and try again.&lt;br /&gt;
You will have this, if you got it right:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Saitek Yoke - Shift key done..jpg | 400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
                                                           &lt;br /&gt;
If it doesn't look like that, click on one of the incorrect key icons. You will be taken back to the point before you clicked the green tick. You can then right-click on any incorrect keys and select Cut. And redo tapping the Shift key if needed.&lt;br /&gt;
&lt;br /&gt;
Now go to the column for Mode 3, and repeat all the ablove actions, except using the Ctrl key, instead of Shift. &lt;br /&gt;
Now you need to create the profile. Click on (Create) Profile. The profile will be created and the Save As dialog will open. Choose a suitable name for the profile and save it.&lt;br /&gt;
You will now need to edit your joysticks's xml file. There is plenty of information on that. You will of course need to program &amp;lt;mod-shift&amp;gt; and &amp;lt;mod-ctrl&amp;gt; sections for the buttons.&lt;br /&gt;
&lt;br /&gt;
== Very Important ==&lt;br /&gt;
* If you assign Shift to Mode 2, and the yoke switch is in Mode 2, then ''everything'' you do will be treated as if the shift key is pressed while you do it. This includes the mouse. To use a modded button, flick the switch to Mode 2 or Mode 3, do what you have to do, and then flick straight back to Mode 1.&lt;br /&gt;
&lt;br /&gt;
* The profile you have defined is not automatically assigned at system boot-up. You have to go to the system area, right-click on the yoke-icon and select your profile. The icon will then have a green box around it to show that it has been assigned a profile.&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;br /&gt;
[[Category:Howto]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick&amp;diff=57631</id>
		<title>Using a Nasal file with a joystick</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick&amp;diff=57631"/>
		<updated>2013-02-03T07:02:36Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
Sometimes the code for a button is quite complicated. Not only does it make your xml file larger and more difficult to go through, but writing the code in a dedicated Nasal file cane be a lot easier. There are things which are just easier that way. You may also have come across an example in the forums which you want to use, and you don't know how to do it.&lt;br /&gt;
&lt;br /&gt;
Whatever your reason for using a Nasal file, this is how to implement it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Getting Started ==&lt;br /&gt;
&lt;br /&gt;
You are going to put your Nasal file in the same folder as your joystick's xml file. You need to choose a suitable name for the file. If your joystick is a KungFu ABC123 you could safely name the file abc123.nas. If, however, you have a Saitek yoke, you don't want to name the file yoke.nas, because in the Saitek folder is a Pro Flight Yoke and a Cessna Yoke, so you want to be more specific. Call the file cessnayoke.nas or proflightyoke.nas'&lt;br /&gt;
&lt;br /&gt;
The name you choose is visible ''everywhere'' in FG, so make sure you choose something unique.&lt;br /&gt;
&lt;br /&gt;
Notice that there are no capital letters.&lt;br /&gt;
&lt;br /&gt;
So open up your favourite text-editor, create a new file, and save it in your joystick's folder with the chosen filename. Don't forget that the extension must be .nas, and make sure your editor doesn't make it .nas.txt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Changes to your joystick's xml file  ==&lt;br /&gt;
&lt;br /&gt;
'''Save a copy of your xml file in a safe place, one that you will remember.'''&lt;br /&gt;
&lt;br /&gt;
For the sake of this exercise we will assume that you have a KungFu ABC123 joystick. So your nasal file is abc123.nas. &lt;br /&gt;
&lt;br /&gt;
Open the xml file.&lt;br /&gt;
&lt;br /&gt;
At the top, just after all the &amp;lt;name&amp;gt; entries, add this:&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
      if (!contains(globals, &amp;quot;abc123&amp;quot;)) {&lt;br /&gt;
        io.load_nasal(getprop(&amp;quot;/sim/fg-root&amp;quot;) ~ &amp;quot;/Input/Joysticks/KungFu/abc123.nas&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
  &lt;br /&gt;
      abc123.initABC123();&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ''if (!contains...'' bit (if not contains) makes sure that the nas file is loaded only once.&lt;br /&gt;
&lt;br /&gt;
The ''abc123.initABC123'' cals an initialise routine in the nas file. We haven't created it yet. Notice the ''abc123''. This tells FG which nas file to use. The ''initABC123'' is which routine in that nas file to call. The ''()'' is because it is a function.&lt;br /&gt;
&lt;br /&gt;
Save your xml file and open the nas file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Adding routines to the nas file  ==&lt;br /&gt;
&lt;br /&gt;
We have just told the xml file to call initABC123, so we better add it to the nas file.&lt;br /&gt;
&lt;br /&gt;
At the top of the file add&lt;br /&gt;
  var initABC123 = func() {&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Every new thing in Nasal starts with '''var'''. That is followed by its name (initABC123). Then we must assign it to something. In this case it is a function, so we write '''= func()'''. If you want to pass a value to the function (we aren't here), you give a name to the value between the brackets, and place the value to pass between the brackets in the xml file. The '''{''' and '''}''' mark the start and end of the function (what it does.) It doesn't currently do anything, so there is nothing between them.&lt;br /&gt;
&lt;br /&gt;
Now we need to make at least one button call a function in the nas file. Let's assume you have a button labelled D on your joystick. So we will have a function called buttonD. If it is the only red button, you could call the function redButton.&lt;br /&gt;
&lt;br /&gt;
So we add&lt;br /&gt;
  var buttonD = func() {&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Once again, it doesn't do anything yet.&lt;br /&gt;
&lt;br /&gt;
Save the nas file and open the xml file. Go to where the D button is handled.&lt;br /&gt;
&lt;br /&gt;
Between the &amp;lt;binding&amp;gt; and &amp;lt;/binding&amp;gt; we add our call to the nas file. We get&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
    &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;abc123.buttonD()&amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, when button D is pressed, it will call the function '''buttonD''' in abc123.nas. You just need to put the correct code in the function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To make your nas file a bit more use-friendly, open it and at right at the top add&lt;br /&gt;
  print(&amp;quot;Loading abc123.nas&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Now, when you run FG, along with all the other info in the &amp;quot;black window&amp;quot; you will see ''Loading abc123.nas'' when the joystick xml file loads. This not only confirms that it has loaded, but if you have a parse error in your nas file it will be reported, and you can fix it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Notes  ==&lt;br /&gt;
&lt;br /&gt;
This article does not supply any coding for actions, it is just to get you started. A sort of template.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When naming Nasal functions, the convention is to use camel coding. That is, the first word in the name starts with a lower-case letter, all subsequent words star with an upper-case letter. The can be no spaces in the name. If you want to separate words use an underscore (_).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So valid names would be startDividingByThree, start_Dividing_By_Three, adjRadioFrequency.&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick&amp;diff=57630</id>
		<title>Using a Nasal file with a joystick</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick&amp;diff=57630"/>
		<updated>2013-02-03T06:22:11Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
&lt;br /&gt;
== Background ==&lt;br /&gt;
&lt;br /&gt;
Sometimes the code for a button is quite complicated. Not only does it make your xml file larger and more difficult to go through, but writing the code in a dedicated Nasal file cane be a lot easier. There are things which are just easier that way. You may also have come across an example in the forums which you want to use, and you don't know how to do it.&lt;br /&gt;
&lt;br /&gt;
Whatever your reason for using a Nasal file, this is how to implement it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Getting Started ==&lt;br /&gt;
&lt;br /&gt;
You are going to put your Nasal file in the same folder as your joystick's xml file. You need to choose a suitable name for the file. If your joystick is a KungFu ABC123 you could safely name the file abc123.nas. If, however, you have a Saitek yoke, you don't want to name the file yoke.nas, because in the Saitek folder is a Pro Flight Yoke and a Cessna Yoke, so you want to be more specific. Call the file cessnayoke.nas or proflightyoke.nas'&lt;br /&gt;
&lt;br /&gt;
The name you choose is visible ''everywhere'' in FG, so make sure you choose something unique.&lt;br /&gt;
&lt;br /&gt;
Notice that there are no capital letters.&lt;br /&gt;
&lt;br /&gt;
So open up your favourite text-editor, create a new file, and save it in your joystick's folder with the chosen filename. Don't forget that the extension must be .nas, and make sure your editor doesn't make it .nas.txt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==  Changes to your joystick's xml file  ==&lt;br /&gt;
&lt;br /&gt;
'''Save a copy of your xml file in a safe place, one that you will remember.'''&lt;br /&gt;
&lt;br /&gt;
For the sake of this exercise we will assume that you have a KungFu ABC123 joystick. So your nasal file is abc123.nas. &lt;br /&gt;
&lt;br /&gt;
Open the xml file.&lt;br /&gt;
&lt;br /&gt;
At the top, just after all the &amp;lt;name&amp;gt; entries, add this:&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
      if (!contains(globals, &amp;quot;abc123&amp;quot;)) {&lt;br /&gt;
        io.load_nasal(getprop(&amp;quot;/sim/fg-root&amp;quot;) ~ &amp;quot;/Input/Joysticks/KungFu/abc123.nas&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
  &lt;br /&gt;
      abc123.initABC123();&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick&amp;diff=57629</id>
		<title>Using a Nasal file with a joystick</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick&amp;diff=57629"/>
		<updated>2013-02-03T05:59:38Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
{{WIP}}&lt;br /&gt;
[[Category:Howto]]&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick&amp;diff=57628</id>
		<title>Using a Nasal file with a joystick</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_a_Nasal_file_with_a_joystick&amp;diff=57628"/>
		<updated>2013-02-03T05:56:30Z</updated>

		<summary type="html">&lt;p&gt;Macnab: Created page with &amp;quot;  {{WIP}}&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
{{WIP}}&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_Saitek_AV8R_second_throttle_as_view_pan_speed_control&amp;diff=57195</id>
		<title>Using Saitek AV8R second throttle as view pan speed control</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_Saitek_AV8R_second_throttle_as_view_pan_speed_control&amp;diff=57195"/>
		<updated>2013-01-16T03:16:44Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
These changes to your aviator.xml file will enable you to use Throttle 2 as a speed control while panning the view. Panning speed can be controlled smoothly from no movement at all to very fast.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Caveats =&lt;br /&gt;
You will lose Throttle 2's other functionality. The most important being Mixture, which means you will have to use the keyboard for this - M for leaner and m for richer. This is not a significant problem as the mixture does not have to be adjusted often.&lt;br /&gt;
&lt;br /&gt;
Also, this wiki assumes that you have not done any modifications to your aviator.xml file. If you have, you will have to work out the changes yourself, or ask on the Support-&amp;gt;Hardware forum.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Usage =&lt;br /&gt;
This is the same as standard - use the hat-switch as is to get the predefined views. Press the modifier (trigger) while using the hat-switch to pan left/right and up/down. The difference is that, while using the trigger/hat-switch, Throttle 2 will control the speed of view-change.&lt;br /&gt;
&lt;br /&gt;
There are two methods you can use:&lt;br /&gt;
&lt;br /&gt;
== Method 1 ==&lt;br /&gt;
Moving the hat-switch left/right (up/down) will pan left/right (up/down) with Throttle 2 controlling the speed of movement - throttle closed is dead-still and throttle fully open is very fast movement. This means that the hat-switch can only be used for left/right and up/down.&lt;br /&gt;
&lt;br /&gt;
== Method 2 ==&lt;br /&gt;
With this method you assign 4 different controls to the 4 directions of the hat-switch. With each one, Throttle 2 in the center means no movement, fully open is fast in one direction and throttle closed means fast in the ''other'' direction.&lt;br /&gt;
&lt;br /&gt;
So you could use hat-switch left for pan left/right and hat-switch up for pan up/down. This leaves hat-switch right and hat-switch down for other functions, such as move eye-position (more on this later.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Changes to aviator.xml =&lt;br /&gt;
You need a text-editor to modify this file:&lt;br /&gt;
    .../FlightGear/data/Input/Saitek/Aviator.xml&lt;br /&gt;
&lt;br /&gt;
Step 1 is to make a copy of this file in a safe place, in case things go wrong.&lt;br /&gt;
&lt;br /&gt;
Step 2 is to open the file, and find this:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
   &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
   &amp;lt;script&amp;gt;&lt;br /&gt;
     if (engine_select_mode == 0) {&lt;br /&gt;
       controls.mixtureAxis();&lt;br /&gt;
     } else {&lt;br /&gt;
       controls.perEngineSelectedAxisHandler(engine_axis_mode)&lt;br /&gt;
           ((engine_select_mode == 1) ? engine[1] : engine[3]);&lt;br /&gt;
     }&lt;br /&gt;
   &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
and change it to this:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now Throttle 2 does nothing. No cutting out the engine because you changed the Mixture while panning around.&lt;br /&gt;
If you really want to keep your Mixture control, then you can change the above to:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
   &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
   &amp;lt;script&amp;gt;&lt;br /&gt;
     if (!modifier) {&lt;br /&gt;
       if (engine_select_mode == 0) {&lt;br /&gt;
         controls.mixtureAxis();&lt;br /&gt;
       } else {&lt;br /&gt;
         controls.perEngineSelectedAxisHandler(engine_axis_mode)&lt;br /&gt;
             ((engine_select_mode == 1) ? engine[1] : engine[3]);&lt;br /&gt;
       }&lt;br /&gt;
     }&lt;br /&gt;
   &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
This will keep the Throttle 2 functionality, but you need to return it to its original position before you release the modifier button.&lt;br /&gt;
&lt;br /&gt;
Next is to look for this:&lt;br /&gt;
 &amp;lt;!-- Axis 5. Hat left/right --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Hat left/right&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;5&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;5&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;5&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;quick view left/right, +mod: horizontal view pan&amp;lt;/desc&amp;gt;&lt;br /&gt;
  .....&lt;br /&gt;
&lt;br /&gt;
Scroll down until you see:&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
     &amp;lt;![CDATA[&lt;br /&gt;
       trace(&amp;quot;Axis 5, Hat: low!&amp;quot;);&lt;br /&gt;
      if (modifier) {&lt;br /&gt;
         view.panViewDir(0.5);&lt;br /&gt;
       } else {&lt;br /&gt;
         quick_view(1);&lt;br /&gt;
       }&lt;br /&gt;
     ]]&amp;gt;&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will need to change this line:&lt;br /&gt;
         view.panViewDir(0.5);&lt;br /&gt;
&lt;br /&gt;
If you are using Method 1, change it to&lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
If you are using Method 2, change it to&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
&lt;br /&gt;
You only need do this step for Method 1. Scroll a bit further down until you see&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
     &amp;lt;![CDATA[&lt;br /&gt;
       trace(&amp;quot;Axis 5, Hat: high!&amp;quot;);&lt;br /&gt;
       if (modifier) {&lt;br /&gt;
         view.panViewDir(-0.5);&lt;br /&gt;
       } else {&lt;br /&gt;
         quick_view(2);&lt;br /&gt;
       }&lt;br /&gt;
     ]]&amp;gt;&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The line to change is &lt;br /&gt;
         view.panViewDir(-0.5);&lt;br /&gt;
Change it to&lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
Having made these changes, you can do the following:&lt;br /&gt;
Method 1: Pressing modifier (trigger) and moving the hat-switch left means you can use Throttle 2 to control the speed of pan to the left. Pressing modifier (trigger) and moving the hat-switch right means you can use Throttle 2 to control the speed of pan to the right. &lt;br /&gt;
Method 2: Pressing modifier (trigger) and moving the hat-switch left means that you can use Throttle 2 to control the speed of pan to left and right, with throttle in the middle doing no movement.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now to make the changes to manage pan up and down (pitch.)&lt;br /&gt;
Scroll down to&lt;br /&gt;
 &amp;lt;!-- Axis 6. Hat up/down --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Hat up/down&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;6&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;6&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;6&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;view reset/quick view front, +mod: vertical view pan&amp;lt;/desc&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Scroll a bit further down. The line to change is&lt;br /&gt;
         view.panViewPitch(0.5);&lt;br /&gt;
&lt;br /&gt;
For Method 1, change it to&lt;br /&gt;
         view.panViewPitch(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
For Method 2, change it to&lt;br /&gt;
         view.panViewPitch(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
&lt;br /&gt;
For Method 1, scroll a bit further down and replace &lt;br /&gt;
         view.panViewPitch(0.5);&lt;br /&gt;
with this&lt;br /&gt;
         view.panViewPitch(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
Now you can do look up/down exactly the same as left/right.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Alternatives =&lt;br /&gt;
You could of course use this exact same method to move your eye-point around, instead of looking around. &lt;br /&gt;
&lt;br /&gt;
If using Method 1, replace&lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
with &lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)) * 10);&lt;br /&gt;
and &lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
with&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;))* -10);&lt;br /&gt;
&lt;br /&gt;
If using Method 2. change&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
to&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 20);&lt;br /&gt;
&lt;br /&gt;
This will move you horizontally.&lt;br /&gt;
To move up and down, replace x-offset with y-offset. To move backwards and forwards, change it to z-offset.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can also use this method for zooming in and out. Unfortunately we need to implement limits for zoom, so the code is more complicated.&lt;br /&gt;
If using Method 1, replace&lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
with &lt;br /&gt;
         &amp;lt;![CDATA[&lt;br /&gt;
           controls.slewProp(&amp;quot;/sim/current-view/field-of-view&amp;quot;, &lt;br /&gt;
              (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)) * -20);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;gt;= 120)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 120);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;lt;= 1)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 1);&lt;br /&gt;
         ]]&amp;gt;&lt;br /&gt;
and &lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
with&lt;br /&gt;
         &amp;lt;![CDATA[&lt;br /&gt;
           controls.slewProp(&amp;quot;/sim/current-view/field-of-view&amp;quot;, &lt;br /&gt;
              -(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)) * -20);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;gt;= 120)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 120);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;lt;= 1)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 1);&lt;br /&gt;
         ]]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If using Method 2. change&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * -2);&lt;br /&gt;
to&lt;br /&gt;
         &amp;lt;![CDATA[&lt;br /&gt;
           controls.slewProp(&amp;quot;/sim/current-view/field-of-view&amp;quot;, &lt;br /&gt;
              getprop(&amp;quot;input/joysticks/j[0]/axis[4]/binding/setting&amp;quot;) * 40);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;gt;= 120)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 120);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;lt;= 1)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 1);&lt;br /&gt;
         ]]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Summing Up =&lt;br /&gt;
It seems a bit daunting, but if you look carefully, the steps are all the same, there are just a few places where the changes need to be made.&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_Saitek_AV8R_second_throttle_as_view_pan_speed_control&amp;diff=57174</id>
		<title>Using Saitek AV8R second throttle as view pan speed control</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_Saitek_AV8R_second_throttle_as_view_pan_speed_control&amp;diff=57174"/>
		<updated>2013-01-14T10:04:24Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
These changes to your aviator.xml file will enable you to use Throttle 2 as a speed control while panning the view. Panning speed can be controlled smoothly from no movement at all to very fast.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Caveats =&lt;br /&gt;
You will lose Throttle 2's other functionality. The most important being Mixture, which means you will have to use the keyboard for this - M for leaner and m for richer. This is not a significant problem as the mixture does not have to be adjusted often.&lt;br /&gt;
&lt;br /&gt;
Also, this wiki assumes that you have not done any modifications to your aviator.xml file. If you have, you will have to work out the changes yourself, or ask on the Support-&amp;gt;Hardware forum.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Usage =&lt;br /&gt;
This is the same as standard - use the hat-switch as is to get the predefined views. Press the modifier (trigger) while using the hat-switch to pan left/right and up/down. The difference is that, while using the trigger/hat-switch, Throttle 2 will control the speed of view-change.&lt;br /&gt;
&lt;br /&gt;
There are two methods you can use:&lt;br /&gt;
&lt;br /&gt;
== Method 1 ==&lt;br /&gt;
Moving the hat-switch left/right (up/down) will pan left/right (up/down) with Throttle 2 controlling the speed of movement - throttle closed is dead-still and throttle fully open is very fast movement. This means that the hat-switch can only be used for left/right and up/down.&lt;br /&gt;
&lt;br /&gt;
== Method 2 ==&lt;br /&gt;
With this method you assign 4 different controls to the 4 directions of the hat-switch. With each one, Throttle 2 in the center means no movement, fully open is fast in one direction and throttle closed means fast in the ''other'' direction.&lt;br /&gt;
&lt;br /&gt;
So you could use hat-switch left for pan left/right and hat-switch up for pan up/down. This leaves hat-switch right and hat-switch down for other functions, such as move eye-position (more on this later.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Changes to aviator.xml =&lt;br /&gt;
You need a text-editor to modify this file:&lt;br /&gt;
    .../FlightGear/data/Input/Saitek/Aviator.xml&lt;br /&gt;
&lt;br /&gt;
Step 1 is to make a copy of this file in a safe place, in case things go wrong.&lt;br /&gt;
&lt;br /&gt;
Step 2 is to open the file, and find this:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
   &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
   &amp;lt;script&amp;gt;&lt;br /&gt;
     if (engine_select_mode == 0) {&lt;br /&gt;
       controls.mixtureAxis();&lt;br /&gt;
     } else {&lt;br /&gt;
       controls.perEngineSelectedAxisHandler(engine_axis_mode)&lt;br /&gt;
           ((engine_select_mode == 1) ? engine[1] : engine[3]);&lt;br /&gt;
     }&lt;br /&gt;
   &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
and change it to this:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now Throttle 2 does nothing. No cutting out the engine because you changed the Mixture while panning around.&lt;br /&gt;
If you really want to keep your Mixture control, then you can change the above to:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
   &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
   &amp;lt;script&amp;gt;&lt;br /&gt;
     if (!modifier) {&lt;br /&gt;
       if (engine_select_mode == 0) {&lt;br /&gt;
         controls.mixtureAxis();&lt;br /&gt;
       } else {&lt;br /&gt;
         controls.perEngineSelectedAxisHandler(engine_axis_mode)&lt;br /&gt;
             ((engine_select_mode == 1) ? engine[1] : engine[3]);&lt;br /&gt;
       }&lt;br /&gt;
     }&lt;br /&gt;
   &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
This will keep the Throttle 2 functionality, but you need to return it to its original position before you release the modifier button.&lt;br /&gt;
&lt;br /&gt;
Next is to look for this:&lt;br /&gt;
 &amp;lt;!-- Axis 5. Hat left/right --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Hat left/right&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;5&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;5&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;5&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;quick view left/right, +mod: horizontal view pan&amp;lt;/desc&amp;gt;&lt;br /&gt;
  .....&lt;br /&gt;
&lt;br /&gt;
Scroll down until you see:&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
     &amp;lt;![CDATA[&lt;br /&gt;
       trace(&amp;quot;Axis 5, Hat: low!&amp;quot;);&lt;br /&gt;
      if (modifier) {&lt;br /&gt;
         view.panViewDir(0.5);&lt;br /&gt;
       } else {&lt;br /&gt;
         quick_view(1);&lt;br /&gt;
       }&lt;br /&gt;
     ]]&amp;gt;&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will need to change this line:&lt;br /&gt;
         view.panViewDir(0.5);&lt;br /&gt;
&lt;br /&gt;
If you are using Method 1, change it to&lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
If you are using Method 2, change it to&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
&lt;br /&gt;
You only need do this step for Method 1. Scroll a bit further down until you see&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
     &amp;lt;![CDATA[&lt;br /&gt;
       trace(&amp;quot;Axis 5, Hat: high!&amp;quot;);&lt;br /&gt;
       if (modifier) {&lt;br /&gt;
         view.panViewDir(-0.5);&lt;br /&gt;
       } else {&lt;br /&gt;
         quick_view(2);&lt;br /&gt;
       }&lt;br /&gt;
     ]]&amp;gt;&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The line to change is &lt;br /&gt;
         view.panViewDir(-0.5);&lt;br /&gt;
Change it to&lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
Having made these changes, you can do the following:&lt;br /&gt;
Method 1: Pressing modifier (trigger) and moving the hat-switch left means you can use Throttle 2 to control the speed of pan to the left. Pressing modifier (trigger) and moving the hat-switch right means you can use Throttle 2 to control the speed of pan to the right. &lt;br /&gt;
Method 2: Pressing modifier (trigger) and moving the hat-switch left means that you can use Throttle 2 to control the speed of pan to left and right, with throttle in the middle doing no movement.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now to make the changes to manage pan up and down (pitch.)&lt;br /&gt;
Scroll down to&lt;br /&gt;
 &amp;lt;!-- Axis 6. Hat up/down --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Hat up/down&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;6&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;6&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;6&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;view reset/quick view front, +mod: vertical view pan&amp;lt;/desc&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Scroll a bit further down. The line to change is&lt;br /&gt;
         view.panViewPitch(0.5);&lt;br /&gt;
&lt;br /&gt;
For Method 1, change it to&lt;br /&gt;
         view.panViewPitch(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
For Method 2, change it to&lt;br /&gt;
         view.panViewPitch(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
&lt;br /&gt;
For Method 1, scroll a bit further down and replace &lt;br /&gt;
         view.panViewPitch(0.5);&lt;br /&gt;
with this&lt;br /&gt;
         view.panViewPitch(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
Now you can do look up/down exactly the same as left/right.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Alternatives =&lt;br /&gt;
You could of course use this exact same method to move your eye-point around, instead of looking around. &lt;br /&gt;
&lt;br /&gt;
If using Method 1, replace&lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
with &lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)) * 10);&lt;br /&gt;
and &lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
with&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;))* 10);&lt;br /&gt;
&lt;br /&gt;
If using Method 2. change&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
to&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 20);&lt;br /&gt;
&lt;br /&gt;
This will move you horizontally.&lt;br /&gt;
To move up and down, replace x-offset with y-offset. To move backwards and forwards, change it to z-offset.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can also use this method for zooming in and out. Unfortunately we need to implement limits for zoom, so the code is more complicated.&lt;br /&gt;
If using Method 1, replace&lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
with &lt;br /&gt;
         &amp;lt;![CDATA[&lt;br /&gt;
           controls.slewProp(&amp;quot;/sim/current-view/field-of-view&amp;quot;, &lt;br /&gt;
              (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)) * -20);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;gt;= 120)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 120);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;lt;= 1)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 1);&lt;br /&gt;
         ]]&amp;gt;&lt;br /&gt;
and &lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
with&lt;br /&gt;
         &amp;lt;![CDATA[&lt;br /&gt;
           controls.slewProp(&amp;quot;/sim/current-view/field-of-view&amp;quot;, &lt;br /&gt;
              -(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)) * -20);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;gt;= 120)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 120);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;lt;= 1)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 1);&lt;br /&gt;
         ]]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If using Method 2. change&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * -2);&lt;br /&gt;
to&lt;br /&gt;
         &amp;lt;![CDATA[&lt;br /&gt;
           controls.slewProp(&amp;quot;/sim/current-view/field-of-view&amp;quot;, &lt;br /&gt;
              getprop(&amp;quot;input/joysticks/j[0]/axis[4]/binding/setting&amp;quot;) * 40);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;gt;= 120)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 120);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;lt;= 1)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 1);&lt;br /&gt;
         ]]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Summing Up =&lt;br /&gt;
It seems a bit daunting, but if you look carefully, the steps are all the same, there are just a few places where the changes need to be made.&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_Saitek_AV8R_second_throttle_as_view_pan_speed_control&amp;diff=57173</id>
		<title>Using Saitek AV8R second throttle as view pan speed control</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_Saitek_AV8R_second_throttle_as_view_pan_speed_control&amp;diff=57173"/>
		<updated>2013-01-14T06:23:45Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Purpose =&lt;br /&gt;
These changes to your aviator.xml file will enable you to use Throttle 2 as a speed control while panning the view. Panning speed can be controlled smoothly from no movement at all to very fast.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Caveats =&lt;br /&gt;
You will lose Throttle 2's other functionality. The most important being Mixture, which means you will have to use the keyboard for this - M for leaner and m for richer. This is not a significant problem as the mixture does not have to be adjusted often.&lt;br /&gt;
&lt;br /&gt;
Also, this wiki assumes that you have not done any modifications to your aviator.xml file. If you have, you will have to work out the changes yourself, or ask on the Support-&amp;gt;Hardware forum.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Usage =&lt;br /&gt;
This is the same as standard - use the hat-switch as is to get the predefined views. Press the modifier (trigger) while using the hat-switch to pan left/right and up/down. The difference is that, while using the trigger/hat-switch, Throttle 2 will control the speed of view-change.&lt;br /&gt;
&lt;br /&gt;
There are two methods you can use:&lt;br /&gt;
&lt;br /&gt;
== Method 1 ==&lt;br /&gt;
Moving the hat-switch left/right (up/down) will pan left/right (up/down) with Throttle 2 controlling the speed of movement - throttle closed is dead-still and throttle fully open is very fast movement. This means that the hat-switch can only be used for left/right and up/down.&lt;br /&gt;
&lt;br /&gt;
== Method 2 ==&lt;br /&gt;
With this method you assign 4 different controls to the 4 directions of the hat-switch. With each one, Throttle 2 in the center means no movement, fully open is fast in one direction and throttle closed means fast in the ''other'' direction.&lt;br /&gt;
&lt;br /&gt;
So you could use hat-switch left for pan left/right and hat-switch up for pan up/down. This leaves hat-switch right and hat-switch down for other functions, such as move eye-position (more on this later.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Changes to aviator.xml =&lt;br /&gt;
You need a text-editor to modify this file:&lt;br /&gt;
    .../FlightGear/data/Input/Saitek/Aviator.xml&lt;br /&gt;
&lt;br /&gt;
Step 1 is to make a copy of this file in a safe place, in case things go wrong.&lt;br /&gt;
&lt;br /&gt;
Step 2 is to open the file, and find this:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
   &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
   &amp;lt;script&amp;gt;&lt;br /&gt;
     if (engine_select_mode == 0) {&lt;br /&gt;
       controls.mixtureAxis();&lt;br /&gt;
     } else {&lt;br /&gt;
       controls.perEngineSelectedAxisHandler(engine_axis_mode)&lt;br /&gt;
           ((engine_select_mode == 1) ? engine[1] : engine[3]);&lt;br /&gt;
     }&lt;br /&gt;
   &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
and change it to this:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now Throttle 2 does nothing. No cutting out the engine because you changed the Mixture while panning around.&lt;br /&gt;
If you really want to keep your Mixture control, then you can change the above to:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
   &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
   &amp;lt;script&amp;gt;&lt;br /&gt;
     if (!modifier) {&lt;br /&gt;
       if (engine_select_mode == 0) {&lt;br /&gt;
         controls.mixtureAxis();&lt;br /&gt;
       } else {&lt;br /&gt;
         controls.perEngineSelectedAxisHandler(engine_axis_mode)&lt;br /&gt;
             ((engine_select_mode == 1) ? engine[1] : engine[3]);&lt;br /&gt;
       }&lt;br /&gt;
     }&lt;br /&gt;
   &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
This will keep the Throttle 2 functionality, but you need to return it to its original position before you release the modifier button.&lt;br /&gt;
&lt;br /&gt;
Next is to look for this:&lt;br /&gt;
 &amp;lt;!-- Axis 5. Hat left/right --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Hat left/right&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;5&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;5&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;5&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;quick view left/right, +mod: horizontal view pan&amp;lt;/desc&amp;gt;&lt;br /&gt;
  .....&lt;br /&gt;
&lt;br /&gt;
Scroll down until you see:&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
     &amp;lt;![CDATA[&lt;br /&gt;
       trace(&amp;quot;Axis 5, Hat: low!&amp;quot;);&lt;br /&gt;
      if (modifier) {&lt;br /&gt;
         view.panViewDir(0.5);&lt;br /&gt;
       } else {&lt;br /&gt;
         quick_view(1);&lt;br /&gt;
       }&lt;br /&gt;
     ]]&amp;gt;&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will need to change this line:&lt;br /&gt;
         view.panViewDir(0.5);&lt;br /&gt;
&lt;br /&gt;
If you are using Method 1, change it to&lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
If you are using Method 2, change it to&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
&lt;br /&gt;
You only need do this step for Method 1. Scroll a bit further down until you see&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
     &amp;lt;![CDATA[&lt;br /&gt;
       trace(&amp;quot;Axis 5, Hat: high!&amp;quot;);&lt;br /&gt;
       if (modifier) {&lt;br /&gt;
         view.panViewDir(-0.5);&lt;br /&gt;
       } else {&lt;br /&gt;
         quick_view(2);&lt;br /&gt;
       }&lt;br /&gt;
     ]]&amp;gt;&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The line to change is &lt;br /&gt;
         view.panViewDir(-0.5);&lt;br /&gt;
Change it to&lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
Having made these changes, you can do the following:&lt;br /&gt;
Method 1: Pressing modifier (trigger) and moving the hat-switch left means you can use Throttle 2 to control the speed of pan to the left. Pressing modifier (trigger) and moving the hat-switch right means you can use Throttle 2 to control the speed of pan to the right. &lt;br /&gt;
Method 2: Pressing modifier (trigger) and moving the hat-switch left means that you can use Throttle 2 to control the speed of pan to left and right, with throttle in the middle doing no movement.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now to make the changes to manage pan up and down (pitch.)&lt;br /&gt;
Scroll down to&lt;br /&gt;
 &amp;lt;!-- Axis 6. Hat up/down --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Hat up/down&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;6&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;6&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;6&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;view reset/quick view front, +mod: vertical view pan&amp;lt;/desc&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Scroll a bit further down. The line to change is&lt;br /&gt;
         view.panViewPitch(0.5);&lt;br /&gt;
&lt;br /&gt;
For Method 1, change it to&lt;br /&gt;
         view.panViewPitch(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
For Method 2, change it to&lt;br /&gt;
         view.panViewPitch(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
&lt;br /&gt;
For Method 1, scroll a bit further down and replace &lt;br /&gt;
         view.panViewPitch(0.5);&lt;br /&gt;
with this&lt;br /&gt;
         view.panViewPitch(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
Now you can do look up/down exactly the same as left/right.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Alternatives =&lt;br /&gt;
You could of course use this exact same method to move your eye-point around, instead of looking around. &lt;br /&gt;
&lt;br /&gt;
If using Method 1, replace&lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
with &lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)) * 10);&lt;br /&gt;
and &lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
with&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;))* 10);&lt;br /&gt;
&lt;br /&gt;
If using Method 2. change&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
to&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 20);&lt;br /&gt;
&lt;br /&gt;
This will move you horizontally.&lt;br /&gt;
To move up and down, replace x-offset with y-offset. To move backwards and forwards, change it to z-offset.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can also use this method for zooming in and out. Unfortunately we need to implement limits for zoom, so the code is more complicated.&lt;br /&gt;
If using Method 1, replace&lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
with &lt;br /&gt;
         &amp;lt;![CDATA[&lt;br /&gt;
           controls.slewProp(&amp;quot;/sim/current-view/field-of-view&amp;quot;, &lt;br /&gt;
              (1 - getprop(&amp;quot;input/joysticks/js[2]/axis[2]/binding/setting&amp;quot;)) * -20);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;gt;= 120)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 120);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;lt;= 1)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 1);&lt;br /&gt;
         ]]&amp;gt;&lt;br /&gt;
and &lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
with&lt;br /&gt;
         &amp;lt;![CDATA[&lt;br /&gt;
           controls.slewProp(&amp;quot;/sim/current-view/field-of-view&amp;quot;, &lt;br /&gt;
              -(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)) * -20);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;gt;= 120)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 120);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;lt;= 1)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 1);&lt;br /&gt;
         ]]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If using Method 2. change&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * -2);&lt;br /&gt;
to&lt;br /&gt;
         &amp;lt;![CDATA[&lt;br /&gt;
           controls.slewProp(&amp;quot;/sim/current-view/field-of-view&amp;quot;, &lt;br /&gt;
              getprop(&amp;quot;input/joysticks/js02]/axis[4]/binding/setting&amp;quot;) * 40);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;gt;= 120)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 120);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;lt;= 1)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 1);&lt;br /&gt;
         ]]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Summing Up =&lt;br /&gt;
It seems a bit daunting, but if you look carefully, the steps are all the same, there are just a few places where the changes need to be made.&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_Saitek_AV8R_second_throttle_as_view_pan_speed_control&amp;diff=57172</id>
		<title>Using Saitek AV8R second throttle as view pan speed control</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_Saitek_AV8R_second_throttle_as_view_pan_speed_control&amp;diff=57172"/>
		<updated>2013-01-14T06:21:51Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
Don't use any of this code until the Work in Progress banner has been removed.&lt;br /&gt;
&lt;br /&gt;
= Purpose =&lt;br /&gt;
These changes to your aviator.xml file will enable you to use Throttle 2 as a speed control while panning the view. Panning speed can be controlled smoothly from no movement at all to very fast.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Caveats =&lt;br /&gt;
You will lose Throttle 2's other functionality. The most important being Mixture, which means you will have to use the keyboard for this - M for leaner and m for richer. This is not a significant problem as the mixture does not have to be adjusted often.&lt;br /&gt;
&lt;br /&gt;
Also, this wiki assumes that you have not done any modifications to your aviator.xml file. If you have, you will have to work out the changes yourself, or ask on the Support-&amp;gt;Hardware forum.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Usage =&lt;br /&gt;
This is the same as standard - use the hat-switch as is to get the predefined views. Press the modifier (trigger) while using the hat-switch to pan left/right and up/down. The difference is that, while using the trigger/hat-switch, Throttle 2 will control the speed of view-change.&lt;br /&gt;
&lt;br /&gt;
There are two methods you can use:&lt;br /&gt;
&lt;br /&gt;
== Method 1 ==&lt;br /&gt;
Moving the hat-switch left/right (up/down) will pan left/right (up/down) with Throttle 2 controlling the speed of movement - throttle closed is dead-still and throttle fully open is very fast movement. This means that the hat-switch can only be used for left/right and up/down.&lt;br /&gt;
&lt;br /&gt;
== Method 2 ==&lt;br /&gt;
With this method you assign 4 different controls to the 4 directions of the hat-switch. With each one, Throttle 2 in the center means no movement, fully open is fast in one direction and throttle closed means fast in the ''other'' direction.&lt;br /&gt;
&lt;br /&gt;
So you could use hat-switch left for pan left/right and hat-switch up for pan up/down. This leaves hat-switch right and hat-switch down for other functions, such as move eye-position (more on this later.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Changes to aviator.xml =&lt;br /&gt;
You need a text-editor to modify this file:&lt;br /&gt;
    .../FlightGear/data/Input/Saitek/Aviator.xml&lt;br /&gt;
&lt;br /&gt;
Step 1 is to make a copy of this file in a safe place, in case things go wrong.&lt;br /&gt;
&lt;br /&gt;
Step 2 is to open the file, and find this:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
   &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
   &amp;lt;script&amp;gt;&lt;br /&gt;
     if (engine_select_mode == 0) {&lt;br /&gt;
       controls.mixtureAxis();&lt;br /&gt;
     } else {&lt;br /&gt;
       controls.perEngineSelectedAxisHandler(engine_axis_mode)&lt;br /&gt;
           ((engine_select_mode == 1) ? engine[1] : engine[3]);&lt;br /&gt;
     }&lt;br /&gt;
   &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
and change it to this:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now Throttle 2 does nothing. No cutting out the engine because you changed the Mixture while panning around.&lt;br /&gt;
If you really want to keep your Mixture control, then you can change the above to:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
   &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
   &amp;lt;script&amp;gt;&lt;br /&gt;
     if (!modifier) {&lt;br /&gt;
       if (engine_select_mode == 0) {&lt;br /&gt;
         controls.mixtureAxis();&lt;br /&gt;
       } else {&lt;br /&gt;
         controls.perEngineSelectedAxisHandler(engine_axis_mode)&lt;br /&gt;
             ((engine_select_mode == 1) ? engine[1] : engine[3]);&lt;br /&gt;
       }&lt;br /&gt;
     }&lt;br /&gt;
   &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
This will keep the Throttle 2 functionality, but you need to return it to its original position before you release the modifier button.&lt;br /&gt;
&lt;br /&gt;
Next is to look for this:&lt;br /&gt;
 &amp;lt;!-- Axis 5. Hat left/right --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Hat left/right&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;5&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;5&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;5&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;quick view left/right, +mod: horizontal view pan&amp;lt;/desc&amp;gt;&lt;br /&gt;
  .....&lt;br /&gt;
&lt;br /&gt;
Scroll down until you see:&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
     &amp;lt;![CDATA[&lt;br /&gt;
       trace(&amp;quot;Axis 5, Hat: low!&amp;quot;);&lt;br /&gt;
      if (modifier) {&lt;br /&gt;
         view.panViewDir(0.5);&lt;br /&gt;
       } else {&lt;br /&gt;
         quick_view(1);&lt;br /&gt;
       }&lt;br /&gt;
     ]]&amp;gt;&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will need to change this line:&lt;br /&gt;
         view.panViewDir(0.5);&lt;br /&gt;
&lt;br /&gt;
If you are using Method 1, change it to&lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
If you are using Method 2, change it to&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
&lt;br /&gt;
You only need do this step for Method 1. Scroll a bit further down until you see&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
     &amp;lt;![CDATA[&lt;br /&gt;
       trace(&amp;quot;Axis 5, Hat: high!&amp;quot;);&lt;br /&gt;
       if (modifier) {&lt;br /&gt;
         view.panViewDir(-0.5);&lt;br /&gt;
       } else {&lt;br /&gt;
         quick_view(2);&lt;br /&gt;
       }&lt;br /&gt;
     ]]&amp;gt;&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The line to change is &lt;br /&gt;
         view.panViewDir(-0.5);&lt;br /&gt;
Change it to&lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
Having made these changes, you can do the following:&lt;br /&gt;
Method 1: Pressing modifier (trigger) and moving the hat-switch left means you can use Throttle 2 to control the speed of pan to the left. Pressing modifier (trigger) and moving the hat-switch right means you can use Throttle 2 to control the speed of pan to the right. &lt;br /&gt;
Method 2: Pressing modifier (trigger) and moving the hat-switch left means that you can use Throttle 2 to control the speed of pan to left and right, with throttle in the middle doing no movement.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now to make the changes to manage pan up and down (pitch.)&lt;br /&gt;
Scroll down to&lt;br /&gt;
 &amp;lt;!-- Axis 6. Hat up/down --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Hat up/down&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;6&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;6&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;6&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;view reset/quick view front, +mod: vertical view pan&amp;lt;/desc&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Scroll a bit further down. The line to change is&lt;br /&gt;
         view.panViewPitch(0.5);&lt;br /&gt;
&lt;br /&gt;
For Method 1, change it to&lt;br /&gt;
         view.panViewPitch(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
For Method 2, change it to&lt;br /&gt;
         view.panViewPitch(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
&lt;br /&gt;
For Method 1, scroll a bit further down and replace &lt;br /&gt;
         view.panViewPitch(0.5);&lt;br /&gt;
with this&lt;br /&gt;
         view.panViewPitch(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
Now you can do look up/down exactly the same as left/right.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Alternatives =&lt;br /&gt;
You could of course use this exact same method to move your eye-point around, instead of looking around. &lt;br /&gt;
&lt;br /&gt;
If using Method 1, replace&lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
with &lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)) * 10);&lt;br /&gt;
and &lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
with&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;))* 10);&lt;br /&gt;
&lt;br /&gt;
If using Method 2. change&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
to&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 20);&lt;br /&gt;
&lt;br /&gt;
This will move you horizontally.&lt;br /&gt;
To move up and down, replace x-offset with y-offset. To move backwards and forwards, change it to z-offset.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can also use this method for zooming in and out. Unfortunately we need to implement limits for zoom, so the code is more complicated.&lt;br /&gt;
If using Method 1, replace&lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
with &lt;br /&gt;
         &amp;lt;![CDATA[&lt;br /&gt;
           controls.slewProp(&amp;quot;/sim/current-view/field-of-view&amp;quot;, &lt;br /&gt;
              (1 - getprop(&amp;quot;input/joysticks/js[2]/axis[2]/binding/setting&amp;quot;)) * -20);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;gt;= 120)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 120);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;lt;= 1)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 1);&lt;br /&gt;
         ]]&amp;gt;&lt;br /&gt;
and &lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
with&lt;br /&gt;
         &amp;lt;![CDATA[&lt;br /&gt;
           controls.slewProp(&amp;quot;/sim/current-view/field-of-view&amp;quot;, &lt;br /&gt;
              -(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)) * -20);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;gt;= 120)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 120);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;lt;= 1)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 1);&lt;br /&gt;
         ]]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If using Method 2. change&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * -2);&lt;br /&gt;
to&lt;br /&gt;
         &amp;lt;![CDATA[&lt;br /&gt;
           controls.slewProp(&amp;quot;/sim/current-view/field-of-view&amp;quot;, &lt;br /&gt;
              getprop(&amp;quot;input/joysticks/js02]/axis[4]/binding/setting&amp;quot;) * 40);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;gt;= 120)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 120);&lt;br /&gt;
           if (getprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;) &amp;lt;= 1)&lt;br /&gt;
             setprop(&amp;quot;/sim/current-view/field-of-view&amp;quot;, 1);&lt;br /&gt;
         ]]&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Summing Up =&lt;br /&gt;
It seems a bit daunting, but if you look carefully, the steps are all the same, there are just a few places where the changes need to be made.&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_Saitek_AV8R_second_throttle_as_view_pan_speed_control&amp;diff=57171</id>
		<title>Using Saitek AV8R second throttle as view pan speed control</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_Saitek_AV8R_second_throttle_as_view_pan_speed_control&amp;diff=57171"/>
		<updated>2013-01-14T05:57:21Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
Don't use any of this code until the Work in Progress banner has been removed.&lt;br /&gt;
&lt;br /&gt;
= Purpose =&lt;br /&gt;
These changes to your aviator.xml file will enable you to use Throttle 2 as a speed control while panning the view. Panning speed can be controlled smoothly from no movement at all to very fast.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Caveats =&lt;br /&gt;
You will lose Throttle 2's other functionality. The most important being Mixture, which means you will have to use the keyboard for this - M for leaner and m for richer. This is not a significant problem as the mixture does not have to be adjusted often.&lt;br /&gt;
&lt;br /&gt;
Also, this wiki assumes that you have not done any modifications to your aviator.xml file. If you have, you will have to work out the changes yourself, or ask on the Support-&amp;gt;Hardware forum.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Usage =&lt;br /&gt;
This is the same as standard - use the hat-switch as is to get the predefined views. Press the modifier (trigger) while using the hat-switch to pan left/right and up/down. The difference is that, while using the trigger/hat-switch, Throttle 2 will control the speed of view-change.&lt;br /&gt;
&lt;br /&gt;
There are two methods you can use:&lt;br /&gt;
&lt;br /&gt;
== Method 1 ==&lt;br /&gt;
Moving the hat-switch left/right (up/down) will pan left/right (up/down) with Throttle 2 controlling the speed of movement - throttle closed is dead-still and throttle fully open is very fast movement. This means that the hat-switch can only be used for left/right and up/down.&lt;br /&gt;
&lt;br /&gt;
== Method 2 ==&lt;br /&gt;
With this method you assign 4 different controls to the 4 directions of the hat-switch. With each one, Throttle 2 in the center means no movement, fully open is fast in one direction and throttle closed means fast in the ''other'' direction.&lt;br /&gt;
&lt;br /&gt;
So you could use hat-switch left for pan left/right and hat-switch up for pan up/down. This leaves hat-switch right and hat-switch down for other functions, such as move eye-position (more on this later.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Changes to aviator.xml =&lt;br /&gt;
You need a text-editor to modify this file:&lt;br /&gt;
    .../FlightGear/data/Input/Saitek/Aviator.xml&lt;br /&gt;
&lt;br /&gt;
Step 1 is to make a copy of this file in a safe place, in case things go wrong.&lt;br /&gt;
&lt;br /&gt;
Step 2 is to open the file, and find this:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
   &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
   &amp;lt;script&amp;gt;&lt;br /&gt;
     if (engine_select_mode == 0) {&lt;br /&gt;
       controls.mixtureAxis();&lt;br /&gt;
     } else {&lt;br /&gt;
       controls.perEngineSelectedAxisHandler(engine_axis_mode)&lt;br /&gt;
           ((engine_select_mode == 1) ? engine[1] : engine[3]);&lt;br /&gt;
     }&lt;br /&gt;
   &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
and change it to this:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now Throttle 2 does nothing. No cutting out the engine because you changed the Mixture while panning around.&lt;br /&gt;
If you really want to keep your Mixture control, then you can change the above to:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
   &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
   &amp;lt;script&amp;gt;&lt;br /&gt;
     if (!modifier) {&lt;br /&gt;
       if (engine_select_mode == 0) {&lt;br /&gt;
         controls.mixtureAxis();&lt;br /&gt;
       } else {&lt;br /&gt;
         controls.perEngineSelectedAxisHandler(engine_axis_mode)&lt;br /&gt;
             ((engine_select_mode == 1) ? engine[1] : engine[3]);&lt;br /&gt;
       }&lt;br /&gt;
     }&lt;br /&gt;
   &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
This will keep the Throttle 2 functionality, but you need to return it to its original position before you release the modifier button.&lt;br /&gt;
&lt;br /&gt;
Next is to look for this:&lt;br /&gt;
 &amp;lt;!-- Axis 5. Hat left/right --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Hat left/right&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;5&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;5&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;5&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;quick view left/right, +mod: horizontal view pan&amp;lt;/desc&amp;gt;&lt;br /&gt;
  .....&lt;br /&gt;
&lt;br /&gt;
Scroll down until you see:&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
     &amp;lt;![CDATA[&lt;br /&gt;
       trace(&amp;quot;Axis 5, Hat: low!&amp;quot;);&lt;br /&gt;
      if (modifier) {&lt;br /&gt;
         view.panViewDir(0.5);&lt;br /&gt;
       } else {&lt;br /&gt;
         quick_view(1);&lt;br /&gt;
       }&lt;br /&gt;
     ]]&amp;gt;&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will need to change this line:&lt;br /&gt;
         view.panViewDir(0.5);&lt;br /&gt;
&lt;br /&gt;
If you are using Method 1, change it to&lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
If you are using Method 2, change it to&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
&lt;br /&gt;
You only need do this step for Method 1. Scroll a bit further down until you see&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
     &amp;lt;![CDATA[&lt;br /&gt;
       trace(&amp;quot;Axis 5, Hat: high!&amp;quot;);&lt;br /&gt;
       if (modifier) {&lt;br /&gt;
         view.panViewDir(-0.5);&lt;br /&gt;
       } else {&lt;br /&gt;
         quick_view(2);&lt;br /&gt;
       }&lt;br /&gt;
     ]]&amp;gt;&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The line to change is &lt;br /&gt;
         view.panViewDir(-0.5);&lt;br /&gt;
Change it to&lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
Having made these changes, you can do the following:&lt;br /&gt;
Method 1: Pressing modifier (trigger) and moving the hat-switch left means you can use Throttle 2 to control the speed of pan to the left. Pressing modifier (trigger) and moving the hat-switch right means you can use Throttle 2 to control the speed of pan to the right. &lt;br /&gt;
Method 2: Pressing modifier (trigger) and moving the hat-switch left means that you can use Throttle 2 to control the speed of pan to left and right, with throttle in the middle doing no movement.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now to make the changes to manage pan up and down (pitch.)&lt;br /&gt;
Scroll down to&lt;br /&gt;
 &amp;lt;!-- Axis 6. Hat up/down --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Hat up/down&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;6&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;6&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;6&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;view reset/quick view front, +mod: vertical view pan&amp;lt;/desc&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Scroll a bit further down. The line to change is&lt;br /&gt;
         view.panViewPitch(0.5);&lt;br /&gt;
&lt;br /&gt;
For Method 1, change it to&lt;br /&gt;
         view.panViewPitch(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
For Method 2, change it to&lt;br /&gt;
         view.panViewPitch(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
&lt;br /&gt;
For Method 1, scroll a bit further down and replace &lt;br /&gt;
         view.panViewPitch(0.5);&lt;br /&gt;
with this&lt;br /&gt;
         view.panViewPitch(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
Now you can do look up/down exactly the same as left/right.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Alternatives =&lt;br /&gt;
You could of course use this exact same method to move your eye-point around, instead of looking around. &lt;br /&gt;
&lt;br /&gt;
If using Method 1, replace&lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
with &lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)) * 10);&lt;br /&gt;
and &lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
with&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;))* 10);&lt;br /&gt;
&lt;br /&gt;
If using Method 2. change&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
to&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 20);&lt;br /&gt;
&lt;br /&gt;
This will move you horizontally.&lt;br /&gt;
To move up and down, replace x-offset with y-offset. To move backwards and forwards, change it to z-offset.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can also use this method for zooming in and out.&lt;br /&gt;
If using Method 1, replace&lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
with &lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/field-of-view&amp;quot;, &lt;br /&gt;
            (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)) * -20);&lt;br /&gt;
and &lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
with&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/field-of-view&amp;quot;, &lt;br /&gt;
            (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)) * 20);&lt;br /&gt;
&lt;br /&gt;
If using Method 2. change&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * -2);&lt;br /&gt;
to&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/field-of-view&amp;quot;, &lt;br /&gt;
            getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 20);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Summing Up =&lt;br /&gt;
It seems a bit daunting, but if you look carefully, the steps are all the same, there are just a few places where the changes need to be made.&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_Saitek_AV8R_second_throttle_as_view_pan_speed_control&amp;diff=57170</id>
		<title>Using Saitek AV8R second throttle as view pan speed control</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_Saitek_AV8R_second_throttle_as_view_pan_speed_control&amp;diff=57170"/>
		<updated>2013-01-14T05:37:50Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
Don't use any of this code until the Work in Progress banner has been removed.&lt;br /&gt;
&lt;br /&gt;
= Purpose =&lt;br /&gt;
These changes to your aviator.xml file will enable you to use Throttle 2 as a speed control while panning the view. Panning speed can be controlled smoothly from no movement at all to very fast.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Caveats =&lt;br /&gt;
You will lose Throttle 2's other functionality. The most important being Mixture, which means you will have to use the keyboard for this - M for leaner and m for richer. This is not a significant problem as the mixture does not have to be adjusted often.&lt;br /&gt;
&lt;br /&gt;
Also, this wiki assumes that you have not done any modifications to your aviator.xml file. If you have, you will have to work out the changes yourself, or ask on the Support-&amp;gt;Hardware forum.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Usage =&lt;br /&gt;
This is the same as standard - use the hat-switch as is to get the predefined views. Press the modifier (trigger) while using the hat-switch to pan left/right and up/down. The difference is that, while using the trigger/hat-switch, Throttle 2 will control the speed of view-change.&lt;br /&gt;
&lt;br /&gt;
There are two methods you can use:&lt;br /&gt;
&lt;br /&gt;
== Method 1 ==&lt;br /&gt;
Moving the hat-switch left/right (up/down) will pan left/right (up/down) with Throttle 2 controlling the speed of movement - throttle closed is dead-still and throttle fully open is very fast movement. This means that the hat-switch can only be used for left/right and up/down.&lt;br /&gt;
&lt;br /&gt;
== Method 2 ==&lt;br /&gt;
With this method you assign 4 different controls to the 4 directions of the hat-switch. With each one, Throttle 2 in the center means no movement, fully open is fast in one direction and throttle closed means fast in the ''other'' direction.&lt;br /&gt;
&lt;br /&gt;
So you could use hat-switch left for pan left/right and hat-switch up for pan up/down. This leaves hat-switch right and hat-switch down for other functions, such as move eye-position (more on this later.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Changes to aviator.xml =&lt;br /&gt;
You need a text-editor to modify this file:&lt;br /&gt;
    .../FlightGear/data/Input/Saitek/Aviator.xml&lt;br /&gt;
&lt;br /&gt;
Step 1 is to make a copy of this file in a safe place, in case things go wrong.&lt;br /&gt;
&lt;br /&gt;
Step 2 is to open the file, and find this:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
   &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
   &amp;lt;script&amp;gt;&lt;br /&gt;
     if (engine_select_mode == 0) {&lt;br /&gt;
       controls.mixtureAxis();&lt;br /&gt;
     } else {&lt;br /&gt;
       controls.perEngineSelectedAxisHandler(engine_axis_mode)&lt;br /&gt;
           ((engine_select_mode == 1) ? engine[1] : engine[3]);&lt;br /&gt;
     }&lt;br /&gt;
   &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
and change it to this:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now Throttle 2 does nothing. No cutting out the engine because you changed the Mixture while panning around.&lt;br /&gt;
If you really want to keep your Mixture control, then you can change the above to:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
   &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
   &amp;lt;script&amp;gt;&lt;br /&gt;
     if (!modifier) {&lt;br /&gt;
       if (engine_select_mode == 0) {&lt;br /&gt;
         controls.mixtureAxis();&lt;br /&gt;
       } else {&lt;br /&gt;
         controls.perEngineSelectedAxisHandler(engine_axis_mode)&lt;br /&gt;
             ((engine_select_mode == 1) ? engine[1] : engine[3]);&lt;br /&gt;
       }&lt;br /&gt;
     }&lt;br /&gt;
   &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
This will keep the Throttle 2 functionality, but you need to return it to its original position before you release the modifier button.&lt;br /&gt;
&lt;br /&gt;
Next is to look for this:&lt;br /&gt;
 &amp;lt;!-- Axis 5. Hat left/right --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Hat left/right&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;5&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;5&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;5&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;quick view left/right, +mod: horizontal view pan&amp;lt;/desc&amp;gt;&lt;br /&gt;
  .....&lt;br /&gt;
&lt;br /&gt;
Scroll down until you see:&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
     &amp;lt;![CDATA[&lt;br /&gt;
       trace(&amp;quot;Axis 5, Hat: low!&amp;quot;);&lt;br /&gt;
      if (modifier) {&lt;br /&gt;
         view.panViewDir(0.5);&lt;br /&gt;
       } else {&lt;br /&gt;
         quick_view(1);&lt;br /&gt;
       }&lt;br /&gt;
     ]]&amp;gt;&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will need to change this line:&lt;br /&gt;
         view.panViewDir(0.5);&lt;br /&gt;
&lt;br /&gt;
If you are using Method 1, change it to&lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
If you are using Method 2, change it to&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
&lt;br /&gt;
You only need do this step for Method 1. Scroll a bit further down until you see&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
     &amp;lt;![CDATA[&lt;br /&gt;
       trace(&amp;quot;Axis 5, Hat: high!&amp;quot;);&lt;br /&gt;
       if (modifier) {&lt;br /&gt;
         view.panViewDir(-0.5);&lt;br /&gt;
       } else {&lt;br /&gt;
         quick_view(2);&lt;br /&gt;
       }&lt;br /&gt;
     ]]&amp;gt;&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The line to change is &lt;br /&gt;
         view.panViewDir(-0.5);&lt;br /&gt;
Change it to&lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
Having made these changes, you can do the following:&lt;br /&gt;
Method 1: Pressing modifier (trigger) and moving the hat-switch left means you can use Throttle 2 to control the speed of pan to the left. Pressing modifier (trigger) and moving the hat-switch right means you can use Throttle 2 to control the speed of pan to the right. &lt;br /&gt;
Method 2: Pressing modifier (trigger) and moving the hat-switch left means that you can use Throttle 2 to control the speed of pan to left and right, with throttle in the middle doing no movement.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now to make the changes to manage pan up and down (pitch.)&lt;br /&gt;
Scroll down to&lt;br /&gt;
 &amp;lt;!-- Axis 6. Hat up/down --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Hat up/down&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;6&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;6&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;6&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;view reset/quick view front, +mod: vertical view pan&amp;lt;/desc&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Scroll a bit further down. The line to change is&lt;br /&gt;
         view.panViewPitch(0.5);&lt;br /&gt;
&lt;br /&gt;
For Method 1, change it to&lt;br /&gt;
         view.panViewPitch(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
For Method 2, change it to&lt;br /&gt;
         view.panViewPitch(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
&lt;br /&gt;
For Method 1, scroll a bit further down and replace &lt;br /&gt;
         view.panViewPitch(0.5);&lt;br /&gt;
with this&lt;br /&gt;
         view.panViewPitch(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
Now you can do look up/down exactly the same as left/right.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Alternatives =&lt;br /&gt;
You could of course use this exact same method to move your eye-point around, instead of looking around. &lt;br /&gt;
&lt;br /&gt;
If using Method 1, replace&lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
with &lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)) * 10);&lt;br /&gt;
and &lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
with&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, (1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;))* 10);&lt;br /&gt;
&lt;br /&gt;
If using Method 2. change&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
to&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 20);&lt;br /&gt;
&lt;br /&gt;
This will move you horizontally.&lt;br /&gt;
To move up and down, replace x-offset with y-offset. To move backwards and forwards, change it to z-offset.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can also use this method for zooming in and out.&lt;br /&gt;
If using Method 1, replace&lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
with &lt;br /&gt;
         view.increase(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
and &lt;br /&gt;
         vie.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
with&lt;br /&gt;
         view.increase(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
If using Method 2. change&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * -2);&lt;br /&gt;
to&lt;br /&gt;
         view.increase(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * -2);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Summing Up =&lt;br /&gt;
It seems a bit daunting, but if you look carefully, the steps are all the same, there are just a few places where the changes need to be made.&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Using_Saitek_AV8R_second_throttle_as_view_pan_speed_control&amp;diff=57168</id>
		<title>Using Saitek AV8R second throttle as view pan speed control</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Using_Saitek_AV8R_second_throttle_as_view_pan_speed_control&amp;diff=57168"/>
		<updated>2013-01-14T05:23:51Z</updated>

		<summary type="html">&lt;p&gt;Macnab: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP}}&lt;br /&gt;
Don't use any of this code until the Work in Progress banner has been removed.&lt;br /&gt;
&lt;br /&gt;
= Purpose =&lt;br /&gt;
These changes to your aviator.xml file will enable you to use Throttle 2 as a speed control while panning the view. Panning speed can be controlled smoothly from no movement at all to very fast.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Caveats =&lt;br /&gt;
You will lose Throttle 2's other functionality. The most important being Mixture, which means you will have to use the keyboard for this - M for leaner and m for richer. This is not a significant problem as the mixture does not have to be adjusted often.&lt;br /&gt;
&lt;br /&gt;
Also, this wiki assumes that you have not done any modifications to your aviator.xml file. If you have, you will have to work out the changes yourself, or ask on the Support-&amp;gt;Hardware forum.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Usage =&lt;br /&gt;
This is the same as standard - use the hat-switch as is to get the predefined views. Press the modifier (trigger) while using the hat-switch to pan left/right and up/down. The difference is that, while using the trigger/hat-switch, Throttle 2 will control the speed of view-change.&lt;br /&gt;
&lt;br /&gt;
There are two methods you can use:&lt;br /&gt;
&lt;br /&gt;
== Method 1 ==&lt;br /&gt;
Moving the hat-switch left/right (up/down) will pan left/right (up/down) with Throttle 2 controlling the speed of movement - throttle closed is dead-still and throttle fully open is very fast movement. This means that the hat-switch can only be used for left/right and up/down.&lt;br /&gt;
&lt;br /&gt;
== Method 2 ==&lt;br /&gt;
With this method you assign 4 different controls to the 4 directions of the hat-switch. With each one, Throttle 2 in the center means no movement, fully open is fast in one direction and throttle closed means fast in the ''other'' direction.&lt;br /&gt;
&lt;br /&gt;
So you could use hat-switch left for pan left/right and hat-switch up for pan up/down. This leaves hat-switch right and hat-switch down for other functions, such as move eye-position (more on this later.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Changes to aviator.xml =&lt;br /&gt;
You need a text-editor to modify this file:&lt;br /&gt;
    .../FlightGear/data/Input/Saitek/Aviator.xml&lt;br /&gt;
&lt;br /&gt;
Step 1 is to make a copy of this file in a safe place, in case things go wrong.&lt;br /&gt;
&lt;br /&gt;
Step 2 is to open the file, and find this:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
   &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
   &amp;lt;script&amp;gt;&lt;br /&gt;
     if (engine_select_mode == 0) {&lt;br /&gt;
       controls.mixtureAxis();&lt;br /&gt;
     } else {&lt;br /&gt;
       controls.perEngineSelectedAxisHandler(engine_axis_mode)&lt;br /&gt;
           ((engine_select_mode == 1) ? engine[1] : engine[3]);&lt;br /&gt;
     }&lt;br /&gt;
   &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
and change it to this:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now Throttle 2 does nothing. No cutting out the engine because you changed the Mixture while panning around.&lt;br /&gt;
If you really want to keep your Mixture control, then you can change the above to:&lt;br /&gt;
 &amp;lt;!-- Analog axis 4. Throttle 2 --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Right throttle&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;4&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;4&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;4&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;TM0: mixture, TM1: throttle/propeller 2, TM2: throttle/propeller 4&amp;lt;/desc&amp;gt;&lt;br /&gt;
  &amp;lt;binding&amp;gt;&lt;br /&gt;
   &amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
   &amp;lt;script&amp;gt;&lt;br /&gt;
     if (!modifier) {&lt;br /&gt;
       if (engine_select_mode == 0) {&lt;br /&gt;
         controls.mixtureAxis();&lt;br /&gt;
       } else {&lt;br /&gt;
         controls.perEngineSelectedAxisHandler(engine_axis_mode)&lt;br /&gt;
             ((engine_select_mode == 1) ? engine[1] : engine[3]);&lt;br /&gt;
       }&lt;br /&gt;
     }&lt;br /&gt;
   &amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;/binding&amp;gt;&lt;br /&gt;
 &amp;lt;/axis&amp;gt;&lt;br /&gt;
This will keep the Throttle 2 functionality, but you need to return it to its original position before you release the modifier button.&lt;br /&gt;
&lt;br /&gt;
Next is to look for this:&lt;br /&gt;
 &amp;lt;!-- Axis 5. Hat left/right --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Hat left/right&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;5&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;5&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;5&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;quick view left/right, +mod: horizontal view pan&amp;lt;/desc&amp;gt;&lt;br /&gt;
  .....&lt;br /&gt;
&lt;br /&gt;
Scroll down until you see:&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
     &amp;lt;![CDATA[&lt;br /&gt;
       trace(&amp;quot;Axis 5, Hat: low!&amp;quot;);&lt;br /&gt;
      if (modifier) {&lt;br /&gt;
         view.panViewDir(0.5);&lt;br /&gt;
       } else {&lt;br /&gt;
         quick_view(1);&lt;br /&gt;
       }&lt;br /&gt;
     ]]&amp;gt;&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You will need to change this line:&lt;br /&gt;
         view.panViewDir(0.5);&lt;br /&gt;
&lt;br /&gt;
If you are using Method 1, change it to&lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
If you are using Method 2, change it to&lt;br /&gt;
         view.panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
&lt;br /&gt;
You only need do this step for Method 1. Scroll a bit further down until you see&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
     &amp;lt;![CDATA[&lt;br /&gt;
       trace(&amp;quot;Axis 5, Hat: high!&amp;quot;);&lt;br /&gt;
       if (modifier) {&lt;br /&gt;
         view.panViewDir(-0.5);&lt;br /&gt;
       } else {&lt;br /&gt;
         quick_view(2);&lt;br /&gt;
       }&lt;br /&gt;
     ]]&amp;gt;&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The line to change is &lt;br /&gt;
         view.panViewDir(-0.5);&lt;br /&gt;
Change it to&lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
Having made these changes, you can do the following:&lt;br /&gt;
Method 1: Pressing modifier (trigger) and moving the hat-switch left means you can use Throttle 2 to control the speed of pan to the left. Pressing modifier (trigger) and moving the hat-switch right means you can use Throttle 2 to control the speed of pan to the right. &lt;br /&gt;
Method 2: Pressing modifier (trigger) and moving the hat-switch left means that you can use Throttle 2 to control the speed of pan to left and right, with throttle in the middle doing no movement.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now to make the changes to manage pan up and down (pitch.)&lt;br /&gt;
Scroll down to&lt;br /&gt;
 &amp;lt;!-- Axis 6. Hat up/down --&amp;gt;&lt;br /&gt;
 &amp;lt;axis&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Hat up/down&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;number&amp;gt;&lt;br /&gt;
   &amp;lt;unix&amp;gt;6&amp;lt;/unix&amp;gt;&lt;br /&gt;
   &amp;lt;mac&amp;gt;6&amp;lt;/mac&amp;gt;&lt;br /&gt;
   &amp;lt;windows&amp;gt;6&amp;lt;/windows&amp;gt;&lt;br /&gt;
  &amp;lt;/number&amp;gt;&lt;br /&gt;
  &amp;lt;desc&amp;gt;view reset/quick view front, +mod: vertical view pan&amp;lt;/desc&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Scroll a bit further down. The line to change is&lt;br /&gt;
         view.panViewPitch(0.5);&lt;br /&gt;
&lt;br /&gt;
For Method 1, change it to&lt;br /&gt;
         view.panViewPitch(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
For Method 2, change it to&lt;br /&gt;
         view.panViewPitch(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * 2);&lt;br /&gt;
&lt;br /&gt;
For Method 1, scroll a bit further down and replace &lt;br /&gt;
         view.panViewPitch(0.5);&lt;br /&gt;
with this&lt;br /&gt;
         view.panViewPitch(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
Now you can do look up/down exactly the same as left/right.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Alternatives =&lt;br /&gt;
You could of course use this exact same method to move your eye-point around, instead of looking around. &lt;br /&gt;
&lt;br /&gt;
If using Method 1, replace&lt;br /&gt;
         view.panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
with &lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, 1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
and &lt;br /&gt;
         view.panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
with&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, -(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
&lt;br /&gt;
If using Method 2. change&lt;br /&gt;
         panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * -2);&lt;br /&gt;
to&lt;br /&gt;
         controls.slewProp(&amp;quot;/sim/current-view/x-offset-m&amp;quot;, getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * -2);&lt;br /&gt;
&lt;br /&gt;
This will move you horizontally.&lt;br /&gt;
To move up and down, replace x-offset with y-offset. To move backwards and forwards, change it to z-offset.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can also use this method for zooming in and out.&lt;br /&gt;
If using Method 1, replace&lt;br /&gt;
         panViewDir(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
with &lt;br /&gt;
         view.increase(-(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;)));&lt;br /&gt;
and &lt;br /&gt;
         panViewDir(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
with&lt;br /&gt;
         view.increase(1 - getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
If using Method 2. change&lt;br /&gt;
         panViewDir(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * -2);&lt;br /&gt;
to&lt;br /&gt;
         view.increase(getprop(&amp;quot;input/joysticks/js[0]/axis[4]/binding/setting&amp;quot;) * -2);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Summing Up =&lt;br /&gt;
It seems a bit daunting, but if you look carefully, the steps are all the same, there are just a few places where the changes need to be made.&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Hardware]]&lt;/div&gt;</summary>
		<author><name>Macnab</name></author>
	</entry>
</feed>