2015年12月4日 星期五

QTest::toString(const T&), class template, explicit template specialization

若有定義好==運算子,QCOMPARE巨集可比較自定義類別。

舉例來說:
class Employee {
public:
  Employee() { id_ = count_++; }
  unsigned id() const { return id_; }
private:
  static unsigned count_;
  unsigned id_;
}

unsigned Employee::count_ = 0;

定義==運算子
bool operator ==(const Employee& lhs, const Employee& rhs)
{
  return lhs.id() == rhs.id();
}


於Test Case
Employee employee1;
Employee employee2;
QCOMPARE(empolyee1, employee2);


如此,執行Unit Test會跑出Compare values are not the same。但不會像比較double等內定型別一樣,列出ActualExpected


若要希望QCOMPARE自定類別也可列出ActualExpected,需explicit template specialization QTest::toString(const T&):

namespace QTest {
template <>
char* toString(const Employee& employee)
{
  QByteArray ba = "Employee, id = ";
  ba += QByteArray::number(employee.id());
  return qstrdup(ba.data());
}
}

如此,會跑出
Actual   (employee1): Employee, id = 0
Expected (employee2): Employee, id = 1



假使希望對class template做相同的事:

template <unsigned _rowCount>
class Vector {
public:
  double& operator ()(unsigned row) { return data_[row-1]; }
  double operator ()(unsigned row) const {return data_[row-1]; }
private:
  double data_[_rowCount];
}

