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

Problem with FSX Custom Event

Messages
28
Country
monaco
Hello,

I try to coordinate 2D and 3D panels using custom events.

1) In gauges.h I have declared the new events:

// Third parties can use custom events in this range to communicate between 3D VC's and 2D C++ gauges.
#define THIRD_PARTY_EVENT_ID_MIN 0x00011000
#define THIRD_PARTY_EVENT_ID_MAX 0x0001FFFF

// Third party events
const int KEY_PHI_MODE_INC = 0x11000; //THIRD_PARTY_EVENT_ID_MIN
const int KEY_PHI_MODE_DEC = 0x11001;

2) I have an EventHandler in my sub-gauge :

// GAUGE_KEY_EVENT_HANDLER
static void FSAPI EventHandler(ID32 event, UINT32 evdata, PVOID userdata)
{
switch(event)
{

case KEY_NULL :
break;

case KEY_PHI_MODE_INC:
HomingState++;
if(HomingState>4)
HomingState=0;
break;

case KEY_PHI_MODE_DEC:
HomingState--;
if(HomingState<0)
HomingState=4;
break;

default:
break;
}
}
These 2 events increase/decrease by step of Homingstate (SINT32 variable) a rotactor to set its position (0 to 4)

3) I Have registered and unregistered this EventHandler in mysub-gauge callback :

static void FSAPI gauge_cb( PGAUGEHDR pgauge, int service_id, UINT32 extra_data )
{
switch(service_id)
{
case PANEL_SERVICE_CONNECT_TO_WINDOW:
{
register_key_event_handler((GAUGE_KEY_EVENT_HANDLE R) EventHandler, NULL);
break;
}

case PANEL_SERVICE_PRE_INSTALL:
break;


case PANEL_SERVICE_PRE_UPDATE:
........
break;

case PANEL_SERVICE_DISCONNECT:
{
unregister_key_event_handler((GAUGE_KEY_EVENT_HAND LER) EventHandler, NULL);
break;
}


case PANEL_SERVICE_PRE_KILL:

break;
}
}

4) I call the events with 2 mouse callbacks and update the 3D corresponding element

static BOOL FSAPI switch_inc_cb( PPIXPOINT relative_point, FLAGS32 mouse_flags )
{
trigger_key_event(KEY_PHI_MODE_INC,0);
set_named_variable_value(phi_mode_id,HomingState);
return FALSE;
}

Everything works well except that the increasing step for Homingstate var is 2 and not 1.
If I don't use the eventHandler but the mouse callback completed with
HomingState++;
if(HomingState>4)
HomingState=0;
I get a step of 1.

Any explanation to this and how can I have a step of 1 using the EventHandler to enable me to coordinate the 2 cockpits ?

Thank for the help
Jean-Pierre
 
Your code doesn't look wrong at first sight, although you are using a different approach than what is usually done, because you are triggering the custom even from the C++ Gauge, but generally this method is used by triggering the custom event in the modeldef.xml, this way:

Code:
<MouseRect>
    <Cursor>Hand</Cursor>
    <MouseFlags>LeftSingle</MouseFlags>
    <EventID>0x00011000</EventID>
</MouseRect>

Or like this, for inc/dec in the same code

Code:
<MouseFlags>LeftSingle+LeftDrag+Wheel</MouseFlags>
<CallbackJumpDragging>
    <XMovement>
        <Delta>20</Delta>
        <EventIdInc>0x0001101A</EventIdInc>
        <EventIdDec>0x0001101B</EventIdDec>
    </XMovement>
</CallbackJumpDragging>
</MouseRect>

I really never tried triggering a custom even from the C++ code. Looking at your description of the problem, it seems it works, but the "inc" event gets fired twice.

Have you tried running in the debugger, using breakpoints to check what's going on ?

Another suggestion, DO NOT use the Gauge Callback PANEL_SERVICE_CONNECT_TO_WINDOW and PANEL_SERVICE_DISCONNECT as a way to initialize code, this always lead to potential problems, because you are not certain that callback is called until that gauge is actually loaded by opening the panel that contains it or by going to the VC (if the gauge is also instantiated in the VC). Also, if you have multiple instances of that Gauge (for example, in the 2D panel and in the VC) that code is executed twice, one for each instance so, you would have to revert to ugly code hacks to check if you have initialialized yourself or not, like adding another variable, etc.

Instead, the correct and clean way to do this, is to use module_init() and module_deinit() calls. They are guaranteed to be executed only ONCE when the AIRPLANE loads/unloads, provided the main .GAU file is present in at least one panel (or the VC), but they are at the main gauge level so, you are sure only one version exists, unlike the Gauge Callbacks, which have multiple instances, one for each time the relevant Sub-Gauge is referenced in the panel.cfg

Have a look at this post:

http://www.fsdeveloper.com/forum/showpost.php?p=134452&postcount=10

There's an explanation how to use module_init() and module_deinit()
 
Last edited:
Hello Umberto,

Sorry to say that I am a beginner in C++. I just understand the basics of the FS SDK but I never made a custom event code. I am a

self made programmer with the help of some experts when I can get it.

