Discussion Coffees_Fa_Off_Advanced_V1: Joystick emulates mouse through of it's range. Must have for FA OFF T16000 or Warthog users.

Coffees_Fa_Off_Advanced_V1: Joystick emulates mouse through [part] of it's range. Must have for FA OFF T16000 or Warthog users.

So, I've been avoiding using mouse for FA Off for the longest time (years), and I thought I'd try out to see what mouse emulation is like on Thrustmaster TARGET Script Software. So my find: it's absolutely awesome! I feel like this works better than mouse and keyboard, and it's all joystick! I've very excited, and just wanted to share in hopes you all have fun with this too.

This picture illustrates the range of motion (for Mouse and Joystick):

Coffees_Fa_Off_Advanced_V1.jpg



Here's the TMC file code:

C:
include "target.tmh"

///////////////////////////////////////////////////////////////////////////////
//     Coffees_Fa_Off_Advanced_V1
//     Version: 1.0
//     Author: MrCoffee76
//     Date: 2022 02 01
//
//     description:
//
//     A Thrustmaster T16000 stick script that has a (roughly)50% deadzone for
//     joystick and makes pitch and yaw (not roll) function like a mouse within
//  this deadzone with micro trim.
//     This substantially stabilizes aiming of fixed weapons during Flight Assist
//    maneuvers.
//
//     Installation:
//
//    1) Install Thrustmaster Target Script Editor 3.0.18.028 (or later?)
//    2) Place this text into a .tmc file (if you copy pasted).  Otherwise, just
//       save this file somewhere on your drive.
//    3) Run the .tmc file you created or saved in step 2
//    4) Make sure your yaw axis is set up properly in DEFAULT SETTINGS below
//    5) Check Elite Dangerous mouse settings:
//        Mouse X: Yaw
//        Relative Mouse X-Axis: On
//        Mouse Y: Pitch Inverted
//        Relative Mouse Y-Axis: On
//        Mouse Sensitivity: low (your choice, start at low settings imo)
//        Relative Mouse Rate: full
//        Mouse Deadzone: 0
//        Mouse Power Curve: 0
//        Mouse Widget: your choice
//
//
//    Issues: after some rolls, pitches and yaws, you will most likely have to
//        constantly to get on target.  Doing a quick 55% pitch/yaw move usually
//        cancels most of the stray.  Future versions will probably have a trim
//        function that reduces stray within a second or two.
//
//    Why: This little experiment/find changed my FA off aiming.  No mouse needed
//        and I prefer aiming with the joystick now.
//        So, all of those people who gave up their Thrustmaster sticks for mouse
//        can potentially benefit as much as I have.  Good luck!
//
///////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////
// DEFAULT SETTINGS
// REQUIRED for Script
///////////////////////////////////////////////////////////////////////////////

// NOTE: if you use left and right on stick for yawing in ship, change RUDDER
//       to DX_X_AXIS below.  For example: define ED_YAW_AXIS RUDDER
define ED_YAW_AXIS RUDDER
define KEY_TOGGLE_MOUSE TS4

// if your trigger is broken and clicks off and on, try
// define USE_TRIGGER_FIX_HACK 1
define USE_TRIGGER_FIX_HACK 0


///////////////////////////////////////////////////////////////////////////////
// END OF DEFAULT SETTINGS
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////




// DO NOT change these unless you want to change
define NOSE_DOWN_THRESHOLD -2048
define NOSE_UP_THRESHOLD 16384
define NOSE_LEFT_THRESHOLD -16384
define NOSE_RIGHT_THRESHOLD 16384
// these values below are pre calculated.  If you change the thresholds
// above, you will most likely need to recalculate these values below
// to get maximum pitch/yaw authority.
// for example, since we only use half the range for yaw, 32767 / 16384 = 2
// A divider is used to for nosing down so we reduce bounce effect
define NOSE_DOWN_OFFSET_MULT 2
define NOSE_UP_TRIM_DIVIDER 2
define NOSE_YAW_OFFSET_MULT 2

// trim cutoff levels and max trim authority
// max joystick deflection usually is 32767 so a value of 32 or -32 is a very small
// amount of adjustment.
define TRIM_CUTOFF_POS 1024
define TRIM_CUTOFF_NEG -1024
define MAX_TRIM_AUTHORITY_POS 32
define MAX_TRIM_AUTHORITY_NEG -32

