• Which the release of FS2020 we see an explosition of activity on the forun and of course we are very happy to see this. But having all questions about FS2020 in one forum becomes a bit messy. So therefore we would like to ask you all to use the following guidelines when posting your questions:

    • Tag FS2020 specific questions with the MSFS2020 tag.
    • Questions about making 3D assets can be posted in the 3D asset design forum. Either post them in the subforum of the modelling tool you use or in the general forum if they are general.
    • Questions about aircraft design can be posted in the Aircraft design forum
    • Questions about airport design can be posted in the FS2020 airport design forum. Once airport development tools have been updated for FS2020 you can post tool speciifc questions in the subforums of those tools as well of course.
    • Questions about terrain design can be posted in the FS2020 terrain design forum.
    • Questions about SimConnect can be posted in the SimConnect forum.

    Any other question that is not specific to an aspect of development or tool can be posted in the General chat forum.

    By following these guidelines we make sure that the forums remain easy to read for everybody and also that the right people can find your post to answer it.

P3D v4 XML Keys: Detect axis mapping and trap

Messages
12
Country
belgium
Hello all,

It's been a long time since I last posted in this forum, but I've been lurking around and soaking knowledge like a sponge.
I'm designing a study level aircraft with TPE-331 engines (single shaft turboprop) and I've found through trial and error how I need to set my power and RPM levers in order to get the correct reactions from the engine so it resembles real life (start locks, low idle, high idle, beta, etc...).
The only problem with this is that I need to trap the axis that control Power (throttle) and RPM for each engine (or all engines if such is the mapping) and send each of these values to an LVar.
These Lvars will be evaluated through a convoluted set of conditions that will then apply the correct power lever and RPM lever positions to the sim AVars through PID loops. After that, the Lvars will only be used for the display of the levers in the cockpit.

I know XML Keys can do this (I still need to understand exactly how).
All the examples of code I've seen in here trap a given joystick axis without knowing what the mapping of said axis is.
I know my control settings, but I'd like to distribute this airplane to some other people and I don't know which axis is mapped to which value in their setup.

So my question is:
Is there a way for XMLKeys to know what each joystick axis is mapped to?
Or, is there a way to know what joystick axis is controlling the general throttle or engine 1 throttle / engine rpm, etc?

If I can determine which axis controls my Power and RPM for each engine (or both) then I think I can easily do the rest.

I'm trying to stay away from Simconnect gauges as I'm unfamiliar with C++ and I'm trying to get this project over asap, so learning C++ right now is not really an option (I'll get to it, I promise).

Thanks for the help.
 
Have you taken a look at (A:GENERAL ENG1 THROTTLE LEVER POSITION, part) and (A:GENERAL ENG1 PROPELLER LEVER POSITION, part) to see if they could be used to accomplish the same thing?

Bob
 
Have you taken a look at (A:GENERAL ENG1 THROTTLE LEVER POSITION, part) and (A:GENERAL ENG1 PROPELLER LEVER POSITION, part) to see if they could be used to accomplish the same thing?

Bob
Hey Bob,

Thanks for taking the time!

Unless I'm doing something wrong, whenever I try to set the AVars directly, the sim starts fighting between the joystick input and the value I set in the AVar and I get "jumpy" levers in the sim.

In some ranges of the power lever, the user will actually be operating the sim RPM lever with the physical power lever and vice-versa, this is why I need to trap the inputs so the sim doesn't see them, but I need to also know where the physical joystick axis are.

I think only XML keys or simconnect can do it. Unless you've done this successfully before and you could show me how, which of course would be greatly appreciated.
 
You need to control the AXIS inputs. It's the set of inputs with the word AXIS in them. You do NOT need to know what hardware is or isn't attached to the AXIS input to do this. SimConnect would be the best approach, if you know how to use it. I used SimConnect to intercept the throttle axis for an aircraft, so I know it works... and works well. The ONLY catch is that any visual 3D elements that depict the throttle, condition or prop levers are probably NOT going to behave correctly because they'll move based on YOUR commands and ignore the user's physical hardware. For that, I'd recommend a custom var for the visual elements to use.
 
You need to control the AXIS inputs. It's the set of inputs with the word AXIS in them. You do NOT need to know what hardware is or isn't attached to the AXIS input to do this. SimConnect would be the best approach, if you know how to use it. I used SimConnect to intercept the throttle axis for an aircraft, so I know it works... and works well. The ONLY catch is that any visual 3D elements that depict the throttle, condition or prop levers are probably NOT going to behave correctly because they'll move based on YOUR commands and ignore the user's physical hardware. For that, I'd recommend a custom var for the visual elements to use.
Hey Warpd, thanks for the input.