I don't know how to use the debugger. If you can let me know what to do I would be very gratefull.
In the BUILD menu I choosed

Start Debug, To... but I have no executable files, only my .cpp files.

I also don't know how to use module_init() and module_deinit() calls. Iwill try to understand through your pecified post and let you know.

Thanks Umberto
Regards
Jean-Pierre
 
Hello Umberto,

You said : "provided the main .GAU file is present in at least one panel (or the VC)"
What do you mean in the panel.cfg. I only have sub-gauges declared as :
gaugeXX = Main_gauge!subgauge1, xxx, yyy, www, hhh

Regards
Jean-Pierre
 
That's fine, as long as you have at least 1 sub-gauge referenced, this will trigger the whole main gauge to be loaded and, on first load, the module_init() will be called, and it will never be called again even if you have several panels with different instances of the same gauge and even if you have a VC as well.

Of course, if you have two different main gauges, like this:

gaugeXX = Main_gauge1!subgauge1, xxx, yyy, www, hhh
gaugeXX = Main_gauge1!subgauge2, xxx, yyy, www, hhh
gaugeXX = Main_gauge2!subgauge1, xxx, yyy, www, hhh
gaugeXX = Main_gauge2!subgauge2, xxx, yyy, www, hhh

Both module_init() will be called, one for Main_gauge1 and another one for Main_gauge2

When you select another airplane, module_deinit() will be called just before loading the new airplane.
 
Hello Umberto,

I have tried to modify my main gauge so that it looks like your sample. The EventHandler is not anymore in my subgauge but in the main gauge where I have the following code:

// Etendard4M.cpp

#include "gauges.h"

SINT32 HomingState = 0;

// Subgauges

#include "Radio_COM\Etd4_Radio_COM.h"
#include "Radios_NAV\Etd4_Radio_NAV1.h"
......

// (no more static)
void FSAPI EventHandler(ID32 event, UINT32 evdata, PVOID userdata)
{
switch(event)
{
case KEY_NULL :
{
break;
}

case KEY_PHI_MODE_INC:
{
HomingState++;
if(HomingState>4)
HomingState=0;
break;
}

case KEY_PHI_MODE_DEC:
{
HomingState--;
if(HomingState<0)
HomingState=4;
break;
}


default:
break;
}

}
//-----------------------------------------------------------------------
// Based on FSDevelopper explanations and Cabin_Comfort sample

BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
{
return TRUE;
}

void FSAPI module_init(void)
{
register_key_event_handler((GAUGE_KEY_EVENT_HANDLER) EventHandler, NULL);
}


void FSAPI module_deinit(void)
{
unregister_key_event_handler((GAUGE_KEY_EVENT_HANDLER) EventHandler, NULL);
}

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


// This is the module's export table, the GAUGE TABLE

GAUGESLINKAGE Linkage =
{
0x00000013,
module_init,
module_deinit,
0,
0,
FS9LINK_VERSION,
{

&gaugehdr_Radio_COM,
&gaugehdr_Radio_NAV1,
.........
0 // <=== Ne pas oublier le 0
}
};
Is that code OK ?

The 2 events increase/decrease by step of Homingstate (SINT32 variable) a rotactor to set its position (0 to 4) are still called in the subgauge.

Unfortunately, now, the rotactor does not turn nor receive the event when I clic on it.

Thanks for the help
Jean-Pierre
 