define ED_MOUSE_CONFIG 2

int g_default_config = 1;
int g_config = g_default_config;

///////////////////////////////////////////////////////////////////////////////
// END REQUIRED
///////////////////////////////////////////////////////////////////////////////

//program startup
int main()
{
 

    Configure(&HCougar, MODE_EXCLUDED);
    Configure(&Joystick, MODE_EXCLUDED);
    // Configure(&Throttle, MODE_EXCLUDED);
    Configure(&LMFD, MODE_EXCLUDED);
    Configure(&RMFD, MODE_EXCLUDED);
    if(Init(&EventHandle)) return 1;
    SetKBRate(32, 50);
    SetKBLayout(KB_ENG);
    SetShiftButton(0, 0, 0, 0, 0, 0);

    // hat switch
    MapKeyIOUMD(&T16000, H1D, DOWN+F9, DOWN+F9, DOWN+F9, DOWN+F9, DOWN+F9, DOWN+F9);
    MapKeyRIOUMD(&T16000, H1D, UP+F9, UP+F9, UP+F9, UP+F9, UP+F9, UP+F9);
    MapKeyIOUMD(&T16000, H1U, DOWN+F8, DOWN+F8, DOWN+F8, DOWN+F8, DOWN+F8, DOWN+F8);
    MapKeyRIOUMD(&T16000, H1U, UP+F8, UP+F8, UP+F8, UP+F8, UP+F8, UP+F8);
    MapKeyIOUMD(&T16000, H1R, DOWN+F12, DOWN+F12, DOWN+F12, DOWN+F12, DOWN+F12, DOWN+F12);
    MapKeyRIOUMD(&T16000, H1R, UP+F12, UP+F12, UP+F12, UP+F12, UP+F12, UP+F12);
    MapKeyIOUMD(&T16000, H1L, DOWN+F11, DOWN+F11, DOWN+F11, DOWN+F11, DOWN+F11, DOWN+F11);
    MapKeyRIOUMD(&T16000, H1L, UP+F11, UP+F11, UP+F11, UP+F11, UP+F11, UP+F11);

    MapKey(&T16000, TS2, DX2 );
 
 
    if ( USE_TRIGGER_FIX_HACK == 1 )
    {
        MapKey(&T16000, TG1, EXEC( "MainTrigger(1);" ) );
        MapKeyR(&T16000, TG1, EXEC( "MainTrigger(0);" ) );
    }
 
    // REQUIRED for ED_fa_off_stick_mouse_advanced
    MapKey(&T16000, KEY_TOGGLE_MOUSE, EXEC( "ToggleMouse( 1 ); " ) );
    MapJoystickAxes();
    // END REQUIRED
     
 
 
    // TWCS initialization
    SetKBLayout(KB_ENG);
    SetShiftButton(0, 0, 0, 0, 0, 0);
 
    // TWCS axes and buttons.  Most of these are left as their default buttons.  See next section for changes.
    MapKey(&TWCSThrottle,    TBTN2,    DX22 );
    MapKey(&TWCSThrottle,    TBTN3,    DX23 );
 
    MapKey(&TWCSThrottle,    TBTN4,    DX24 );
 
    MapKey(&TWCSThrottle,    TBTN5,    DX25 );
 
    MapKey(&TWCSThrottle,    TLOCK,    DX26); // Analog stick click.
    MapKey(&TWCSThrottle,    THAT1U,    DX27); // THAT1 is the U-shaped hat. RIGHT is forward/away from you on the hat, LEFT is backward/toward you.
    MapKey(&TWCSThrottle,    THAT1R,    DX28);
    MapKey(&TWCSThrottle,    THAT1D,    DX29);
    MapKey(&TWCSThrottle,    THAT1L,    DX30);
    MapKey(&TWCSThrottle,    THAT3U,    DX31); // THAT3 is the castle hat. RIGHT is forward/away from you on the hat, LEFT is backward/toward you.
    MapKey(&TWCSThrottle,    THAT3R,    DX32);
    MapKey(&TWCSThrottle,    THAT3D,    DX17);
    MapKey(&TWCSThrottle,    THAT3L,    DX18);
    MapKey(&TWCSThrottle,    THAT2U,    DXHATUP); // THAT2 is the conical POV hat.
    MapKey(&TWCSThrottle,    THAT2R,    DXHATRIGHT);
    MapKey(&TWCSThrottle,    THAT2D,    DXHATDOWN);
    MapKey(&TWCSThrottle,    THAT2L,    DXHATLEFT);
 
 
    // TWCS axes.  These are the default settings.
    MapAxis(&TWCSThrottle, TTHR, DX_THROTTLE_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); // normal
    MapAxis(&TWCSThrottle, TANT, DX_SLIDER_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); // normal
    MapAxis(&TWCSThrottle, TRDR, DX_Z_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); // normal
    SetSCurve(&TWCSThrottle, TRDR, 2, 2, 2, 6, 0 );

    MapAxis(&TWCSThrottle, TMSTX, DX_XROT_AXIS, AXIS_NORMAL, MAP_ABSOLUTE);
    SetSCurve(&TWCSThrottle, TMSTX, 0, 3, 0, 4, 0);
 
    MapAxis(&TWCSThrottle, TMSTY, DX_YROT_AXIS, AXIS_NORMAL, MAP_ABSOLUTE);
    SetSCurve(&TWCSThrottle, TMSTY, 0, 0, 0, 4, 0);
 
    // Rudder axes, if you have the rudder plugged into the throttle, instead of into the computer directly.  These are all disabled here.
    MapAxis(&TWCSThrottle, TCSRIGHT, 0, AXIS_NORMAL, MAP_ABSOLUTE);
    SetSCurve(&TWCSThrottle, TCSRIGHT, 0, 0, 0, 0, 0);
    MapAxis(&TWCSThrottle, TCSRUDDER, 0, AXIS_NORMAL, MAP_ABSOLUTE);
    SetSCurve(&TWCSThrottle, TCSRUDDER, 0, 0, 0, 0, 0);
    MapAxis(&TWCSThrottle, TCSLEFT, 0, AXIS_NORMAL, MAP_ABSOLUTE);
    SetSCurve(&TWCSThrottle, TCSLEFT, 0, 0, 0, 0, 0);
 
 
 
 
}