So from what you tell me, there's no way to do this with XML only, not even with XML tools. That's a shame.

My goal was to indeed trap the input axis and store their value in an LVar. And then set up the sim axis position myself through XML but display the levers with the Lvar.

I need to learn how on earth you do all this with simconnect. (At least the trapping and storing in an Lvar part).
I'm guessing my 1 month deadline will be busted. :(
 
there's no way to do this with XML only, not even with XML tools.

I think your first idea that XMLKeys can do this is probably correct. Now, having said that, I have not used the XMLKeys class before so I don't have an example I can post, but reading through the documentation it looks like it's what you need.

If you study Tom Aguilo's KeysHandler.xml gauge included in the XMLTOOLS download, you'll see how he did it for the throttle = joystick slider, so you need to add the joystick prop rpm to the xml code. To figure out the controller name for the prop lever, you might use XMLEventsLogger.xml and see what shows up when you move the prop lever.

If you get it working for your own joystick and then pass the XML to someone else, will it work with their joystick? I'm guessing 'Yes', but you'll have to find out.


Bob
 
Last edited:
So from what you tell me, there's no way to do this with XML only, not even with XML tools. That's a shame.

Yes, it is possible to do with XML, using XMLTool's SIMVARS class instead onf XMLKeys.

XMLKeys is the best option but requires the #unit id as a parameter. So a sort of config tool would be necessary for users to provide their hardware info.

If a total transparent way is required, the other option is to use <On Event> to capture Axis changes and then use (C:SIMVARS:Avar Axis) to overwrite the current value with a custom one.

Tom
 
Using SimConnect, you can trap the value of AXIS_THROTTLE_SET (as one example) and block that event from reaching the core sim, sending the core sim your own modified value instead. I've done that many times with commercial training aircraft code as well as the Eaglesoft Citation X and XLS+.

So, can XMLKeys trap AXIS_THROTTLE_SET and block the sim from seeing it? The blocking part is actually important to avoid a "fight".
 
Yes. XMLKeys uses Simconnect to trap hardware events. SIMVARS also uses Simconnect, but to overwrite AVar values (those which accept that).

Tom
 
You want to intercept the AXIS_THROTTLE_SET event... use it's value to calculate your own desired throttle axis value and transmit the event to the sim with the new value. I have done this several times... the key is that you're trapping the axis, which is the joystick's input and blocking the sim from seeing that input. Then you're sending the sim the same event, with YOUR value instead.
 
Exactly. That is done with XMLKeys class in XMLTools.
The other way (which I use the most) is, in the Event Handler callback, to replace the Avar value that is returned by the axis event with your custom value using SIMVARS class. Results are pretty much the same.

Tom
 
Exactly. That is done with XMLKeys class in XMLTools.
The other way (which I use the most) is, in the Event Handler callback, to replace the Avar value that is returned by the axis event with your custom value using SIMVARS class. Results are pretty much the same.

Tom
Hi Tom!

Sorry for the late response, but I've been busy with studying my 2nd Type Rating, and my brain is a bit melted for the moment.

I tried the OnEvent code with SIMVARS as you suggested, and can manage to replace the value of the axis using Simvars.
In this snippet I make it so that 0% in the joystick corresponds to full reverse, and 100% corresponds to full power:

<On Event="AXIS_THROTTLE1_SET">
<!--Determine user power lever position!-->
(A:GENERAL ENG THROTTLE LEVER POSITION:1, percent) 100 / 120 * 20 - (>L:USERPOWERLEVER1)
<!--Set the power lever to the new range!-->
(L:USERPOWERLEVER1) (>C:SIMVARS:GENERAL ENG THROTTLE LEVER POSITION:1, percent)
</On>

I still get heavy fighting between the physical axis and the Simvar value, but I'm guessing it's simply impossible to avoid. (Unless you have a magical way of doing it?)
I'll have to see what I can do with it, because the turboprop responds fast, and thus tends to have jumpy torque and RPM, but it's already 10 times better than nothing, so thanks a lot!

Do you think it would be possible to read the controls xml of P3D in order to get the joystick ID for a given binding, so that it can be communicated to XMLKeys afterwards?
Somewhat of a far fetch, but we never know for the future. :)

Thanks all for your help.

P.S: I'll post some code snippets whenever the code is satisfactory in order to help whoever would need to design a TPE-331 in the future as a way to pay back all the help.
 
Using SimConnect you can take control of the axis and only let the sim see the values you want it to see.
Hey WarpD!

Thanks for your suggestion. The problem is I'm completely unfamiliar with SimConnect and C, C++ & C#
I'm guessing it would take me quite a lot of reading and learning in order to write that "simple" code, and with my job and everything else, I don't have too much time for it yet.
I'm quite proficient in XML, so I wanted to keep it as xml-only as possible.

