• 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.

FSXA [Fixed]Joystick throttle intercept gauge

Kekelekou

Resource contributor
Messages
226
Country
france
Hello everyone,


I am working on my first C++ gauge, which will be supposed to intercept throttle movements from the joystick and pass the intercepted value to an XML L:var:

http://www.fsdeveloper.com/forum/threads/simconnect-dll-declared-as-gau-in-panel-cfg.441418/

I am studying the SDK and the few samples in the resource section of FSDeveloper.

I have noticed that the invisible gauges do display see-through strings or textures, even thought they are not supposed to draw anything on screen.

Does this mean that at least one “element” has to be drawn so that the gauge works properly? If so, is one pure black background bmp enough? Is there a minimum pixel size for this file?

Same question with mouserects : is it possible to get rid of them altogether, or one must be included?

Thanks!
 
You do need to include at least one "visible" static image. It can however be a pure RGB(0,0,0) bitmap that will be treated as transparent by the sim.
You can supply a NULL pointer for the mouse rect in the gauge header declaration.
Here is what the "visible" element looks like in my fuel dump gauge:
Code:
char FuelDumpGaugeName[]  = GAUGE_NAME;
extern PELEMENT_HEADER   FuelDumpList;

GAUGE_HEADER_FS800(GAUGEHDR_VAR_NAME, GAUGE_W, FuelDumpGaugeName, &FuelDumpList, NULL, NULL, 0, 0);

MAKE_STATIC(DumpStatic,SmallBitmap,NULL,NULL ,IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT7 | IMAGE_USE_LUMINOUS,0,0,0)
PELEMENT_HEADER FuelDumpList = &DumpStatic.header;
 
Thank you to both of you for your help.
JB3DG (how do you pronounce that btw?) : I was referring to this very template! Could you please confirm that all "connexions" between files (declarations and inclusions) are all done? The links between files are something I'm struggling with, so that if the template has this sorted out, I'll be much relieved.
 
--- Code updated 11/23/2017, 9am ---

Well, here am I so far. I have decided to gather almost all code into one cpp file, so that I don't mess up with the connections/inclusions.

IMPGauge.cpp :

Code:
#include "gauges.h"
#include "SimConnect.h"
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>

#include "IMPGauge.h"

CALLBACK MyDispatchProcDLL;

HRESULT hr = NULL;
HANDLE  hSimConnect = NULL;

int Eng1_ThrPos = 0;
int Eng2_ThrPos = 0;

int Eng1_ThrMod = 0;
int Eng2_ThrMod = 0;

ID Eng1_ThrPos_ID;
ID Eng2_ThrPos_ID;

static enum GROUP_ID {
    GROUP_Thr,
};

static enum EVENT_ID {
    EVENT_Thr1,
   EVENT_Thr2,
};


/////////////////////////////////////////////////////////////////////////////
// IMPGauge Declaration
/////////////////////////////////////////////////////////////////////////////

#define     GAUGE_NAME          "IMPGauge"
#define     GAUGEHDR_VAR_NAME   gaugehdr_IMPGauge
#define       GAUGE_H               100
#define     GAUGE_W               100


char imp_gauge_name[]   = GAUGE_NAME;
extern PELEMENT_HEADER gaugeimp_element_list;
GAUGE_CALLBACK cxmlinterface;

GAUGE_HEADER_FS700(GAUGE_W, imp_gauge_name, &gaugeimp_element_list, NULL, cxmlinterface, 0, 0, 0);

MAKE_STATIC(gaugeimp_image,BMP_BACKGROUND,NULL,NULL ,IMAGE_USE_ERASE | IMAGE_USE_TRANSPARENCY | BIT7 | IMAGE_USE_LUMINOUS,0,0,0);

PELEMENT_HEADER       gaugeimp_element_list   = &gaugeimp_image.header;


#undef GAUGE_NAME
#undef GAUGEHDR_VAR_NAME
#undef GAUGE_H
#undef GAUGE_W


/////////////////////////////////////////////////////////////////////////////
// Gauge table entries
/////////////////////////////////////////////////////////////////////////////

void FSAPI module_init(void);
void FSAPI module_deinit(void);


GAUGESIMPORT ImportTable = {
   { 0x0000000F, (PPANELS)NULL },
   { 0x00000000, NULL }
};