///////////////////////////////////////////////////////////////////////////////
//event handler
int EventHandle(int type, alias o, int x)
{
 
    DefaultMapping(&o, x);
 
    // REQUIRED for ED_fa_off_stick_mouse_advanced
    // check to see if we're in mouse mode and using T16000
     if ( &o == &T16000 )
    {  
        if ( x == JOYY )
            ApplyEdgeJoystickInputY(); // check to see if we need pitch authority
        else if ( x == ED_YAW_AXIS )
            ApplyEdgeJoystickInputZ(); // check to see if we need yaw authority
    }
    // END REQUIRED
 
}

////////////////////////////////////////////////////////////////////////////////
// REQUIRED for ED_fa_off_stick_mouse_advanced
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//    int ApplyEdgeJoystickInputY()
//    purpose:     when the joystick is in mouse mode and is moved 50% back or
//                forward (> 0%), this function helps pitch rate by adding
//                joystick input.
//                Any amount of forward pitch (nosing down) will cause this
//                function to apply nose down joystick inputs.  Throughout the
//                entire pitch range, this function will apply tiny trim amounts
//                however if the joystick is moved back to 50% the function will
//                start to apply joystick inputs - 1% input at the 50% pitch mark
//                and 100% input at the 100% pitch mark.
////////////////////////////////////////////////////////////////////////////////
int ApplyEdgeJoystickInputY()
{
 
    int pos = T16000[ JOYY ];
    int new_val = 0;
 
    if ( g_config != ED_MOUSE_CONFIG )
        return 0;
 
    if ( pos >= NOSE_UP_THRESHOLD ) // does the pitch need lots of help?
        new_val = ( pos - NOSE_UP_THRESHOLD ) * NOSE_DOWN_OFFSET_MULT;
    else if ( pos <= NOSE_DOWN_THRESHOLD ) // does the pitch need lots of help?
        new_val = ( pos - NOSE_DOWN_THRESHOLD );
    else if ( pos > TRIM_CUTOFF_POS ) // tiny trim help
         new_val = MAX_TRIM_AUTHORITY_POS;
    else if ( pos < TRIM_CUTOFF_NEG )
        new_val = MAX_TRIM_AUTHORITY_NEG;
    else if ( pos > MAX_TRIM_AUTHORITY_POS )
         new_val = pos / MAX_TRIM_AUTHORITY_POS;
    else if ( pos < MAX_TRIM_AUTHORITY_NEG )
        new_val = pos / ( MAX_TRIM_AUTHORITY_POS / NOSE_UP_TRIM_DIVIDER );
 
 
    DXAxis( DX_Y_AXIS, new_val );
 
    printf( "ApplyEdgeJoystickInputY(), new_val: %d\xa", new_val );
 
    return 1;
}