Sorry, it's just too confusing to have a look at your code, without having the whole project to check. It doesn't "look" wrong (apart from obvious syntax errors, but they are only in the forum post because it wouldn't compile otherwise...), but such bug can't be checked without having a look at the whole project.

As I've said, you should really learn how to use the Visual Studio debugger, so you can check the flow of your code, put breakpoints, check variables values at any stage, check which routines are called, etc.

Programming gauges in C++ (or anything else, in C++, or in any other language, btw...) it's basically impossible without a debugger and knowing how to use it.
 
Err... It's been impossible to attach a debugger to FS for quite some time. I really wouldn't recommend trying to use it out of FS, just in Visual Studio, either, as obviously it's not running inside the right environment, and there's no way of seeing the end result.
 
Err... It's been impossible to attach a debugger to FS for quite some time.

Absolutely not true: I've been happily running FS under the VS debuggers for years, and I couldn't imagine programming anything but the simplest things, without them.

To debug FS9, a nocd patch was required, but that's not a problem in FSX, which runs straight way under a debugger.

Note that, you might have *another* 3rd party module installed, which might block the debugger, but I assure you that debugging plain standard FSX doesn't have any issue, at all.
 
There are several requirements:

1. both VS and FSXmust be on the same computer
2. computer must be able to run VS and FS at the same time
3. VS should be set for "Debug" and not "Release"

Starting a Debug session is as simple as pressing F5, or clicking via the menu Debug/Start Debugging.

The first time you will have to point to fs9.exe or fsx.exe in the dialog.
 
Your code doesn't look wrong at first sight, although you are using a different approach than what is usually done, because you are triggering the custom even from the C++ Gauge, but generally this method is used by triggering the custom event in the modeldef.xml, this way:

Code:
<MouseRect>
    <Cursor>Hand</Cursor>
    <MouseFlags>LeftSingle</MouseFlags>
    <EventID>0x00011000</EventID>
</MouseRect>

Or like this, for inc/dec in the same code

Code:
<MouseFlags>LeftSingle+LeftDrag+Wheel</MouseFlags>
<CallbackJumpDragging>
    <XMovement>
        <Delta>20</Delta>
        <EventIdInc>0x0001101A</EventIdInc>
        <EventIdDec>0x0001101B</EventIdDec>
    </XMovement>
</CallbackJumpDragging>
</MouseRect>

Hi!
Many thanks for your help! I'm working with Jean-Pierre, and I'm in charge of the 3D model. I have a question for about the Virtuali's Modeldef.xml code.
I'm already using these samples for the 3D animations, but I'm wondering if, when using custom events, it's possible to have both mouse clicks and wheel working?
I coded the Inc/Dec sample on a rotating button, the mouse wheel is working fine, but not the left click, and the right one only times to times??

Is there a way to fire custom event into a structure like that:
(M:Event) 'LeftSingle' scmp 0 ==
if{...}
(M:Event) 'RightSingle' scmp 0 ==
if{...}

Regards,
Sylvain
 
Is there a way to fire custom event into a structure like that:
(M:Event) 'LeftSingle' scmp 0 ==
if{...}
(M:Event) 'RightSingle' scmp 0 ==
if{...}

I think yes, you should be able to put a

(>K:0x00011000)

event inside your mouse event
 
Hi!
It doesn't work ...
It seems that K: command needs a Event name to work and not a Event id like "0X00011000" or "KEY_THROTTLE_FULL"...
I don't know how I will manage to rotate my knob in both directions...
:confused:

Regards
Sylvain
 
In the multigauge, you declare a callback :

BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
{
return TRUE;
}

What is the use of this callback ? Is it the equivalent for the multigauge of the gauge callback for the subgauges ?
 
In the multigauge, you declare a callback :

BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
{
return TRUE;
}

What is the use of this callback ?

Every Windows .DLL has this callback. A Gauge file is a regular Windows .DLL so, it has to have this call. It might be used for some initalization like, for example, storing the handle to "yourself" ( HINSTANCE hDLL), in a variable, in case you'll need to call any Windows API function that needs it, later on.

Every Gauge you compile with the Gauges SDK always had a DLLMain, it's just that is explicitely defined in this code because, in order to get access to the module_init() and module_deinit() function, the GAUGE_TABLE_BEGIN macro hasn't been used so, you need to replicate what the macro does. If you check the macro definition in GAUGES.H, you'll see that DLLMain and the module_init() and module_deinit() are there.

Sometimes, using macros can be deceiving, because you don't fully understand what your program is doing.
 
First thing : I finally found what blocked the code I submit you about the multigauge code. I forgot to include the file with all the common variables used in the multigauge. Now it works and I can have custom events for 2D and 3D panels.

Second : In the DllMain callback, can i use:

switch (service_id)
{
case PANEL_SERVICE_CONNECT_TO_WINDOW:

break;

case PANEL_SERVICE_PRE_UPDATE:

break;

case PANEL_SERVICE_DISCONNECT:
break;
}
 
I forgot to include the file with all the common variables used in the multigauge. Now it works and I can have custom events for 2D and 3D panels.

I was quite sure it was something like that...

Second : In the DllMain callback, can i use:

No, because DllMain is not a callback routine that is constantly updated, it's executed only once when the gauge is loaded.

It's best if you don't do anything inside DLLMain (except, perhaps, storing the handle to the gauge, in case you'll need it later) and use module_init() and module_deinit() for initializazion.

However, you will not use the same method as the gauge callback with a switch (service_id) , because there's no callback here and no service_id, which is a parameter that is passed only in the callback. And, again, even the module_init() and module_deinit() are only called once.

So, you put inside module_() the same commands you would otherwise put inside the "case" statement related to PANEL_SERVICE_CONNECT_TO_WINDOW, and put in module_deinit() what you would had in the PANEL_SERVICE_DISCONNECT case.

What's inside PANEL_SERVICE_PRE_UPDATE, must still be inside a regular callback gauge call. And, this is not even certain. It depends WHAT you want to update. If you use the PANEL_SERVICE_PRE_UPDATE as a way to update something related to that specific gauge, than it's ok having the code there.

But, if you are using it to update something else, like any of your own custom variables that are related to your simulation and not specific to gauge updating or drawing, the correct way would be using Simconnect to subscribe to a system event (it can be once per second, every 4 seconds, 6 times per second or even every frame), and than having just ONE general callback (the Simconnect dispatch procedure) at the main gauge level, not a callback for every gauge.
 
No, because DllMain is not a callback routine that is constantly updated, it's executed only once when the gauge is loaded.

I don't use SimConnect at all (I've had no need for it yet), so instead I do use service_id's in the dllMain. In fact, I do all my lookups in dllMain's PRE_UPDATE case.

I have one gauge that is common to both the 2d and vc panels, and have an explicit callback to dllMain.
 
Back
Top