Skip to content
View in the app

A better way to browse. Learn more.

The AVSIM Community

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Event Handler: Push and Hold

Featured Replies

  • Commercial Member

Most of you are probably aware that you can trap FS9/FSX events via an EventHandler, like this:void FSAPI EventHandler (ID32 event, UINT32 evdata, PVOID userdata) { // FS2CREW PAUSE (EVENTS AND AUDIO) if (event == KEY_PAUSE_TOGGLE) { Paused = !Paused; FS2_Audio_PauseEngine( Paused ) ; }}What I want to do, however, is use this same system to know if the user is "Pushing and Holding" a joystick/keyboard button, not just pressing it once like what happens in the Pause example above.The closest Event that I could use that I found is KEY_BRAKES.So basically if the user holds down the button assigned to the brakes, then my "isButtonHeldDown" variable will be be true.When the user releases the brakes, then "isButtonHeldDown" variable becomes false.But obviously I can't use brakes for my push and hold key because it'll cause problems when the user is taxiing.Clear as mud :( Can anyone think of a better KEY_EVENT that I could use so I can determine when the user is "Pushing and Holding" his joystick/keyboard button? Cheers,

Hi BryanI've had a think about this but I can't help. It seems that you need to intercept a keypress rather than an event and we all know what FS9 and FSX think of the keyboard.-Dai
Knowing next to nothing about how FS9.FSX handles the keyboard, would directly polling the keyboard inside a loop help?
#include <windows.h>unsigned char Keys[256];char State;  //  Start of loop  // Get keyboard state if (GetKeyboardState(Keys))    {    // Check statue of Esc key as an example    if (Keys[VK_ESCAPE] & 0x80)         State = 'D';    else       State = 'U';       } // End of loop   

EDIT: Code edited to make general C

Gerry Howard

No... it won't work.DirectX has total control of the keyboard once FS is up and running. It doesn't share it as long as FS's window has focus.
But it does work.I modified the fuel gauge that comes with the SDKs as shown in the snippet. I used the delete key because it was the first unassigned key I found. I also increased the needle's MAX_DEG_PER_SEC in MAKE_NEEDLE to 180 to speed up the response. Pressing and holding the delete key causes the displayed fuel quantity to drop to zero instantly - releasing it causes it to increase back to the actual value instantly. Try it.
FLOAT64 FSAPI fuel_needle_cb( PELEMENT_NEEDLE pelement ){FLOAT64 val = pelement->source_var.var_value.n;   //************************ FOLLOWING LINE ADDED  ***************************   unsigned char Keys[256];   if (val > GAUGE_MAX_FUEL)  val = GAUGE_MAX_FUEL;else if (val < GAUGE_MIN_FUEL)  val = GAUGE_MIN_FUEL;   // ********************  INSERTED CODE BEGINS  *****************************     // Get keyboard state   if (GetKeyboardState(Keys))     {     // If delete key pressed set val = 0     if (Keys[VK_DELETE] & 0x80)         val = 0.0;     }    // *********************  INSERTED CODE ENDS ********************************     return val;}//---------------------------------------------------------------------------// Create needle//---------------------------------------------------------------------------MAKE_NEEDLE(fuel_needle,BMP_FUEL_SMALL_NEEDLE,NULL,fuel_fail,IMAGE_USE_TRANSPARENCY|IMAGE_USE_ERASE|IMAGE_BILINEAR_COLOR,0,150, 150,6, 12,TOTAL_FUEL_QUANTITY_GALLONS,fuel_needle_cb,fuel_nonlinearity,      //  **************** DEGREES/SEC INCREASED to 180 FROM 6 *******************180 )

Gerry Howard

  • Commercial Member
I used the delete key because it was the first unassigned key I found.
That's the catch - the key has to be unassigned. FSX allows you to capture keys for a gauge - inside the gauge code - but FS9 just doesn't. As soon as you select an assigned key you get the keypress but the assigned action also takes place. I spent hours with DirectInput inside FS9 trying to override assigned key actions - failed - and realised that in general the same was likely to happen in FSX. Someone can tell me different because I haven't done the same testing on FSX.-Dai
That's the catch - the key has to be unassigned. FSX allows you to capture keys for a gauge - inside the gauge code - but FS9 just doesn't. As soon as you select an assigned key you get the keypress but the assigned action also takes place. I spent hours with DirectInput inside FS9 trying to override assigned key actions - failed - and realised that in general the same was likely to happen in FSX. Someone can tell me different because I haven't done the same testing on FSX.-Dai
We may be at cross purposes but in FSX (all I have) if the key is assigned the action associated with that key takes place as well as the specific one in the gauge. I haven't looked into how rhe assigned action can be supressed from within a gauge if that's what's needed.

Gerry Howard

Before I rush off in (totally) the wrong direction, did you try a hook?

Gerry Howard

Most of you are probably aware that you can trap FS9/FSX events via an EventHandler, like this:void FSAPI EventHandler (ID32 event, UINT32 evdata, PVOID userdata) { // FS2CREW PAUSE (EVENTS AND AUDIO) if (event == KEY_PAUSE_TOGGLE) { Paused = !Paused; FS2_Audio_PauseEngine( Paused ) ; }}What I want to do, however, is use this same system to know if the user is "Pushing and Holding" a joystick/keyboard button, not just pressing it once like what happens in the Pause example above.The closest Event that I could use that I found is KEY_BRAKES.So basically if the user holds down the button assigned to the brakes, then my "isButtonHeldDown" variable will be be true.When the user releases the brakes, then "isButtonHeldDown" variable becomes false.But obviously I can't use brakes for my push and hold key because it'll cause problems when the user is taxiing.Clear as mud :( Can anyone think of a better KEY_EVENT that I could use so I can determine when the user is "Pushing and Holding" his joystick/keyboard button? Cheers,
Hi,I can only address this from an XML-coded gauge perspective :( , but if it can be solved in XML I assume it can be done the same way in a C/C++ coded gauge as well.I suggest you have a look on how I solved a simular problem for a cannon-trigger (single trigger vs. push&hold) using the CarbHeat toggle event.File rcbsc-20.zip here in the library..Based on timing of course, of keyboard key repetition time or set controller button repetition time.As far as I can tell, the only difference between FS9 and FSX wrt. OnEvent coding (= detecting if a certain Event is given, without suppressing the execution of the Event) and OnKey coding (= true "interception" of a specific keystroke), is the following:- In FS9, OnEvent works always once the gauge is loaded.- In FSX, OnEVent works only if the window in which the gauge is defined, has focus (== is visible)- In both FS9 and FSX, OnKey works only if the window in which the gauge is defined, has focus.Where applicable, I bypass this "has focus" constraint by defining a gauge, that uses such OnEvent of OnKey code, in a transparant 2D-panel window that I keep "forced open", using Doug Dawson's WindowStatus gauge to determine the "open/closed" status of a window (with the window-ident as reference).Hope that helps .....Cheers, Rob

I've managed to intercept key messages so that they are acted on by a gauge but not passed onto Flight Simulator. I used the same simple fuel gauge mentioned in my previous post. For testing, I arranged for it to respond to the Q-key which toggles the sound on and off on my FSX setup. Pressing and holding the Q-key causes the displayed fuel quantity to drop to zero instantly - releasing it causes it to increase back to the actual value instantly but doesn't affect the sound.I used the FSX module_int() and module_deinit() functions to create and release a low-level keyboard hook respectively and added a callback function. These are shown in the following snippet together with the additional variables needed. All this appears in the file before the line:int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)

//---------------------------------------------------------------------------// ************ ADDITIONAL CODE FOR HOOK BEGINS HERE  ***********************//---------------------------------------------------------------------------// Variables for hookHHOOK MyHook;unsigned Q_KeyDown;// Callback function for hookLRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); //---------------------------------------------------------------------------// FS initialisation function//---------------------------------------------------------------------------void FSAPI module_init(void){// Create hook // NOTE: Low level hook needs a handle to a module even though it doesn't// then use it! LoadLibrary("user32.dll") provides one. user32.dll is generally// availableMyHook = SetWindowsHookEx(WH_KEYBOARD_LL,                          (HOOKPROC)KeyboardProc,                          LoadLibrary("user32.dll"),                          0);};//---------------------------------------------------------------------------// FS deinitialisation function//---------------------------------------------------------------------------void FSAPI module_deinit(void){// Release hookUnhookWindowsHookEx(MyHook);};//---------------------------------------------------------------------------// Keyboard callback procedure//---------------------------------------------------------------------------LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {PKBDLLHOOKSTRUCT hookstruct;hookstruct = (PKBDLLHOOKSTRUCT) lParam;// Ignore Q key (VK code 0x51)if(hookstruct->vkCode == 0x51)   {   if (wParam == WM_KEYDOWN)      Q_KeyDown = 1;   if (wParam == WM_KEYUP)      Q_KeyDown = 0;            return 1;   }else   return CallNextHookEx(NULL, nCode, wParam, lParam);}//---------------------------------------------------------------------------// ************ ADDITIONAL CODE FOR HOOK ENDS HERE ************************//--------------------------------------------------------------------------- 

The change to the function FLOAT64 FSAPI fuel_needle_cb( PELEMENT_NEEDLE pelement ) is even simpler than before

FLOAT64 FSAPI fuel_needle_cb( PELEMENT_NEEDLE pelement ) { FLOAT64 val = pelement->source_var.var_value.n; if (val > GAUGE_MAX_FUEL)   val = GAUGE_MAX_FUEL; else if (val < GAUGE_MIN_FUEL)   val = GAUGE_MIN_FUEL; //---------------------------------------------------------------------------// ********************* ADDITIONAL CODE BEGINS HERE ************************//---------------------------------------------------------------------------// If hooked key pressed set val = 0   if (Q_KeyDown)   {   val = 0.0;   }      //---------------------------------------------------------------------------// ********************** ADDITIONAL CODE ENDS HERE *************************//---------------------------------------------------------------------------      return val; }  

It's also necessary to add the following line at the top of that file

extern unsigned Q_KeyDown;

I've tested this using the default C172 on FSX + Acceleration running on XP Professional SP3. One snag is that while FSX is running, the Q-key in any other application is intercepted and so that other applicaton doesn't respond to it either. In principle, this approach should be able to handle multiple keys by adding to the callback function and providing additional variables corresponding to Q_KeyDown.

Gerry Howard

I hope I've now fixed the snag so that the Q_key is not intercepted in other applications. It now gets the process ID on initialisation which is FS. The callback function now gets the current process ID every time it's called and only intercepts the key if the two process IDs are the same.I've only tested it by having Notepad open at the same time as FSX so any feedback would be welcome. The changes in the snippet are marked by - NEW:

//---------------------------------------------------------------------------// ************ ADDITIONAL CODE FOR HOOK BEGINS HERE  ***********************//---------------------------------------------------------------------------// Variables for hookHHOOK MyHook;unsigned Q_KeyDown;// Handles of windows - NEWHWND CurrentWindow;HWND InitialWindow;// ID's of processes - NEW   				DWORD CurrentProcess;DWORD InitialProcess;// Callback function for hookLRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); //---------------------------------------------------------------------------// FS initialisation function//---------------------------------------------------------------------------void FSAPI	module_init(void){// Create hook // NOTE: Low level hook needs a handle to a module even though it doesn't// then use it! LoadLibrary("user32.dll") provides one. user32.dll is generally// availableMyHook = SetWindowsHookEx(WH_KEYBOARD_LL,                      	(HOOKPROC)KeyboardProc,                      	LoadLibrary("user32.dll"),                      	0);                      	 // Get process ID when hook is set (ie FS) - NEWInitialWindow = GetForegroundWindow();GetWindowThreadProcessId(InitialWindow, &InitialProcess); };//---------------------------------------------------------------------------// FS deinitialisation function//---------------------------------------------------------------------------void FSAPI	module_deinit(void){// Release hookUnhookWindowsHookEx(MyHook);};//---------------------------------------------------------------------------// Keyboard callback procedure//---------------------------------------------------------------------------LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {PKBDLLHOOKSTRUCT hookstruct;hookstruct = (PKBDLLHOOKSTRUCT) lParam;// Get process ID of calling process - NEWCurrentWindow = GetForegroundWindow();GetWindowThreadProcessId(CurrentWindow, &CurrentProcess); // Only intercept if from original (FS) process - NEWif (CurrentProcess == InitialProcess)  	{   	// Ignore Q key  	if(hookstruct->vkCode == 0x51) 		{ 		if (wParam == WM_KEYDOWN)        	Q_KeyDown = 1; 		if (wParam == WM_KEYUP)        	Q_KeyDown = 0;     	    	return 1; 		}  	else 		return CallNextHookEx(NULL, nCode, wParam, lParam);    	}   	else   return CallNextHookEx(NULL, nCode, wParam, lParam);   	}//---------------------------------------------------------------------------// ************ ADDITIONAL CODE FOR HOOK ENDS HERE ************************//--------------------------------------------------------------------------- 

Gerry Howard

  • Author
  • Commercial Member
Hi,I can only address this from an XML-coded gauge perspective :( , but if it can be solved in XML I assume it can be done the same way in a C/C++ coded gauge as well.I suggest you have a look on how I solved a simular problem for a cannon-trigger (single trigger vs. push&hold) using the CarbHeat toggle event.File rcbsc-20.zip here in the library..Based on timing of course, of keyboard key repetition time or set controller button repetition time.As far as I can tell, the only difference between FS9 and FSX wrt. OnEvent coding (= detecting if a certain Event is given, without suppressing the execution of the Event) and OnKey coding (= true "interception" of a specific keystroke), is the following:- In FS9, OnEvent works always once the gauge is loaded.- In FSX, OnEVent works only if the window in which the gauge is defined, has focus (== is visible)- In both FS9 and FSX, OnKey works only if the window in which the gauge is defined, has focus.Where applicable, I bypass this "has focus" constraint by defining a gauge, that uses such OnEvent of OnKey code, in a transparant 2D-panel window that I keep "forced open", using Doug Dawson's WindowStatus gauge to determine the "open/closed" status of a window (with the window-ident as reference).Hope that helps .....Cheers, Rob
Thanks Rob, I'll check that out :Big Grin:I'm wondering if when you 'push and hold' the trigger, is the 'push and hold' value always 'true' in a totally unbroken way? Or is 'true' for, say, a second, then it's false for a fraction of second after 'repeat' runs its course, then it goes back to 'true'.I'm curious because what I need is a 'clean' totally uninterrupted, even for a micro second, value for push to hold.Clear as mud?

Create an account or sign in to comment

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.