Waugh Posted April 24, 2007 Share Posted April 24, 2007 To assist Bill in reducing pinned topic clutter, I decided that I might start this thread for techniques I might contribute. I would recommend that if someone has feedback on a tip or example that they start a separate thread to comment on it, and then Bill can make any edits to the content to make any corrections if the community finds something better, or a correction, without cluttering the thread. Thanks, Patrick. I've 'pinned' this topic and deleted the redundant ones now. I will leave this "unlocked" so you can continue to add to it, but I ask anyone else to please respect Patrick's suggestion to start a new thread if you have questions, corrections, or suggestions... Link to comment Share on other sites More sharing options...
Waugh Posted April 24, 2007 Author Share Posted April 24, 2007 The following code can be used to setup a que timer to fire every 20ms (after 1 second wait time), and execute TimerCallback(). // Que timers require Win 2000 min #define _WIN32_WINNT 0x0500 #include #include // link with winmm.lib & kernel32.lib HWND hFsWnd = NULL; HANDLE hTimer = NULL; HANDLE hTimerQueue = NULL; extern GAUGEHDR gauge_header; void CALLBACK TimerCallback( PVOID lpParameter, BOOLEAN TimerOrWaitFired ) { // Stuff you want to do every 20ms DoSomethingReallyQuickOften(); } void FSAPI module_init(void) { HRESULT hr; hFsWnd = FindWindow( L"FS98MAIN", NULL ); hTimerQueue = CreateTimerQueue(); CreateTimerQueueTimer( &hTimer, hTimerQueue, (WAITORTIMERCALLBACK)TimerCallback, NULL, 1000, // Start in 1000ms (1sec) 20, // Callback each 20ms WT_EXECUTEINTIMERTHREAD); } void FSAPI module_deinit(void) { DeleteTimerQueueTimer( NULL, hTimer, NULL ); CloseHandle( hTimer ); } Keep in mind that FS updates many things (like nav stuff) at far less than 55ms. So, as Arne has pointed out in the past, if you are trying to find derivatives, you may find that consequetive values need to be checked for no change, and averaged to be able to take a derivative. Patrick Link to comment Share on other sites More sharing options...
Waugh Posted April 24, 2007 Author Share Posted April 24, 2007 Here's a little helpful tip which you can use if you need to display the hex string of a byte in a tooltip. This can be handy to display some debugging info, if nothing else during testing. I used it to display the Direct Input key code in hex assigned dynamically to a control. In a typical MOUSE_TOOLTIP_TEXT_STRING() you can use %1!d! to display a decimal (base 10) integer, but it does not implement the 'x' format (like printf), ie you can't do %1!x! and have it display the byte in hex. (At least I haven't been able to do so) First, define a global static c-string like this: static char hexString[] = "00"; // NULL terminated Be sure to use the "" (not ''), so that it is NULL terminated. Define the following static function: static char* byteArrayToHexString(byte in) { byte ch = 0x00; int i = 0; char pseudo[] = {"0123456789ABCDEF"}; ch = (byte) (in & 0xF0); // Strip off high nibble ch = (byte) (ch >> 4); // Shift the bits down ch = (byte) (ch & 0x0F); // In case high order bit was set hexString[0] = pseudo[ (int)ch ]; // Convert nibble to hex ch = (byte) (in & 0x0F); // Strip off low nibble hexString[1] = pseudo[ (int)ch ]; // Convert nibble to hex hexString[2] = NULL; return hexString; } Now, create a TOOLTIP callback function: static PCSTRINGZ CALLBACK GetHexString(FLOAT64 number, ID id, PCSTRINGZ string, MODULE_VAR *source_var, PGAUGEHDR gauge) { byteArrayToHexString( byteToConvert ); return hexString; } The function uses a global variable (vs. new allocated memory) to avoid having to unroll the macros to insert appropriate delete [] pointer statements to avoid memory leaks. Now define an appropriate tooltip arg: MOUSE_TOOLTIP_ARGS (Dynamic_Args) MOUSE_TOOLTIP_ARG(MODULE_VAR_NONE, 1, NULL, NULL, NULL, NULL, NULL, GetAssignedKey) MOUSE_TOOLTIP_ARGS_END And the mouse tooltip string in your mouse section: MOUSE_BEGIN(gauge_rect, HELP_NONE, 0, 0) MOUSE_TOOLTIP_TEXT_STRING ("Hex: 0x%1!s!", Dynamic_Args) MOUSE_CHILD_FUNCT(0, 0, 33, 33, CURSOR_GRAB, MOUSE_LEFTSINGLE | MOUSE_LEFTRELEASE | MOUSE_DOWN_REPEAT | MOUSE_LEAVE, Gauge_mcb) MOUSE_END You may find other uses for function. Enjoy! Patrick Link to comment Share on other sites More sharing options...
Waugh Posted April 24, 2007 Author Share Posted April 24, 2007 I use this method to detect when I need to turn sounds on/off. Define some globals to capture the state of the key events you will be monitoring in your callback. bool bPauseToggle; // Globals bool bSoundToggle; Define your CALLBACK EventHandler, and toggle the state globals on each event. Note, you could use a switch statement here too, but in any case you want to minimize what you do here, and process the state changes in your gauge's gauge callback function instead for maximum performance. void CALLBACK EventHandler(ID32 event, UINT32 evdata, PVOID userdata) { if (event == KEY_PAUSE_TOGGLE) { bPauseToggle = !bPauseToggle; // User hit pause toggle } if (event == KEY_SOUND_TOGGLE) { bSoundToggle = !bSoundToggle; // User hit sound toggle } } Now, in your gauge callback, do things like so: void CALLBACK Gcb(PGAUGEHDR pgauge, SINT32 service_id, UINT32 extra_data) { switch (service_id) { case PANEL_SERVICE_PRE_INITIALIZE: register_key_event_handler((GAUGE_KEY_EVENT_HANDLER)EventHandler, 0); break; case PANEL_SERVICE_PRE_UPDATE: if ( bPauseToggle || bSoundToggle ) { PauseAudio( true ); // Your functions here } else { PauseAudio( false ); // and here. } break; case PANEL_SERVICE_PRE_KILL: unregister_key_event_handler((GAUGE_KEY_EVENT_HANDLER)EventHandler, 0); break; } } NOTE: CALLBACK is the same as FSAPI (ie __stdcall), but just more descriptive of the fact that the function is a Win32 callback requiring the __stdcall method of stack cleanup. You can use the shorter FSAPI should you desire, or even just __stdcall. Patrick Link to comment Share on other sites More sharing options...
Recommended Posts