GAUGESLINKAGE Linkage =
{
   0x00000013,
   module_init,
   module_deinit,
   0,
   0,
   FS9LINK_VERSION,
   {
       &gaugehdr_IMPGauge,
       0
   }
};


/////////////////////////////////////////////////////////////////////////////
//  Callback collecting joystick inputs
/////////////////////////////////////////////////////////////////////////////

void CALLBACK MyDispatchProcDLL(SIMCONNECT_RECV* pData, DWORD cbData, void *pContext)
{
 
    switch(pData->dwID)
    {
        case SIMCONNECT_RECV_ID_EVENT:
        {
            SIMCONNECT_RECV_EVENT *evt = (SIMCONNECT_RECV_EVENT*)pData;

            switch(evt->uEventID)
            {
                case EVENT_Thr1:
                   Eng1_ThrPos = (int)evt->dwData;
                   Eng1_ThrMod = 1
               
               case EVENT_Thr2:
                  Eng2_ThrPos = (int)evt->dwData;
                   Eng2_ThrMod = 1

                default:
                    break;
            }
            break;
        }
   
       case SIMCONNECT_RECV_ID_EXCEPTION:
           {
               SIMCONNECT_RECV_EXCEPTION* except = (SIMCONNECT_RECV_EXCEPTION*) pData;
               switch( except->dwException )
               {
               case 0:
                   break;
               default:
                   break;
               }
           }

        default:
            break;
    }
}

/////////////////////////////////////////////////////////////////////////////
//  Gauge DLL Implementation and group definition
/////////////////////////////////////////////////////////////////////////////

void FSAPI module_init(void)
{

   hr = SimConnect_Open(&hSimConnect, ("IMPGauge"), NULL, 0, 0, 0);

   if( hr == S_OK )
   {
       printf("\n IMP Gauge Connected...");
   
       hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_Thr1, "AXIS_THROTTLE1_SET");

        hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUP_Thr, EVENT_Thr1, true);
   
       hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_Thr2, "AXIS_THROTTLE2_SET");

        hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUP_Thr, EVENT_Thr2, true);

        hr = SimConnect_SetNotificationGroupPriority(hSimConnect, GROUP_Thr, SIMCONNECT_GROUP_PRIORITY_HIGHEST_MASKABLE);

   
       hr = SimConnect_CallDispatch(hSimConnect, MyDispatchProcDLL, NULL);
   }
}

void FSAPI module_deinit(void)
{
   hr = SimConnect_Close(hSimConnect);
};

/////////////////////////////////////////////////////////////////////////////
//  DLL C XML Interface
/////////////////////////////////////////////////////////////////////////////

void FSAPI cxmlinterface(PGAUGEHDR pgauge, SINT32 service_id, UINT32 extra_data )
{
   switch(service_id)
   {
   
   case PANEL_SERVICE_PRE_INITIALIZE:
           register_named_variable("Eng1_ThrLeverPos");
           register_named_variable("Eng2_ThrLeverPos");
           break;
   
   case PANEL_SERVICE_PRE_UPDATE:
           Eng1_ThrPos_ID = check_named_variable ("Eng1_ThrLeverPos");
           if (Eng1_ThrMod == 1)
           {
               set_named_variable_value(Eng1_ThrPos_ID,(FLOAT64)Eng1_ThrPos );
               Eng1_ThrMod = 0;
           }
       
           Eng2_ThrPos_ID = check_named_variable("Eng2_ThrLeverPos");
           if (Eng2_ThrMod == 1)
           {
               set_named_variable_value(Eng2_ThrPos_ID,(FLOAT64)Eng2_ThrPos );
               Eng2_ThrMod = 0;
           }
           break;
 
   default:
            break;

   }
}

IMPGauge.h :

Code:
#define         VERSION_MAJOR           1
#define         VERSION_MINOR           0
#define         VERSION_BUILD           0

// magic to get the preprocessor to do what we want
#define       lita(arg) #arg
#define       xlita(arg) lita(arg)
#define       cat3(w,x,z) w##.##x##.##z##\000
#define       xcat3(w,x,z) cat3(w,x,z)
#define       VERSION_STRING xlita(xcat3(VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD))

#ifndef       VS_VERSION_INFO
#define       VS_VERSION_INFO       0x0001
#endif

#define       BMP_BACKGROUND       0x1000

IMPGauge.rc :

Code:
// IMPGaugeRes.rc

#include "IMPGauge.h"

/////////////////////////////////////////////////////////////////////////////
//
// Version
//

