I started to work on this project on January because I was not satisfied of the Thrustmaster scripts tool: I use MFG crosswind rudder pedals, and after a few trials I have seen that Thrustmaster Target voluntarily not support non-Thrustmaster hardware. After a quick tour of other solutions (such as Joystick Gremlin or UCR), I decided to code my own tool: compared to Joystick Gremlin and UCR, I wanted something more closer to Thrustmaster scripts, meaning: first, less based on GUI and second, with the profile defined in C++ (in which I am really fluent). This thread is somehow the continuation of this one (https://robertsspaceindustries.com/spectrum/community/SC/forum/50174/thread/joysticks-programming-an-alternative-to-tm-target-/995977), which I posted nearly 3 months ago. At that time the tool was in an early state, just usable. It is more friendly and simpler to use now. Download and installation The tool can be download from here: https://github.com/3noix/UJPS To use it you will need to install Qt 5 and vJoy, but the tool (UJPS) does not need to be installed (i.e. no installer, no modification in WIndows registry, ...). You will have to build the tool using Qt, via the provided bat file... for now I don't provide directly binaries, because anyway if you don't install Qt, you will only be able to use profiles written by other people without the slightest modification... and today the UJPS community must be just me :slightly_smiling_face:. But in the future, if some people feel the need of it, I could obviously add it. See the documentation for details (https://github.com/3noix/UJPS/blob/master/UJPS-C%2B%2B_V2.2.0_Manual_issue1.pdf). When this post was first created (on 27 May 2018) the version was V2.2.0. The current one is V2.6.4. Changes notes can be found at this end of the documentation. Overview UJPS C++ is a tool that allows you to program your joysticks, whatever their brands are, but on Windows only, using C++ programming language. But just as Thrustmaster Target scripts with C, you don't need an accurate knowledge of C++ to create UJPS profiles: many functions are provided to ease the coding of the profiles. UJPS can use as inputs all the following: real controllers recognized by Windows as game controllers other devices recognized by Windows as game controllers, such as vJoy devices (it can be useful if you feed one with an eye tracking device using FreePIE for example) "remote controllers": an application that can be run on your PC or on mobile devices and that exchange data with the profile. If you don't know what I am talking about, take a look at Roccat Power Grid or LEA extended input. The difference is that the graphics part of the application is fully up to you (there is no GUI editor provided) And the possible outputs are: vJoy devices keyboard keystrokes (I recommend you to limit its use to the minimum to avoid keystrokes interaction: e.g. LShift+A and LCtrl+B might generate also LShift+B or LCtrl+A) The main program is a simple GUI that allows you to choose the profile to run and play / stop / unload it. Other utility programs are provided to monitor your controllers (to know exactly how UJPS see them) or to finely tune your axes curves. Usage Hereafter I just show you a few lines of code to give you an idea of how a profile is defined (I use the "tmwj" abbreviation for Thrustmaster Warthog Joystick). On the GitHub repository, you will find several examples, including my current Star Citizen profile "StarCitizen_3.1.4_v5". For the profile "StarCitizen_3.0.1_v1", both my Thrustmaster script and my UJPS profile are available, the comparison should be helpful. bool Profile::setupJoysticks() { // we retrieve pointers on real joysticks we are interested in tmwj = this->registerRealJoystick("Joystick - HOTAS Warthog"); if (tmwj) {emit message("Warthog joystick detected !",Qt::black);} else {emit message("Warthog joystick not detected !",Qt::red); return false;} // setup of 1 virtual joystick vj1 = new VirtualJoystick(1,50); emit message("Virtual joystick 1 configured",Qt::black); this->registerVirtualJoystick(vj1); return (tmwj && vj1); } void Profile::runFirstStep() { // registering a modifier button this->registerLayerDim1(Layers::In, tmwt, TMWJ::S4); // initialize the virtual joysticks data using the real joysticks data vj1->resetReport(); vj1->setAxis(SC1::AxisFlightStrafeVertical,0.0f); // vertical strafe at 0 to avoid bad surprises when starting up the ship for the first time // mappings creation MapAxis(tmwj, TMWJ::JOYX, AllLayers, vj1, SC1::AxisFlightRoll); // basic axis mapping MapButton(tmwj, TMWJ::TG1, AllLayers, vj1, SC1::FireGroup1); // basic button mapping Map(tmwj, ControlType::Button, TMWJ::S2, AllLayers, new TriggerButtonPress{}, new ActionCallback{[this]() {this->myCustomFunction();}}); // custom function execution Map(tmwj, ControlType::Button, TMWJ::H2U, AllLayers, new TriggerButtonRelease{}, new ActionChain{ new ActionButtonPulse{vj1,SC1::ResetPowerDistribution,ms2cycles(200)}, // button pulse of 200 ms new Delay{ms2cycles(300)}, // and 300 ms before the beginning of the first pulse new ActionKeyPulse{SCK::TrackIR_Center,0,ms2cycles(200)} // a keystroke pulse of 200 ms }); }1