==運算子:
template <unsigned _rowCount>
bool operator ==(const Vector<_rowcount>& lhs, const Vector<_rowcount>& rhs>
{
  for (unsigned row = 1; row <= _rowCount; ++row) {
    if (lhs(row) != rhs(row)) return false;
  }
  return true;
}

class template之toString之寫法較特殊:
namespace QTest {
template <typename T, unsigned _rowCount>
char* toString(const Vector<_rowcount>& v)
{
  QByteArray ba = "Vector(";
  for (unsigned row = 1; row <= _rowCount; ++row) {
    ba += QByteArray::number(v(row));
    ba += (row != _rowCount) ? ", " : ")";
  }
}
}
儘管T未使用,仍不可只寫<>,否則無法正確explicit template specialization toString(const T&)ActualExpected也不會正確顯示。

先前EmployeetoString也可改寫為<typename T>,脫褲子放屁就是了。


於Test Case
Vector<3> vector1;
vector1(1) = vector1(2) = vector1(3) = 1;
Vector<3> vector2;
vector2(1) = vector2(2) = vector2(3) = 2;
QCOMPARE(vector1, vector2);


如此,會跑出
Actual   (vector1): Vector(1, 1, 1)
Expected (vector2): Vector(2, 2, 2)

2015年9月27日 星期日

更新Xcode 7.0後 Qt 5.5.0程式無法編譯

作業系統: OSX 10.10.5
Qt版本: 5.5.0
Qt Creator版本: 3.3.2


更新Xcode 7.0後,編譯出現下列錯誤:

:-1: warning: no such sysroot directory: '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk'

結果是MacOSX10.10.sdk已消失,變成MacOSX10.11.sdk


有兩種解決方法:

1.
在.pro檔加上 QMAKE_MAC_SDK = macosx10.11

2.
在/usr/local/Cellar/qt5/5.5.0/mkspecs/qdevice.pri 加上
!host_build:QMAKE_MAC_SDK = macosx10.11


參考:
stackoverflow


2015年5月1日 星期五

Qt實作emit數字signal之PushButton

之前寫的某個程式,有個0~200的slider。
因為需要經常性將slider值設回100,加了一個text為100的push button,於click後作動。

原本在MainWindow寫好接收push button clicked signal的slot,於其中呼叫slider的setValue(int)設值。

後來越看越覺得這樣多一層函式很醜,因為setValue(int)本來就是slot。
為何不直接繼承出一種有clicked(int) signal的push button?

實作如下:

class MyPushButton : public QPushButton{
  Q_OBJECT
public:
  explicit MyPushButton(QWidget* parent = 0);

signals:
  void clicked(int value);
  void clicked(double value);

protected:
  void mouseReleaseEvent(QMouseEvent* e);

};

繼承QPushButton,增加clicked(int)clicked(double)兩個signals,並override mouseReleaseEvent以於正確時機emit。


NumberButton::NumberButton(QWidget* parent)
  : QPushButton(parent)

{ }

建構式,不搞怪乖乖把parent傳到QPushButton建構式

void MyPushbutton::mouseReleaseEvent(QMouseEvent* e)
{
  if(e->button() == Qt::LeftButton && hitButton(e->pos())){
    emit clicked(text().toInt());
    emit clicked(text().toDouble());
  }

  QPushButton::mouseReleaseEvent(e);

}

放開的button為滑鼠左鍵(表示先前一定有按下),且游標仍在Button內,則發出signal。
最後將QMouseEvent傳回QPushButton::mouseReleaseEvent,做正常處理。


2015年4月25日 星期六

#ifdef、#elif、defined

 最近因為想把用Open GL的程式放到OS X跑,把Preprocessor #include的部分改為

#ifdef _WIN32
...
#elif __APPLE__
#include
...
#endif

後來感覺#elif部分怪怪,查了一下,發現#ifdef其實是#if defined的方便寫法,而原本的#elif部分並不是檢查有無define,而是做條件判斷。

隨便寫個C++程式測試:

...
#ifdef NOT_DEFINED
...
#elif ALSO_NOT_DEFINED
  std::cout << "print for test" << std::endl;
...

可編譯,不輸出


...
#define DEFINED

...
#elif DEFINE
  std::cout << "print for test" << std::endl;
...

無法編譯,"error: expected value in expression"


...
#define DEFINED_AS_ZERO 0

...
#elif DEFINED_AS_ZERO
  std::cout << "print for test" << std::endl;
...

可編譯,不輸出


...
#define DEFINED_AS_ONE 1

...
#elif DEFINED_AS_ONE
  std::cout << "print for test" << std::endl;
...

可編譯,有輸出


改用#elif defined,皆可編譯,除ALSO_NOT_DEFINED外皆有輸出


白目想說cout __APPLE__看看,輸出1,無怪乎原本用#elif也能順利include。但#elif define(__APPLE__)感覺較良好,還是改吧。

2015年4月19日 星期日

於MBPR安裝Qwt

安裝

1. 自SourgeForge下載qwt-6.1.2.tar.bz2

brew有Qwt, 但測試安裝好像是綁Qt4

2. tar jxvf qwt-6.1.2.tar.bz2解壓縮檔案

3. (於qwt資料夾)qmake

4. make

5. make install

在Window裝差不多, 就抓的壓縮檔不同和用的compiler, compile指令不同

使用

1. 在要用Qwt的專案.pro檔加上

include (/usr/local/qwt-6.1.2/features/qwt.prf)

程式到這邊qmake, 編譯都沒問題, 但執行時會出現

dyld: dyld: Library not loaded: qwt.framework/Versions/6/qwt
Reference from: (你的檔案路徑)
Reason: image not found
程式未預期終止。

google到解決方法

2. 點Qt Creator左邊"專案", "建置並執行"分頁上方Clang 64bit下建置右邊的"執行", 進"執行設定", 在下面"Run Environment", 點"詳情", 點"新增", 加入變數"DYLD_FRAMEWORK_PATH", 值"/usr/local/qwt-6.1.2/lib"

值和解決方法不同的原因是我qwt lib沒裝在/usr/local/lib, 看大陸人部落格才想起來

3. 執行ok, 收工

這只是透過Qt Creator執行ok就是了, 之後大概要用前面解決方法 b

2015年4月17日 星期五

於MBPR安裝Qt5與Qt Creator - 使用Homebrew

主要參考此網頁, 安裝成功之作業系統為OS X 10.10.3

1. 安裝Homebrew

  • 開啟terminal (以Spotlight搜尋terminal.app)
  • 官網之script(ruby -e "...)貼至terminal執行
  • 按指示完成安裝, 會順便灌好xcode, xcode command line tools, git ...

2. (於terminal) brew update

取得最新版的Homebrew, 我不確定剛下載好是不是需要update.., 但就update吧

3. brew install qt5

經過漫長的下載, 編譯後將Qt安裝在/usr/local/opt/qt5

4. brew linkapps

通過此步驟才能在應用程式找到Assistant, Designer, Linguist.. 雖然說有了Creator我從沒開過Assistant, Designer, 但Spotlight不知為何連不到Designer, Assistant, 還是link一下好

以下說明Creator安裝方法

5. brew install caskroom/cask/qt-creator

正常好像會先brew install caskroom/cask/brew-cask把cask裝好, 但上述步驟應可直接裝好cask, 再裝Qt Creator

再來要於Qt Creator設定使用的Qt版本(qmake位置)及編譯器

6. 開啟Qt Creator(用Spotlight), 選螢幕上方的"工具"-"外部"-"Configure", 開啟喜好設定視窗

7. 點左邊的"建置並執行", 點上方"Qt Versions"分頁, 點右方"新增"

準備連結qmake

8. 從上面的combo box(下拉式表單)選Macintosh HD

qmake在/usr/local/opt/qt5/bin , 但因usr是隱藏資料夾, 無法點選

9. 按鍵盤之 "Command" + "Shift" + "."

跑出usr等一堆隱藏資料夾

10. 打開/usr/local/opt/qt5/bin/qmake

有了qmake產生makefile檔, 再來就是設定使用的Compiler

11. 點上方"Kits"分頁, 點右方"新增", 下方"Compiler"combo box選"Clang (x86 64bit in /usr/bin)", "Qt版本"選"Qt 5.4.1 (5.4.1)"

至此大功告成, 趕快新增Qt Widgets Application測試. 體驗在Windows和Linux垂涎已久的Macintosh Style


可能有時候還是想在terminal執行qmake, 以下說明PATH變數設定方法

1. vim ~/.bash-profile

不會用vim就用別的文字編輯器吧

2. 加上 export PATH="/usr/local/bin:$PATH" , 儲存檔案

3. 重新開啟terminal, echo $PATH確定有/usr/local/opt/qt5/bin

現在已可在terminal run qmake, 可qmake --version看qt版本

2015年4月15日 星期三

以GTAV操作手法於FlightGear飛Cessna 172P - XBOX360搖桿XML檔設定

GTAV PS4控制器按鍵對應

  • 左操作桿-左右: 副翼(Aileron),操作桿向右,飛機右滾轉
  • 左操作桿-上下: 升降舵(Elevator),操作桿向下、升降舵向下
  • L1: 方向舵(Rudder)左擺
  • R2: 方向舵右擺
  • L2: 熄火/減速
  • R2: 發動/加速
  • 右操作桿-左右: heading(or yaw) 視向(view direction),操作桿向右→往右看
  • 右操作桿-上下: pitch 視向,操作桿向下→往下看
  • 左操作桿-按下: 收/放 起落架
  • 右操作桿-按下: 按下-視向轉正後方;放開-視向轉回正前方
  • 觸控版: 改變視角
  • OPTIONS按鈕: 暫停

FlightGear控制器操作設定方法

FlightGear內的搖桿設定GUI功能有限,為達目標需編輯xml檔。

指定連結到特定xml檔

首先,編輯/FlightGear/data/joysticks.xml如下(參考網頁)
<PropertyList>
  <js n="0" include="Input/Joysticks/custom.xml"/>
</PropertyList>
如此,可強制第一支控制器js n="0"(基本上也只會插一個)以/FlightGear/data/Input/Joysticks/custom.xml對應操作按鍵。

編輯joystick xml檔

基本編輯方法建議參考此教學與/data/Docs/readme Command章節。以下僅就如何於各軸(axis)、按鈕(button)實現GTAV操作對應進行說明。

左操作桿-左右

<axis n="0">
  <binding>
property-scale command將property aileron之value設為axis值
    <command type="string">property-scale</command>
    <property type="string">/controls/flight/aileron</property>
  </binding>
</axis>

左操作桿-上下

<axis n="1">
  <binding>
    <command type="string">property-scale</command>
    <property type="string">/controls/flight/elevator</property>
因左操作桿向下為正,而elevator向上為正,故設factor為-1以反轉
    <factor type="double">-1</factor>
  </binding>
</axis>

L1-R1

XBOX 360搖桿之L1-R1不是類比,不能直接對應成L1-R1按多少→Rudder擺多少。
因此,設定成按下R1→Rudder持續向右擺,放開→回歸原點;按下L1→Rudder持續向左擺,方開→回歸原點。
L1
<button n="4">
  <binding>
property-interpolate command以設定之rate變動property rudder至value
    <command type="string">property-interpolate</command>
    <property type="string">/controls/flight/rudder</property>
Rudder左擺極值為-1
    <value type="double">-1</value>
設定rate,即每秒變動量
    <rate type="double">0.5</rate>
  </binding>
mod-up表放開按鈕
  <mod-up>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
放開L1 Rudder回中心,而中心值為0
      <value type="double">0</value>
      <rate type="double">0.5</rate>
    </binding>
  </mod-up>
</button>
R1
<button n="5">
  <binding>
    <command type="string">property-interpolate</command>
    <property type="string">/controls/flight/rudder</property>
Rudder右擺極值為1
    <value type="double">1</value>
    <rate type="double">0.5</rate>
  </binding>
  <mod-up>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">0</value>
      <rate type="double">0.5</rate>
    </binding>
  </mod-up>
</button>

L2-R2

這個最複雜,因為R2同時要包含油門控制+引擎發動,L2要同時包含煞車+引擎熄火,使用nasal script處理
<axis n="2">
  <binding>
    <command type="string">nasal</command>
    <script type="string">
於script中取得axis值
      var axisValue = cmdarg().getNode("setting").getValue(); 

若引擎未啟動、且R2按到接近底(至底axis值為-1),將starter switch設為1,啟動引擎
      if(getprop("/engines/engine/running") != 1
    and -0.9 > axisValue){
  setprop("/controls/switches/starter", 1);

若magnetos未設為3,設為3
  if(getprop("/controls/engines/engine/magnetos") != 3){ <!-- magnetos setting -->
    setprop("/controls/engines/engine/magnetos", 3);
  }
      }
若引擎已啟動,將starter switch設回0
      else{
 setprop("/controls/switches/starter", 0); 
      }

      <!-- axisValue 0~-1, R2, throttle -->
若axis值小於0,即按R2(0~-1),設定油門(0~1)為axis反轉值
      if(0 >= axisValue){
  setprop("/controls/engines/engine/throttle", -axisValue);
      } 

      <!-- axisValue 0~1, L2, brake -->
若axis值大於0,即按L2(0~1),設定左右煞車(0~1)為axis值
      if(axisValue >= 0){ # L2 is positive (0 ~ 1)
 setprop("/controls/gear/brake-left", axisValue);
 setprop("/controls/gear/brake-right", axisValue);
      } 

若axis值大於0.8,即L2按接近底,將magnetos設為0,引擎熄火
      if(axisValue > 0.8 and getprop("/controls/engines/engine/magnetos") != 0){
 setprop("/controls/engines/engine/magnetos", 0)
      }
    </script>
  </binding>
</axis>

右操作桿-左右

<axis n="4">
axis值約小於-0.9,即右操作桿左擺至接近極限時為low。
  <low> <!-- left --> <!-- axis value < -0.9 -->
動作需重複,即右操作桿左擺時持續減小pitch數值
    <repeatable type="string">true</repeatable>
    <binding>
property-adjust command用以將property數值加上step值
      <command type="string">property-adjust</command>
      <property type="string">/sim/current-view/goal-heading-offset-deg</property>
      <step type="double">-1</step>
    </binding>
  </low>
axis值約大於0.9,即右操作桿右擺至接近極限時為high。
  <high> <!-- right --> <!-- axis value > 0.9 -->
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">property-adjust</command>
      <property type="string">/sim/current-view/goal-heading-offset-deg</property>
      <step type="double">1</step>
    </binding>
  </high>
</axis>

右操作桿-上下

<axis n="3">
axis上擺至接近極限為low
  <low>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">property-adjust</command>
      <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
      <step type="double">-1</step>
    </binding>
  </low>
axis上擺至接近極限為high
  <high>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">property-adjust</command>
      <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
      <step type="double">1</step>
    </binding>
  </high>
</axis>

左操作桿-按下

Cessna 172起落架不能收,跳過

右操作桿-按下

按下看正後方,放開跳回正前方。
<button n="9">
設heading為180度 (正後方)
  <binding>
    <command type="string">property-assign</command>
    <property type="string">/sim/current-view/goal-heading-offset-deg</property>
    <value type="double">180</value>
  </binding>
設pitch為0度
  <binding>
    <command type="string">property-assign</command>
    <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
    <value type="double">0</value>
  </binding>
放開
    <mod-up>
設heading為0度 (正前方)
      <binding>
 <command type="string">property-assign</command>
 <property type="string">/sim/current-view/goal-heading-offset-deg</property>
 <value type="double">0</value>
      </binding>
設pitch為0度
      <binding>
 <command type="string">property-assign</command>
 <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
 <value type="double">0</value>
      </binding>
    </mod-up>
</button>

觸控板

用BACK按鈕代替,利用property-cycle command使property於設定之value循環
<button n="6">
  <binding>
    <command type="string">property-cycle</command>
    <property type="string">/sim/current-view/view-number</property>
cockpit view
    <value>0</value>
model view
    <value>7</value>
chase without yaw view
    <value>5</value>
  </binding>
</button>

OPTIONS按鈕

用START按扭代替,直接pause command就好,easy。
<button n="7"> # START button
  <desc type="string">pause</desc>
  <repeatable type="string">false</repeatable>
  <binding>
    <command type="string">pause</command>
  </binding>
</button>

dead-band

前面說明省略dead-band部分。FlightGear之dead-band 結果以下程式碼說明 (可看joystick文件?)
README.Joystick.html,User Guid to FGInput - Joystick And Keyboard Binding For FlightGear
實際dead-band效果如下函式 (1 >= input >= -1, 1 > deadBand > 0 )

double doDeadBand(double input, double deadBand)
{
  if(input >= deadBand){
    return (input - deadBand) / (1 - deadBand);
  }

  if(input > -deadBand){
    return 0.0;
  }

  return -(abs(input) - deadBand) / (1 - deadBand);
}

完整檔案

<?xml version="1.0"?>

<!-- 
  add 

  <PropertyList>
    <js n="0" include="Input/Joysticks/GTA V like joystick setting for XBOX 360 Controller.xml"/>
  </PropertyList> 

  in FlightGear/data/joysticks.xml

  put this file in FlightGear/data/Input/Joysticks
-->

<PropertyList>
  <name type="string">GTA V like joystick setting for XBOX 360 Controller</name>

  <axis n="0">
    <name type="string">left stick left-right (right positive)</name>
    <desc type="string">adjust aileron</desc>
    <dead-band type="double">0.2</dead-band> <!-- dead-band tag must precede binding tag -->
    <!-- if (input < abs(dead-band)) output = 0 -->
    <!-- if (input > dead-band) output = (output - dead-band) / (1 - dead-band) -->
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/aileron</property>
    </binding>
  </axis>

  <axis n="1">
    <name type="string">left stick up-down (down positive)</name>
    <desc type="string">adjust elevator</desc> 
    <dead-band type="double">0.2</dead-band>
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/elevator</property>
      <factor type="double">-1</factor> <!-- down positive, thus inverse -->
    </binding>
  </axis>

  <axis n="2">
    <name type="string">R2-L2 (L2 positive)</name>
    <desc type="string">start stop engine, adjust throttle, brake</desc>
    <dead-band type="double">0.1</dead-band>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        var axisValue = cmdarg().getNode("setting").getValue(); 
        <!-- the value of /input/joysticks/js/axis[2]/binding/setting -->

        <!-- engine start stop control -->
        if(getprop("/engines/engine/running") != 1 <!-- engine not running -->
             and -0.9 > axisValue){ <!-- R2 pushed near end -->
           setprop("/controls/switches/starter", 1);

           if(getprop("/controls/engines/engine/magnetos") != 3){ <!-- magnetos setting -->
             setprop("/controls/engines/engine/magnetos", 3);
           }
        }
        else{ <!-- engine running -->
          setprop("/controls/switches/starter", 0); 
        }

        <!-- axisValue 0~-1, R2, throttle -->
        if(0 >= axisValue){
           setprop("/controls/engines/engine/throttle", -axisValue);
        } 

        <!-- axisValue 0~1, L2, brake -->
        if(axisValue >= 0){ # L2 is positive (0 ~ 1)
          setprop("/controls/gear/brake-left", axisValue);
          setprop("/controls/gear/brake-right", axisValue);
        } 

        <!-- close engine -->
        if(axisValue > 0.8 and getprop("/controls/engines/engine/magnetos") != 0){
          setprop("/controls/engines/engine/magnetos", 0)
        }
      </script>
    </binding>
  </axis>

  <axis n="3">
    <name type="string">right stick up-down (down positive)</name>
    <desc type="string">adjust view direction pitch</desc>
    <low> <!-- up --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- down --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
<!-- add 

  <PropertyList>
    <js n="0" include="Input/Joysticks/GTA V like joystick setting for XBOX 360 Controller.xml"/>
  </PropertyList> 

  in FlightGear/data/joysticks.xml

  put this file in FlightGear/data/Input/Joysticks
-->

<?xml version="1.0"?>

<PropertyList>
  <name type="string">GTA V like joystick setting for XBOX 360 Controller</name>

  <axis n="0">
    <name type="string">left stick left-right (right positive)</name>
    <desc type="string">adjust aileron</desc>
    <dead-band type="double">0.2</dead-band> <!-- dead-band tag must precede binding tag -->
    <!-- if (input < abs(dead-band)) output = 0 -->
    <!-- if (input > dead-band) output = (output - dead-band) / (1 - dead-band) -->
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/aileron</property>
    </binding>
  </axis>

  <axis n="1">
    <name type="string">left stick up-down (down positive)</name>
    <desc type="string">adjust elevator</desc> 
    <dead-band type="double">0.2</dead-band>
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/elevator</property>
      <factor type="double">-1</factor> <!-- down positive, thus inverse -->
    </binding>
  </axis>

  <axis n="2">
    <name type="string">R2-L2 (L2 positive)</name>
    <desc type="string">start stop engine, adjust throttle, brake</desc>
    <dead-band type="double">0.1</dead-band>
    <binding>
<!-- add 

  <PropertyList>
    <js n="0" include="Input/Joysticks/GTA V like joystick setting for XBOX 360 Controller.xml"/>
  </PropertyList> 

  in FlightGear/data/joysticks.xml

  put this file in FlightGear/data/Input/Joysticks
-->

<?xml version="1.0"?>

<PropertyList>
  <name type="string">GTA V like joystick setting for XBOX 360 Controller</name>

  <axis n="0">
    <name type="string">left stick left-right (right positive)</name>
    <desc type="string">adjust aileron</desc>
    <dead-band type="double">0.2</dead-band> <!-- dead-band tag must precede binding tag -->
    <!-- if (input < abs(dead-band)) output = 0 -->
    <!-- if (input > dead-band) output = (output - dead-band) / (1 - dead-band) -->
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/aileron</property>
    </binding>
  </axis>

  <axis n="1">
    <name type="string">left stick up-down (down positive)</name>
    <desc type="string">adjust elevator</desc> 
    <dead-band type="double">0.2</dead-band>
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/elevator</property>
      <factor type="double">-1</factor> <!-- down positive, thus inverse -->
    </binding>
  </axis>

  <axis n="2">
    <name type="string">R2-L2 (L2 positive)</name>
    <desc type="string">start stop engine, adjust throttle, brake</desc>
    <dead-band type="double">0.1</dead-band>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        var axisValue = cmdarg().getNode("setting").getValue(); 
        <!-- the value of /input/joysticks/js/axis[2]/binding/setting -->

        <!-- engine start stop control -->
        if(getprop("/engines/engine/running") != 1 <!-- engine not running -->
             and -0.9 > axisValue){ <!-- R2 pushed near end -->
           setprop("/controls/switches/starter", 1);

           if(getprop("/controls/engines/engine/magnetos") != 3){ <!-- magnetos setting -->
             setprop("/controls/engines/engine/magnetos", 3);
           }
        }
        else{ <!-- engine running -->
          setprop("/controls/switches/starter", 0); 
        }

        <!-- axisValue 0~-1, R2, throttle -->
        if(0 >= axisValue){
           setprop("/controls/engines/engine/throttle", -axisValue);
        } 

        <!-- axisValue 0~1, L2, brake -->
        if(axisValue >= 0){ # L2 is positive (0 ~ 1)
          setprop("/controls/gear/brake-left", axisValue);
          setprop("/controls/gear/brake-right", axisValue);
        } 

        <!-- close engine -->
        if(axisValue > 0.8 and getprop("/controls/engines/engine/magnetos") != 0){
          setprop("/controls/engines/engine/magnetos", 0)
        }
      </script>
    </binding>
  </axis>

  <axis n="3">
    <name type="string">right stick up-down (down positive)</name>
    <desc type="string">adjust view direction pitch</desc>
    <low> <!-- up --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- down --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>

  <axis n="4">
    <name type="string">right stick left-right (right positive)</name>
    <desc type="string">adjust view direction heading (yaw)</desc>
    <low> <!-- left --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- right --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>

  <button n="0">
    <name type="string">A button</name>
    <desc type="string">decrease elevator trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.elevatorTrim(-1);
        gui.popupTip("elevator trim: " ~ getprop("/controls/flight/elevator-trim"), 1)
      </script>
    </binding>
  </button>

  <button n="1">
    <name type="string">B button</name>
    <desc type="string">increase aileron trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.aileronTrim(1);
        gui.popupTip("aileron trim: " ~ getprop("/controls/flight/aileron-trim"), 1)
      </script>
    </binding>
  </button>

  <button n="2">
    <name type="string">X button</name>
    <desc type="string">decrease aileron trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.aileronTrim(-1);
        gui.popupTip("aileron trim: " ~ getprop("/controls/flight/aileron-trim"), 1)  
      </script>
    </binding>
  </button>

  <button n="3">
    <name type="string">Y button</name>
    <desc type="string">increase elevator trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.elevatorTrim(1);
        gui.popupTip("elevator trim: " ~ getprop("/controls/flight/elevator-trim"), 1)
      </script>
    </binding>
  </button> 
  
  <button n="4">
    <name type="string">L1 button</name>
    <desc type="string">Rudder Right (Turn Left)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">-1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release L1 button --> 
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="5">
    <name type="string">R2 button</name>
    <desc type="string">Rudder Left (Turn Right)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release R2 button -->
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="6">
    <name type="string">BACK button</name>
    <desc type="string">change view</desc>
    <binding>
      <command type="string">property-cycle</command>
      <property type="string">/sim/current-view/view-number</property>
      <value>0</value> <!-- cockpit view -->
      <value>7</value> <!-- model view -->
      <value>5</value> <!-- chase without yaw view -->
    </binding>
  </button>

  <button n="7">
    <name type="string">START button</name>
    <desc type="string">pause</desc>
    <binding>
      <command type="string">pause</command>
    </binding>
  </button>

  <button n="9">
    <name type="string">right stick button</name>
    <desc type = "string">look back, look forward when released</desc>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        setprop("/sim/current-view/goal-heading-offset-deg", 180);
        setprop("/sim/current-view/goal-pitch-offset-deg", 0);
      </script>
    </binding>
    <mod-up>
      <binding>
        <command type="string">nasal</command>
        <script type="string">
          setprop("/sim/current-view/goal-heading-offset-deg", 0);
          setprop("/sim/current-view/goal-pitch-offset-deg", 0);
        </script>
      </binding>
    </mod-up>
  </button>
</PropertyList>
      <command type="string">nasal</command>
      <script type="string">
        var axisValue = cmdarg().getNode("setting").getValue(); 
        <!-- the value of /input/joysticks/js/axis[2]/binding/setting -->

        <!-- engine start stop control -->
        if(getprop("/engines/engine/running") != 1 <!-- engine not running -->
             and -0.9 > axisValue){ <!-- R2 pushed near end -->
           setprop("/controls/switches/starter", 1);

           if(getprop("/controls/engines/engine/magnetos") != 3){ <!-- magnetos setting -->
             setprop("/controls/engines/engine/magnetos", 3);
           }
        }
        else{ <!-- engine running -->
          setprop("/controls/switches/starter", 0); 
        }

        <!-- axisValue 0~-1, R2, throttle -->
        if(0 >= axisValue){
           setprop("/controls/engines/engine/throttle", -axisValue);
        } 

        <!-- axisValue 0~1, L2, brake -->
        if(axisValue >= 0){ # L2 is positive (0 ~ 1)
          setprop("/controls/gear/brake-left", axisValue);
          setprop("/controls/gear/brake-right", axisValue);
        } 

        <!-- close engine -->
        if(axisValue > 0.8 and getprop("/controls/engines/engine/magnetos") != 0){
          setprop("/controls/engines/engine/magnetos", 0)
        }
      </script>
    </binding>
  </axis>

  <axis n="3">
    <name type="string">right stick up-down (down positive)</name>
    <desc type="string">adjust view direction pitch</desc>
    <low> <!-- up --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- down --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>

  <axis n="4">
    <name type="string">right stick left-right (right positive)</name>
    <desc type="string">adjust view direction heading (yaw)</desc>
    <low> <!-- left --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- right --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>
<!-- add 

  <PropertyList>
    <js n="0" include="Input/Joysticks/GTA V like joystick setting for XBOX 360 Controller.xml"/>
  </PropertyList> 

  in FlightGear/data/joysticks.xml

  put this file in FlightGear/data/Input/Joysticks
-->

<?xml version="1.0"?>

<PropertyList>
  <name type="string">GTA V like joystick setting for XBOX 360 Controller</name>

  <axis n="0">
    <name type="string">left stick left-right (right positive)</name>
    <desc type="string">adjust aileron</desc>
    <dead-band type="double">0.2</dead-band> <!-- dead-band tag must precede binding tag -->
    <!-- if (input < abs(dead-band)) output = 0 -->
    <!-- if (input > dead-band) output = (output - dead-band) / (1 - dead-band) -->
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/aileron</property>
    </binding>
  </axis>

  <axis n="1">
    <name type="string">left stick up-down (down positive)</name>
    <desc type="string">adjust elevator</desc> 
    <dead-band type="double">0.2</dead-band>
    <binding>
      <command type="string">property-scale</command>
      <property type="string">/controls/flight/elevator</property>
      <factor type="double">-1</factor> <!-- down positive, thus inverse -->
    </binding>
  </axis>

  <axis n="2">
    <name type="string">R2-L2 (L2 positive)</name>
    <desc type="string">start stop engine, adjust throttle, brake</desc>
    <dead-band type="double">0.1</dead-band>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        var axisValue = cmdarg().getNode("setting").getValue(); 
        <!-- the value of /input/joysticks/js/axis[2]/binding/setting -->

        <!-- engine start stop control -->
        if(getprop("/engines/engine/running") != 1 <!-- engine not running -->
             and -0.9 > axisValue){ <!-- R2 pushed near end -->
           setprop("/controls/switches/starter", 1);

           if(getprop("/controls/engines/engine/magnetos") != 3){ <!-- magnetos setting -->
             setprop("/controls/engines/engine/magnetos", 3);
           }
        }
        else{ <!-- engine running -->
          setprop("/controls/switches/starter", 0); 
        }

        <!-- axisValue 0~-1, R2, throttle -->
        if(0 >= axisValue){
           setprop("/controls/engines/engine/throttle", -axisValue);
        } 

        <!-- axisValue 0~1, L2, brake -->
        if(axisValue >= 0){ # L2 is positive (0 ~ 1)
          setprop("/controls/gear/brake-left", axisValue);
          setprop("/controls/gear/brake-right", axisValue);
        } 

        <!-- close engine -->
        if(axisValue > 0.8 and getprop("/controls/engines/engine/magnetos") != 0){
          setprop("/controls/engines/engine/magnetos", 0)
        }
      </script>
    </binding>
  </axis>

  <axis n="3">
    <name type="string">right stick up-down (down positive)</name>
    <desc type="string">adjust view direction pitch</desc>
    <low> <!-- up --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- down --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>

  <axis n="4">
    <name type="string">right stick left-right (right positive)</name>
    <desc type="string">adjust view direction heading (yaw)</desc>
    <low> <!-- left --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- right --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>

  <button n="0">
    <name type="string">A button</name>
    <desc type="string">decrease elevator trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.elevatorTrim(-1);
        gui.popupTip("elevator trim: " ~ getprop("/controls/flight/elevator-trim"), 1)
      </script>
    </binding>
  </button>

  <button n="1">
    <name type="string">B button</name>
    <desc type="string">increase aileron trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.aileronTrim(1);
        gui.popupTip("aileron trim: " ~ getprop("/controls/flight/aileron-trim"), 1)
      </script>
    </binding>
  </button>

  <button n="2">
    <name type="string">X button</name>
    <desc type="string">decrease aileron trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.aileronTrim(-1);
        gui.popupTip("aileron trim: " ~ getprop("/controls/flight/aileron-trim"), 1)  
      </script>
    </binding>
  </button>

  <button n="3">
    <name type="string">Y button</name>
    <desc type="string">increase elevator trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.elevatorTrim(1);
        gui.popupTip("elevator trim: " ~ getprop("/controls/flight/elevator-trim"), 1)
      </script>
    </binding>
  </button> 
  
  <button n="4">
    <name type="string">L1 button</name>
    <desc type="string">Rudder Right (Turn Left)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">-1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release L1 button --> 
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="5">
    <name type="string">R2 button</name>
    <desc type="string">Rudder Left (Turn Right)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release R2 button -->
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="6">
    <name type="string">BACK button</name>
    <desc type="string">change view</desc>
    <binding>
      <command type="string">property-cycle</command>
      <property type="string">/sim/current-view/view-number</property>
      <value>0</value> <!-- cockpit view -->
      <value>7</value> <!-- model view -->
      <value>5</value> <!-- chase without yaw view -->
    </binding>
  </button>

  <button n="7">
    <name type="string">START button</name>
    <desc type="string">pause</desc>
    <binding>
      <command type="string">pause</command>
    </binding>
  </button>

  <button n="9">
    <name type="string">right stick button</name>
    <desc type = "string">look back, look forward when released</desc>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        setprop("/sim/current-view/goal-heading-offset-deg", 180);
        setprop("/sim/current-view/goal-pitch-offset-deg", 0);
      </script>
    </binding>
    <mod-up>
      <binding>
        <command type="string">nasal</command>
        <script type="string">
          setprop("/sim/current-view/goal-heading-offset-deg", 0);
          setprop("/sim/current-view/goal-pitch-offset-deg", 0);
        </script>
      </binding>
    </mod-up>
  </button>
</PropertyList>

  <button n="0">
    <name type="string">A button</name>
    <desc type="string">decrease elevator trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.elevatorTrim(-1);
        gui.popupTip("elevator trim: " ~ getprop("/controls/flight/elevator-trim"), 1)
      </script>
    </binding>
  </button>

  <button n="1">
    <name type="string">B button</name>
    <desc type="string">increase aileron trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.aileronTrim(1);
        gui.popupTip("aileron trim: " ~ getprop("/controls/flight/aileron-trim"), 1)
      </script>
    </binding>
  </button>

  <button n="2">
    <name type="string">X button</name>
    <desc type="string">decrease aileron trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.aileronTrim(-1);
        gui.popupTip("aileron trim: " ~ getprop("/controls/flight/aileron-trim"), 1)  
      </script>
    </binding>
  </button>

  <button n="3">
    <name type="string">Y button</name>
    <desc type="string">increase elevator trim </desc>
    <repeatable type="string">true</repeatable>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        controls.elevatorTrim(1);
        gui.popupTip("elevator trim: " ~ getprop("/controls/flight/elevator-trim"), 1)
      </script>
    </binding>
  </button> 
  
  <button n="4">
    <name type="string">L1 button</name>
    <desc type="string">Rudder Right (Turn Left)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">-1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release L1 button --> 
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="5">
    <name type="string">R2 button</name>
    <desc type="string">Rudder Left (Turn Right)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release R2 button -->
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="6">
    <name type="string">BACK button</name>
    <desc type="string">change view</desc>
    <binding>
      <command type="string">property-cycle</command>
      <property type="string">/sim/current-view/view-number</property>
      <value>0</value> <!-- cockpit view -->
      <value>7</value> <!-- model view -->
      <value>5</value> <!-- chase without yaw view -->
    </binding>
  </button>

  <button n="7">
    <name type="string">START button</name>
    <desc type="string">pause</desc>
    <binding>
      <command type="string">pause</command>
    </binding>
  </button>

  <button n="9">
    <name type="string">right stick button</name>
    <desc type = "string">look back, look forward when released</desc>
    <binding>
      <command type="string">nasal</command>
      <script type="string">
        setprop("/sim/current-view/goal-heading-offset-deg", 180);
        setprop("/sim/current-view/goal-pitch-offset-deg", 0);
      </script>
    </binding>
    <mod-up>
      <binding>
        <command type="string">nasal</command>
        <script type="string">
          setprop("/sim/current-view/goal-heading-offset-deg", 0);
          setprop("/sim/current-view/goal-pitch-offset-deg", 0);
        </script>
      </binding>
    </mod-up>
  </button>
</PropertyList>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>

  <axis n="4">
    <name type="string">right stick left-right (right positive)</name>
    <desc type="string">adjust view direction heading (yaw)</desc>
    <low> <!-- left --> <!-- axis value < -0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">-1</step>
      </binding>
    </low>
    <high> <!-- right --> <!-- axis value > 0.9 -->
      <repeatable type="string">true</repeatable>
      <binding>
        <command type="string">property-adjust</command>
        <property type="string">/sim/current-view/goal-heading-offset-deg</property>
        <step type="double">1</step>
      </binding>
    </high>
  </axis>

  <button n="4">
    <name type="string">L1 button</name>
    <desc type="string">Rudder Right (Turn Left)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">-1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release L1 button --> 
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="5">
    <name type="string">R2 button</name>
    <desc type="string">Rudder Left (Turn Right)</desc>
    <binding>
      <command type="string">property-interpolate</command>
      <property type="string">/controls/flight/rudder</property>
      <value type="double">1</value>
      <rate type="double">0.5</rate>
    </binding>
    <mod-up> <!-- release R2 button -->
      <binding>
        <command type="string">property-interpolate</command>
        <property type="string">/controls/flight/rudder</property>
        <value type="double">0</value>
        <rate type="double">0.5</rate>
      </binding>
    </mod-up>
  </button>

  <button n="6">
    <name type="string">BACK button</name>
    <desc type="string">change view</desc>
    <binding>
      <command type="string">property-cycle</command>
      <property type="string">/sim/current-view/view-number</property>
      <value>0</value> <!-- cockpit view -->
      <value>7</value> <!-- model view -->
      <value>5</value> <!-- chase without yaw view -->
    </binding>
  </button>

  <button n="7">
    <name type="string">START button</name>
    <desc type="string">pause</desc>
    <binding>
      <command type="string">pause</command>
    </binding>
  </button>

  <button n="9">
    <name type="string">right stick button</name>
    <desc type = "string">look back, look forward when released</desc>
    <binding>
      <command type="string">property-assign</command>
      <property type="string">/sim/current-view/goal-heading-offset-deg</property>
      <value type="double">180</value>
    </binding>
    <binding>
      <command type="string">property-assign</command>
      <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
      <value type="double">0</value>
    </binding>
    <mod-up>
      <binding>
 <command type="string">property-assign</command>
 <property type="string">/sim/current-view/goal-heading-offset-deg</property>
 <value type="double">0</value>
      </binding>
      <binding>
 <command type="string">property-assign</command>
 <property type="string">/sim/current-view/goal-pitch-offset-deg</property>
 <value type="double">0</value>
      </binding>
    </mod-up>
  </button>
</PropertyList>