////////////////////////////////////////////////////////////////////////////////
//    int ApplyEdgeJoystickInputZ()
//    purpose:     when the joystick is in mouse mode and is moved 50% left or
//                right, this function helps yaw rate by adding joystick input.
//                This function always trims by small amounts.
////////////////////////////////////////////////////////////////////////////////

int ApplyEdgeJoystickInputZ()
{
    int pos = T16000[ ED_YAW_AXIS ];
    int new_val = 0;


    if ( g_config != ED_MOUSE_CONFIG )
        return 0;
     
    if ( pos >= NOSE_RIGHT_THRESHOLD )
        new_val = ( pos - NOSE_RIGHT_THRESHOLD ) * NOSE_YAW_OFFSET_MULT;
    else if ( pos <= NOSE_LEFT_THRESHOLD )
        new_val = ( pos - NOSE_LEFT_THRESHOLD ) * NOSE_YAW_OFFSET_MULT;
    else if ( pos > TRIM_CUTOFF_POS )
         new_val = MAX_TRIM_AUTHORITY_POS;
    else if ( pos < TRIM_CUTOFF_NEG )
        new_val = MAX_TRIM_AUTHORITY_NEG;
    else if ( pos > MAX_TRIM_AUTHORITY_POS )
         new_val = pos / MAX_TRIM_AUTHORITY_POS;
    else if ( pos < MAX_TRIM_AUTHORITY_NEG )
        new_val = pos / MAX_TRIM_AUTHORITY_POS;
 
 
    DXAxis( DX_ZROT_AXIS, new_val );
 
    printf( "ApplyEdgeJoystickInputZ(), new_val: %d\xa", new_val );
 
 
    return 1;
}

///////////////////////////////////////////////////////////////////////////////


int ToggleMouse( int cmd ) // 0 = reset, otherwise increment
{
    if ( g_config == g_default_config )
    {
        g_config = ED_MOUSE_CONFIG;
        MapMouseAxes();
    }
    else
    {
        g_config = g_default_config;
        MapJoystickAxes();
    }
    return 0;
}


///////////////////////////////////////////////////////////////////////////////

int MapMouseAxes()
{
    DXAxis( MOUSE_X_AXIS, 0 );
    DXAxis( MOUSE_Y_AXIS, 0 );
 
    MapAxis(&T16000, ED_YAW_AXIS, DX_X_AXIS, 0, 0);
    MapAxis(&T16000, JOYY, DX_Y_AXIS, 0, 0);
 
 
    MapAxis(&T16000, ED_YAW_AXIS, MOUSE_X_AXIS, AXIS_NORMAL, MAP_ABSOLUTE);
    MapAxis(&T16000, JOYY, MOUSE_Y_AXIS, AXIS_NORMAL, MAP_ABSOLUTE);

    SetSCurve(&T16000, ED_YAW_AXIS, 0, 0, 0, -1, -10);
    SetSCurve(&T16000, JOYY, 0, 0, 0, -1, -10);
 
    return 0;
}

///////////////////////////////////////////////////////////////////////////////

int MapJoystickAxes()
{
 
    MapAxis(&T16000, JOYX, DX_X_AXIS, AXIS_NORMAL, MAP_ABSOLUTE);
    SetSCurve(&T16000, JOYX, 2, 5, 2, 2, 0);
    MapAxis(&T16000, JOYY, DX_Y_AXIS, AXIS_NORMAL, MAP_ABSOLUTE);
    SetSCurve(&T16000, JOYY, 2, 2, 2, 3, 0);
    MapAxis(&T16000, RUDDER, DX_ZROT_AXIS, AXIS_NORMAL, MAP_ABSOLUTE);
    SetSCurve(&T16000, RUDDER, 2, 2, 2, 5, 0);
 
    return 0;
}


///////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////
// END REQUIRED
///////////////////////////////////////////////////////////////////////////////
 

///////////////////////////////////////////////////////////////////////////////
// Extras
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////