I'll take a look around if I can manage to understand how to get it done, but networking has always been an arcane science to me, and SimConnect scares the bejeezus out of me.

At this rhythm, I'm seriously starting to look like you avatar!
 
Miguel,
I am just wondering if the XMLEVENTS class might be a bit quicker than a gauge <On Event=> listener ? Not tested.
One "sledgehammer" 🔨 adjustment you could make is to limit the sim frame rate to 17 or less, that way the gauge system will be faster than the visuals... haha :rotfl:.
Another thing you could do, if this is for your own use. Use a hex editor to change the interior model's A:Var responsible for the visual throttle position (if available) and rename as an L:Var - you now have complete control over the visuals.
Ex.. (A:GENERAL ENG1 THROTTLE LEVER POSITION, percent) becomes (L:GENERAL ENG1 THROTTLE LEVER POSITION, percent)

BTW, is this a MU-2? 👍

@taguilo, there's a comment / question for you in the code.
XML:
<Update>
    <!-- INITIALIZE THE XML EVENTS CLASS JUST ONCE  -->
    (G:Var1) 0 == if{
   
            <!-- THE ACTUAL XML EVENTS LISTENER -->
            'AXIS_THROTTLE1_SET' (>C:XMLEVENTS:EventName,string)
            <!-- CONVERT RAW (-16384 to 16383) INPUT TO PERCENTAGE, MODIFY & STORE -->
            '*AXIS_THROTTLE1_SET 16384 + 32767 / 120 * 20 - (>L:USERPOWERLEVER1, percent)'    
           
            <!-- @taquilo.. I am still assuming a SIMVARS class cannot be put in here? -->
            <!-- If it could... Would be the cat's meow ;) -->
           
            (>C:XMLEVENTS:EventString,string)
           
        1 (>G:Var1)
    }
    <!--SET THE POWER LEVER TO THE NEW RANGE-->
    (L:USERPOWERLEVER1, percent) (>C:SIMVARS:GENERAL ENG THROTTLE LEVER POSITION:1, percent)
</Update>
 
Last edited:
I'm doing at this way. According to Tom's description.
XML:
<!-- Initiate Joystick *** Must INI every panel load -->
      (G:Var1) 0 ==
      if{
<!-- Throttle -->
        @KeyConfig('joystick:0:Slider:0',@JoyStick)
        @KeyEnable('joystick:0:Slider:0')
<!-- Aileron -->
        @KeyConfig('joystick:0:XAxis',@JoyStick)
        @KeyEnable('joystick:0:XAxis')
<!-- Elevator -->
        @KeyConfig('joystick:0:YAxis',@JoyStick)
        @KeyEnable('joystick:0:YAxis')
<!-- Rudder -->
        @KeyConfig('joystick:0:RzAxis',@JoyStick)
        @KeyEnable('joystick:0:RzAxis')

        0 (&gt;L:CORE7X_Throttle_Sync,number)
        0 (&gt;L:CORE7X_Axis_Throttle_Set,part)

        1 (&gt;G:Var1)
        }


XML:
<!-- Throttle *** Throttle *** Throttle *** Throttle ****************************** 32784 ... 0 perc Throttle  *** 0 ... 50 perc Throttle *** -32786 ... 100 perc Throttle *** -->
      @KeyName('joystick:0:Slider:0')
      (C:XMLKEYS:KeyValue,number) (&gt;L:XMLKeys_ThrottlePosition,number)
      32768 (L:XMLKeys_ThrottlePosition,number) - 65536 / (&gt;L:CORE7X_Axis_Throttle_Set,part)

(C:XMLKEYS:KeyValue,number) give you a value from 32784 .. -32786 depending on your joystick config

(&gt;L:CORE7X_Axis_Throttle_Set,part) gives you a value from 0 .. 1.

This is used to control the engine.
Different ways of course.
 
Miguel,
I am just wondering if the XMLEVENTS class might be a bit quicker than a gauge <On Event=> listener ? Not tested.
One "sledgehammer" 🔨 adjustment you could make is to limit the sim frame rate to 17 or less, that way the gauge system will be faster than the visuals... haha :rotfl:.
Another thing you could do, if this is for your own use. Use a hex editor to change the interior model's A:Var responsible for the visual throttle position (if available) and rename as an L:Var - you now have complete control over the visuals.
Ex.. (A:GENERAL ENG1 THROTTLE LEVER POSITION, percent) becomes (L:GENERAL ENG1 THROTTLE LEVER POSITION, percent)

BTW, is this a MU-2? 👍