VS_VERSION_INFO VERSIONINFO
 FILEVERSION VERSION_MAJOR,VERSION_MINOR,0,VERSION_BUILD
 PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,0,VERSION_BUILD
 FILEFLAGSMASK 0x3fL
 FILEFLAGS 0x0L
 FILEOS 0x10004L
 FILETYPE 0x1L
 FILESUBTYPE 0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904b0"
        BEGIN
            VALUE "CompanyName", "Kekelesims\0"
            VALUE "FileDescription", "Freeware Joystick Throttle Interceptor\0"
            VALUE "FileVersion", VERSION_STRING
           VALUE "Copyright " , "2017 Rémi -Kekelekou-\0"
            VALUE "LegalCopyright", "Rémi -Kekelekou-\0"
           VALUE "OriginalFileName" , "IMPGauge.gau\0"
        END
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x409, 1200
    END
END


BMP_BACKGROUND           BITMAP           "res\\gauge_background.bmp"

and IMPGauge.def :

Code:
LIBRARY "IMPGauge"
EXPORTS
module_init
module_deinit

Can't wait for hours of fun with the debug marathon
 
Last edited:
You don't need to use SetInputGroupSate with a sim event. Only for raw hardware events that have been set up using MapInputEventToClientEvent.
 
JB3DG : I have deleted the line, thank you for the tip!
kalong and all :
I have created the project with VC++ 2010 Express from scratch and from the GDI+ template (thanks kalong), but I end up with errors 2065: undeclared identifier for 'hr', 'MyDispatchProDLL' and 'dwData' everytime I try to compile.
It looks like SimConnect.h /gauges.h are not read, while they are declared proprely in the cpp and the project :

38554706242_0594f8701a_b.jpg


I am pretty puzzled, but I fear the error 101 : 'newbie programmer detected'...
 
gauges.h includes a reference to windows.h, so I would go with:
Code:
#include "gauges.h"
#include "SimConnect.h"
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>

void CALLBACK MyDispatchProDLL(SIMCONNECT_RECV* pData, DWORD cbData, void *pContext);
DWORD dwData = 0;

I see that hr is declared, so one would hope that removing the repeated inclusion of windows.h and the declaration of dwData and MyDispatchProDLL will solve the problems.

Edit:
add semi-colon at end of function declaration
 
Well I'm glad to thank you once again Doug.
I have noticed a typo Proc/Pro with MyDispatchProcDLL, and inverted the "DLL implementation" and "Callback collecting..." sections so that the "void CALLBACK MyDispatchProcDLL..." line shows up before MyDispatchProcDLL is called.
dwData was just the middleman in rethrieving the joystick position, so I got rid of it by writing : "Eng1_ThrPos = (int)evt->dwData".

The last error I get at compiling involves IMPGauge.rc Error C2059 : syntax error : 'constant' on line 10
Code:
VS_VERSION_INFO VERSIONINFO
I suspected another typo, so I gave it a try with the rc file from your fuel gauge, but no joy. Same error, same line.

Update : I have commented out several parts of the rc file (except the #include and the BMP_BACKGROUND line), the error shifts to the first uncommented line with the exact same error description.
 
Last edited:
Well well well...
I got tired of trying to fix the compiler error yesterday evening, so I started again from the blank invisible system template by JB3DG as suggested by kalong.
A few copy-pastes later, I could witness a working gauge in FSX, pretty much to my own bewildement. 1st C++ gauge done.
I’d like to thank Doug, JB3DG, Simon853 and kalong for your help, as well as all contributors to FSDeveloper’ s forum and resource site.
I’ll post the source code here when it has been tidied up.

Now back to the Damage Mod.
 
Doug... you don't need a bitmap in the static_image. I've been using the following liberally for years now.

MAKE_STATIC(systems_handler_static,
NULL,
NULL,
NULL,
IMAGE_USE_ERASE,
0,
0, 0)
PELEMENT_HEADER systems_handler_list = &systems_handler_static.header;


It looks like you don't even need the bitmap flags, but I've only done a quick test on that just now. Everything appeared to work.

MAKE_STATIC(systems_handler_static,
NULL,
NULL,
NULL,
NULL,
0,
0, 0)
PELEMENT_HEADER systems_handler_list = &systems_handler_static.header;
 
Thanks for the head-up DragonflightDesign!
So, I suppose that you just declare no bitmap in the .rc and .h files and you are done.
 
Back
Top