int MainTrigger( int v )
{
    int i = 0;
    int j;

    if ( v == 0 ) // released?
    {
        g_trigger1 = 1; // about to depress
        while ( i < 17179869184 && g_trigger1 < 2 ); // polling loop or times out
                 
 
        if ( g_trigger1 == 1 ) // are we still in the same g_trigger1 depress state?
        {
            KeyU( DX1 );
            g_trigger1 = 0;
        }    
    }
    else // pressed down
    {
        KeyD( DX1 );
        g_trigger1 = 2;
    }
 
    return 0;
}

///////////////////////////////////////////////////////////////////////////////
 

Attachments

  • Coffees_Fa_Off_Advanced_V1_20200201.zip
    3.8 KB · Views: 151
Wow.....we need a logitech X56 version ASAP...assuming this is legal?
Would this mean the end of hotas crap vs kbm pvp?
 
Last edited:
Maybe others who know more about the legality of this will chime in. I did some research regarding legality, I didn't find much that would stand in the way of this. Also, if it were not legal, it would make me wonder if Joystick curves would also be an issue. Has Thrustmaster's TARGET ever been an issue with Frontier?

Regarding X56: can Logitech emulate mouse axes?
 
Well if anyone can make this happen for the saitek/logitech series hotas's it would be lovely.
As to legality, its not for me to say, perhaps someone more savvy, a moderator or fdev comment?
+1 Op
 
Basically it's a script whereby you get the accuracy and control with fa off using a kbm setup, with a hotas setup instead which to us hotas users is a holy grail moment for fa off combat.
 
It's hard to explain, but I find it works so much better with FA OFF. To explain requires about 1000 words and involves things like relative mouse vs absolute mouse and angles vs angular acceleration. It's rough 🤣. If you ever used a T16000, Warthog or any other TM product that allows you to use TARGET you can just post these lines in to begin a test:

MapAxis(&T16000, RUDDER, DX_X_AXIS, 0, 0);
MapAxis(&T16000, JOYY, DX_Y_AXIS, 0, 0);


MapAxis(&T16000, RUDDER, MOUSE_X_AXIS, AXIS_NORMAL, MAP_ABSOLUTE);
MapAxis(&T16000, JOYY, MOUSE_Y_AXIS, AXIS_NORMAL, MAP_ABSOLUTE);

SetSCurve(&T16000, RUDDER, 0, 0, 0, -1, -10);
SetSCurve(&T16000, JOYY, 0, 0, 0, -1, -10);

[edit] Change RUDDER to whatever axis you use for yaw if you don't twist. IIRC, JOYX is the T16000's X axis.
[edit2] Needed mouse settings for ED:
Check Elite Dangerous mouse settings:
// Mouse X: Yaw
// Relative Mouse X-Axis: On
// Mouse Y: Pitch Inverted
// Relative Mouse Y-Axis: On
// Mouse Sensitivity: low (your choice, start at low settings imo)
// Relative Mouse Rate: full
// Mouse Deadzone: 0
// Mouse Power Curve: 0
// Mouse Widget: your choice
 
Last edited:
Interesting. So what are you doing that makes FA off hotas aiming easier, if I may ask? Curves? Better stick (yeah there's much better sticks out there)?

I flew FA off for close to 4 years (off and on), no curves on axes and I had to "twitch" to clean up my FA off to aim rail guns or PAs. It was do-able but alot of work.

I was actually thinking about getting a Virpil or VKB Gunfighter but after this find with TARGET, I might hold off.
 
Maybe others who know more about the legality of this will chime in. I did some research regarding legality, I didn't find much that would stand in the way of this. Also, if it were not legal, it would make me wonder if Joystick curves would also be an issue. Has Thrustmaster's TARGET ever been an issue with Frontier?

Regarding X56: can Logitech emulate mouse axes?

EDIT: OOOPS...didn't realise this thread was 2.5 years old!

Hiya,

First up, thanks for posting this, I'm keen to give it a try and if it's as good as you say it is, I'll incorporate into my WARTHOG script.
Like you, I've been trying to avoid having to switch to KB+Mouse when FA-Off and I'm extremely crap just using the WARTHOG with special curve to try to smooth things out.

Re Legality, I cannot say for sure but my script and Aussiedroid's do automate a lot of ship functions and to date (over 3 years) no-one has challenged the legality and I've never read anywhere that others have been challenged.

Clicker
 
Back
Top Bottom