@taguilo, there's a comment / question for you in the code.
XML:
<Update>
    <!-- INITIALIZE THE XML EVENTS CLASS JUST ONCE  -->
    (G:Var1) 0 == if{
  
            <!-- THE ACTUAL XML EVENTS LISTENER -->
            'AXIS_THROTTLE1_SET' (>C:XMLEVENTS:EventName,string)
            <!-- CONVERT RAW (-16384 to 16383) INPUT TO PERCENTAGE, MODIFY & STORE -->
            '*AXIS_THROTTLE1_SET 16384 + 32767 / 120 * 20 - (>L:USERPOWERLEVER1, percent)'   
          
            <!-- @taquilo.. I am still assuming a SIMVARS class cannot be put in here? -->
            <!-- If it could... Would be the cat's meow ;) -->
          
            (>C:XMLEVENTS:EventString,string)
          
        1 (>G:Var1)
    }
    <!--SET THE POWER LEVER TO THE NEW RANGE-->
    (L:USERPOWERLEVER1, percent) (>C:SIMVARS:GENERAL ENG THROTTLE LEVER POSITION:1, percent)
</Update>
Hey Spokes!

Thanks for the suggestion, I tried the XML events listener you posted, but it seems it's as fast as an On-Event call, so the fighting keeps happening.

I'm doing a CASA 212 from scratch, up to study level. It's been a good 6 months of hair pulling, 4 of which has been engine behaviour...
But I might be onto something!! It'll need some testing but I must admit I danced in my underwear in the dark at 4 am when the idea came to me and the first code was promising.

It seems that the engine corrected fuel flow in P3D is affected solely by OAT (An offset to fuel flow depending on OAT). So I found that using Tom's SIMVARS, it's possible to replace the Corrected fuel flow to the engine with my own formula, which is a stable way of making the engine do whatever you want, without the fights against the throttle lever position. If you combine both methods, the engines are something around 90-95% stable, even in transitions from Flight idle to Beta to reverse, which is a BIG win.
I still need to understand how I'm going to use the RPM lever to taxi, especially in Beta, but I'm sure sleep deprivation will help me get a weird idea that will end up working. It seems this is the way of the plane maker.

I was thinking when in Beta mode associating a power lever position with a given Beta angle (like IRL), and making a PID loop that changes the RPM lever position until obtaining the desired prop Beta. While another PID takes care of maintaining fuel flow to avoid over and underspeeds. The more I think about it, the more I think I may be crazy. We'll see how it works!
 
I'm doing at this way. According to Tom's description.
XML:
<!-- Initiate Joystick *** Must INI every panel load -->
      (G:Var1) 0 ==
      if{
<!-- Throttle -->
        @KeyConfig('joystick:0:Slider:0',@JoyStick)
        @KeyEnable('joystick:0:Slider:0')
<!-- Aileron -->
        @KeyConfig('joystick:0:XAxis',@JoyStick)
        @KeyEnable('joystick:0:XAxis')
<!-- Elevator -->
        @KeyConfig('joystick:0:YAxis',@JoyStick)
        @KeyEnable('joystick:0:YAxis')
<!-- Rudder -->
        @KeyConfig('joystick:0:RzAxis',@JoyStick)
        @KeyEnable('joystick:0:RzAxis')

        0 (&gt;L:CORE7X_Throttle_Sync,number)
        0 (&gt;L:CORE7X_Axis_Throttle_Set,part)

        1 (&gt;G:Var1)
        }


XML:
<!-- Throttle *** Throttle *** Throttle *** Throttle ****************************** 32784 ... 0 perc Throttle  *** 0 ... 50 perc Throttle *** -32786 ... 100 perc Throttle *** -->
      @KeyName('joystick:0:Slider:0')
      (C:XMLKEYS:KeyValue,number) (&gt;L:XMLKeys_ThrottlePosition,number)
      32768 (L:XMLKeys_ThrottlePosition,number) - 65536 / (&gt;L:CORE7X_Axis_Throttle_Set,part)

(C:XMLKEYS:KeyValue,number) give you a value from 32784 .. -32786 depending on your joystick config

(&gt;L:CORE7X_Axis_Throttle_Set,part) gives you a value from 0 .. 1.

This is used to control the engine.
Different ways of course.
Hey Edu!

Thanks for your suggestion. My first idea was going with XMLKeys as you did, but the problem is that I intend on distributing this airplane to some friends who all have different hardware. I myself will be flying it with twin saitek throttle quadrants, rudder pedals and yoke. So it would make it a big mess if I tried using XMLKeys whilenot knowing what hardware every single person is using.

Thanks for the help, though! :)
 
Back
Top