Jump to content

TARGET - Advanced programming


ivanwfr

Recommended Posts

Glad it is working for you. The example is a simplified version of my template which I use for new files, so I left stuff in like the LEDs and such in case it was useful. I do VR now too so LEDs and printf statements are mostly for debug now.

 

Yes good point that the Pilot function can have 100% of all commands and call it first as the default, and the RIO function just has the changes specific to the RIO. You were talking about .ttm files which it is OK to break them up as well. You just have to include both .ttm files. But include files are universal, just be aware. You can't include a .ttm file and have it only be active for only one function.

 

Anyway, as I was saying, you can also make the Pilot and RIO functions complete by themselves, or just make the RIO function add on or modify commands from the pilot function but call the pilot function to set the base config, which makes it easier to manage them or make them separate .tmc files one day if desired. You get the idea and the rest is just personal preference how you want to do it.

Link to comment
Share on other sites

So I made my 2 macro files, but I get a compile error when I try to use a marco in the function.

Compile [b]Error[/b]:Define stack full in F14B_Unified_Cockpit.tmc at line 94

It works fine if I put a direct key command in like:

MapKey(&Joystick[color=#ffffff],[/color]S1, [b]"5"[/b]);

But the second I use a macro I get the error.

MapKey(&Joystick[color=#ffffff],[/color]S1, [b]Recenter_VR_Headset[/b]);

Edit:

Further testing revealed that errors are reported when I use both the pilot and RIO .ttm's. If I use one or the other , but not both, the .tmc works fine.

Looks like I'm just gonna have to go through them line by line.

Any thoughts on what I should be looking for?

 

 

Got it working just fine.

It's just a matter of making sure there are no duplicate Macro defines.


Edited by SGT Coyle
Further Testing

Night Ops in the Harrier

IYAOYAS


 
Link to comment
Share on other sites

OK, I was just going to ask that (if you were doing duplicate define names in the two different .ttm files).

 

BTW, an include (.ttm file called with an include statement or other files like target.tmh) should be treated as if the text of that file is inserted into your main .tmc file exactly where the include statement is. And in fact that is exactly what happens during compiling.

 

As you discovered, you can't define the same name twice in a single .ttm file or anywhere in the entire compiled set of files for that matter, "included" or otherwise..

 

But there is another way to do it using variables instead of defines. For example I might define the following in a .ttm file: (SGT_Coyle, I just saw you have done variables before but hopefully this will enhance your understanding - if not sorry for the redundancy)

 

define		WipersIncrease	'v'			// Window Wiper - increase speed
define		WipersDecrease	L_SHIFT+'v'	// Window Wiper - decrease speed

 

But I can do a similar thing with integer variables as follows:

 

int wipersIncrease = 'v';
int wipersDecrease = L_SHIFT+'v';

 

'v' is a variable of type char but a char is just an 8 bit integer. Hence why I use an int variable (int wipersIncrease for example). It can be used just like a define, but a define is a constant - can't change it. A variable can be changed. And it also means you can create variables just like defines with SHIFT, ALT, CTRL, etc. as I did with wipersDecrease.

 

BTW, I tend to start defines with a capital letter but variables with lower case. It helps me remember which is a define vs. a variable.

 

Then you can use this variable just like you would a define macro. For example:

 

int wpersIncrease = 'v';
int wipersDecrease = L_SHIFT+'v';

// EAC Switch
MapKeyIO(&Throttle, EACON, 0, PULSE+wipersIncrease);
MapKeyIO(&Throttle, EACOFF, 0, PULSE+wipersDecrease);

 

Here I added a PULSE command to the two wiper variables. It all works just like a define.

 

 

It is important to think about where you define the variables, though. Variables created before main() will be global which will include any variables you create in a .ttm file which is included before main(). All functions will see them, and anywhere you change the variable, it changes it globally. But if you create the variable inside a function the variable is only visible in that function. And its value will bw lost when you leave that function. This is all just standard C programming.

 

Here is a complex example which uses both global int variables and local int variables. This is just a small subset of a Target program I wrote for Train Sim World which allows changing the config profile for 7 different locomotive engines. It uses the same concept of a common config function (see CommonConfig()) as well as custom configuration functions for each different engine.

 

Don't worry about all the details in my example. I stripped this down to just to show the examples of how I handled windshield wipers and engine headlights differently for several engines. In some cases I used defines in the .ttm and in others I used int variables. In some I used variables with defines to build complex chains.

 

Look for the following variables in the code. These three are global for controlling the windshield wipers:

wiperCHAINUP

wiperCHAINDN

wiperCHAINUPCount;

 

But these are defined only inside specific functions and are visible only inside those functions:

headlightFrontFwd

headlightFrontBkd

headlightRearFwd

headlightRearBkd

 

Note, this example will not compile and run. I stripped it down too much. If you want to see the full script, you can see it here:

https://forums.dovetailgames.com/threads/thurstmaster-target-script-for-warthog-throttle-saitek-tq-profile.3634/

 

Or just download the script here (with documentation):

http://akhara.com/drop/TrainSimWorld/TSW_TARGET_Script_Drakoz_v2_1.zip

 

Here is the .tmc:

include "target.tmh"
include "Drakoz_TrainSimWorld.ttm"

// Default Engine Profile 
//	This script is designed to have different control setups for different engines.  
//	This is mainly to control the difference of separate throttle and brake levers (e.g. SD40-2, GP38)
//  vs. combined throttle/brake levers (e.g. AC4400CW). 
//	Choices:
//	  pro_ProfileSelection = 
//			pro_SD40GP38		- EMD SD40-2, GP38-2, GP40-2	(LED 00001 = 1)
//			pro_AC4400CW		- GE AC4400CW					(LED 00010 = 2)
//			pro_BR43			- British Rail Class 43 HST		(LED 00011 = 3)
//			pro_BR166			- British Rail Class 166		(LED 00100 = 4)
//			pro_BR66			- British Rail Class 66			(LED 00101 = 5)
//			pro_DBBR422			- DB BR 442 Talent 2 EMU		(LED 00110 = 6)
//			pro_ACS64			- Amtrak ACS-64					(LED 00111 = 7)
//int pro_ProfileSelection = pro_SD40GP38;
int pro_ProfileSelection = pro_ACS64;

int wiperCHAINUP, wiperCHAINDN, wiperCHAINUPCount;		// global vars used for window wiper switch up/down commands

int main()
{
   // ...
   
// Call functions to make custom configuration for each profile
//	Allows creating MapKey() and other configurations specific to each engine type.
//	Configurations in pro_CallCustomConfigs() will override any previous MapKey(), KeyAxis(), etc. commands.  
pro_CallCustomConfigs();

}	// end main()

//******************************************************************
// CommonConfig()
//	Configurations (MapKey, KeyAxis, Axis setup, etc.) that is common to all engines should be set up here. 
//  This function will be called every time a profile change occurs before setting any custom configuration for specific engines.  
int CommonConfig()
{

// Engine Fuel Flow Left/Right Switches	
MapKeyIO(&Throttle, EFRNORM, 0, CHAIN(LOCK+DOWN+WipersIncrease, D(500), UP+WipersIncrease, LOCK));
MapKeyIO(&Throttle, EFROVER, 0, CHAIN(LOCK+DOWN+WipersDecrease, D(1100), UP+WipersDecrease, LOCK));

// Engine Operate Switch - Left
MapKeyIO (&Throttle, EOLIGN, 0, PULSE+HeadlightsRearFwd);
MapKeyIO (&Throttle, EOLNORM, 0, 0);
MapKeyRIO(&Throttle, EOLMOTOR, 0, 0);
MapKeyIO (&Throttle, EOLMOTOR, 0, PULSE+HeadlightsRearBkd);

// Engine Operate Switch - Right
MapKeyIO (&Throttle, EORIGN, 0, PULSE+HeadlightsFwd);
MapKeyIO (&Throttle, EORNORM, 0, 0);
MapKeyRIO(&Throttle, EORMOTOR, 0, 0);
MapKeyIO (&Throttle, EORMOTOR, 0, PULSE+HeadlightsBkd);	

// Autopilot button and switch
wiperCHAINUP = CHAIN(LOCK+DOWN+WipersIncrease, D(250), UP+WipersIncrease, D(25), LOCK);
MapKeyIO(&Throttle, APPAT, 0, 							// Repeat WipersIncrease until APPAT turned off, or count reached
	CHAIN(
		EXEC("wiperCHAINUPCount=5;"), 					// Set to number of time to repeat
		REXEC(REXEC_Wiper, 1000, 						// 1 second delay between repeats
			"ActKey(KEYON+wiperCHAINUP);"				// press wiper key
			"wiperCHAINUPCount=wiperCHAINUPCount-1;"	// decrement count and if = 0, stop the REXEC
			"if (wiperCHAINUPCount <= 0) StopAutoRepeat(REXEC_Wiper);"
		)
	)
);

wiperCHAINDN = CHAIN(LOCK+DOWN+WipersDecrease, D(250), UP+WipersDecrease, D(25), LOCK);
MapKeyIO(&Throttle, APALT, 0,  							// Repeat WipersDecrease until APALT turned off, or count reached
	CHAIN(
		EXEC("wiperCHAINUPCount=5;"), 
		REXEC(REXEC_Wiper, 1000, 
			"ActKey(KEYON+wiperCHAINDN);"
			"wiperCHAINUPCount=wiperCHAINUPCount-1;"
			"if (wiperCHAINUPCount <= 0) StopAutoRepeat(REXEC_Wiper);"
		)
	)
);

   // ... other configs that are common to all engines

}

//******************************************************************
// pro_CallCustomConfigs()
//	Call functions to make custom configuration for each profile
int pro_CallCustomConfigs()
{
// Do common config shared by all engines first
CommonConfig();		

// Then do custom config depending on profile.  
// MapKey(), etc. setup in custom config will overwrite the button/axis configs from the common config.
if      (pro_ProfileSelection == pro_SD40GP38)	pro_ConfigureSD40GP38();
else if (pro_ProfileSelection == pro_AC4400CW)	pro_ConfigureAC4400CW();
else if (pro_ProfileSelection == pro_BR43) 		pro_ConfigureBR43();
else if (pro_ProfileSelection == pro_BR166) 	pro_ConfigureBR166();
else if (pro_ProfileSelection == pro_BR66) 		pro_ConfigureBR66();
else if (pro_ProfileSelection == pro_DBBR422) 	pro_ConfigureDBBR422();
else if (pro_ProfileSelection == pro_ACS64) 	pro_ConfigureACS64();
}

//******************************************************************
// pro_ConfigureSD40GP38()
//	Custom configuration for SD40-2, GP38-2, GP40-2 and other similar diesel engines
int pro_ConfigureSD40GP38()
{
printf("Profile %d: pro_SD40GP38\xa", pro_SD40GP38);

   // ... custom config here ...
   
}
	
//******************************************************************
// pro_ConfigureAC4400CW()
//	Custom configuration for AC4400CW. 
int pro_ConfigureAC4400CW()
{
printf("Profile %d: pro_AC4400CW\xa", pro_AC4400CW);

// Headlight Switch - different delays needed vs. other engines. 
// Following complicated CHAIN commands needed to overcome issues with SHIFT & CTL not being received properly by TSW (bug with TSW?)
int headlightFrontFwd = CHAIN(LOCK+DOWN+'h', D(250), UP+'h', D(50), LOCK);
int headlightFrontBkd = CHAIN(LOCK+DOWN+L_SHIFT, D(50), DOWN+'h', D(250), UP+'h', D(50), UP+L_SHIFT, D(50), LOCK);
int headlightRearFwd = CHAIN(LOCK+DOWN+L_CTL, D(50), DOWN+'h', D(300), UP+'h', D(50), UP+L_CTL, D(50), LOCK);
int headlightRearBkd = CHAIN(LOCK+DOWN+L_SHIFT, D(50), DOWN+L_CTL, D(50), DOWN+'h', D(300), UP+'h', D(50), UP+L_CTL, D(50), UP+L_SHIFT, D(50), LOCK);
// Engine Operate Switch - Right
MapKeyIO (&Throttle, EORIGN, 0, headlightFrontFwd);
MapKeyIO (&Throttle, EORNORM, 0, 0);
MapKeyRIO(&Throttle, EORMOTOR, 0, 0);
MapKeyIO (&Throttle, EORMOTOR, 0, headlightFrontBkd);	
// Engine Operate Switch - Left
MapKeyIO (&Throttle, EOLIGN, 0, headlightRearFwd);
MapKeyIO (&Throttle, EOLNORM, 0, 0);
MapKeyRIO(&Throttle, EOLMOTOR, 0, 0);
MapKeyIO (&Throttle, EOLMOTOR, 0, headlightRearBkd);	

   // ... other custom config here ...
   
}

//******************************************************************
// pro_ConfigureBR43()
//	Custom configuration for British Rail Class 43 HST
int pro_ConfigureBR43()
{
printf("Profile %d: pro_BR43\xa", pro_BR43);

   // ... custom config here ...

}

//******************************************************************
// pro_ConfigureBR166()
//	Custom configuration for British Rail Class 166
int pro_ConfigureBR166()
{
printf("Profile %d: pro_BR166\xa", pro_BR166);

// Headlight Switch - different delays needed vs. other engines. 
// Following complicated CHAIN commands needed to overcome issues with SHIFT & CTL not being received properly by TSW (bug with TSW?)
int headlightFrontFwd = CHAIN(LOCK+DOWN+'h', D(400), UP+'h', D(50), LOCK);
int headlightFrontBkd = CHAIN(LOCK+DOWN+L_SHIFT, D(50), DOWN+'h', D(400), UP+'h', D(50), UP+L_SHIFT, D(50), LOCK);
// Engine Operate Switch - Right
MapKeyIO (&Throttle, EORIGN, 0, headlightFrontFwd);
MapKeyIO (&Throttle, EORNORM, 0, 0);
MapKeyRIO(&Throttle, EORMOTOR, 0, 0);
MapKeyIO (&Throttle, EORMOTOR, 0, headlightFrontBkd);

   // ... other custom config here ...
   	
}

//******************************************************************
// pro_ConfigureBR66()
//	Custom configuration for British Rail Class 66
int pro_ConfigureBR66()
{
printf("Profile %d: pro_BR66\xa", pro_BR66);

// Engine Operate Switch - Left
//   Map HeadlightsRearFwd for EOLIGN and EOLMOTOR because HeadlightsRearBkd does nothing for this engine
MapKeyIO (&Throttle, EOLIGN, 0, HeadlightsRearFwd);
MapKeyIO (&Throttle, EOLNORM, 0, 0);
MapKeyRIO(&Throttle, EOLMOTOR, 0, 0);
MapKeyIO (&Throttle, EOLMOTOR, 0, HeadlightsRearFwd);	

   // ... other custom config here ...
   	
}

//******************************************************************
// pro_ConfigureDBBR422()
//	Custom configuration for DB BR 442 Talent 2 EMU
int pro_ConfigureDBBR422()
{
printf("Profile %d: pro_DBBR422   --  currently unsupported\xa", pro_DBBR422);

   // ... custom config here ...

}

//******************************************************************
// pro_ConfigureACS64()
//	Custom configuration for Amtrak ACS-64
int pro_ConfigureACS64()
{
printf("Profile %d: pro_ACS64\xa", pro_ACS64);

   // ... custom config here ...

}

//******************************************************************
int EventHandle(int type, alias o, int x)
{	
DefaultMapping(&o, x);
}
//******************************************************************

 

And the .ttm:

//******************************************************************
//	Profile Selection Labels (used for the variable pro_ProfileSelection)
//	Do not define any profile at 0, only 1 through 31 allowed.  
define		pro_SD40GP38		1		// EMD SD40-2, GP38-2, GP40-2	(LED 00001 = 1)
define		pro_AC4400CW		2		// GE AC4400CW					(LED 00010 = 2)
define		pro_BR43			3		// British Rail Class 43 HST	(LED 00011 = 3)
define		pro_BR166			4		// British Rail Class 166		(LED 00100 = 4)
define		pro_BR66			5		// British Rail Class 66		(LED 00101 = 5)
define		pro_DBBR422			6		// DB BR 442 Talent 2 EMU		(LED 00110 = 6)
define		pro_ACS64			7		// Amtrak ACS-64				(LED 00111 = 7)

define		pro_NumOfProfiles	7		// Set to the number of profiles listed  (31 max allowed)


//******************************************************************
//  REXEC() Handles
//	Place any handles for REXEC() here so we know which handle numbers we have used (0 to 99 allowed)
define		REXEC_Wiper				1			// Used for a repeating window wiper REXEC() function


define		WipersIncrease			'v'					// Window Wiper - increase speed
define		WipersDecrease			L_SHIFT+'v'			// Window Wiper - decrease speed

// Following complicated CHAIN commands needed to overcome issues with SHIFT & CTL not being received properly by TSW (bug with TSW?)
//define	HeadlightsFwd			'h'					// Front Headlight - Move to next Switch Position
define		HeadlightsFwd			CHAIN(LOCK+DOWN+'h', D(250), UP+'h', D(50), LOCK)
//define	HeadlightsBkd			L_SHIFT+'h'			// Front Headlight - Move to previous Switch Position
define		HeadlightsBkd			CHAIN(LOCK+DOWN+L_SHIFT, D(50), DOWN+'h', D(250), UP+'h', D(50), UP+L_SHIFT, D(50), LOCK)
//define	HeadlightsRearFwd		L_CTL+'h'			// Rear Headlight - Move to next Switch Position
define		HeadlightsRearFwd		CHAIN(LOCK+DOWN+L_CTL, D(50), DOWN+'h', D(250), UP+'h', D(50), UP+L_CTL, D(50), LOCK)
//define	HeadlightsRearBkd		L_SHIFT+L_CTL+'h'	// Rear Headlight - Move to previous Switch Position
define		HeadlightsRearBkd		CHAIN(LOCK+DOWN+L_SHIFT, D(50), DOWN+L_CTL, D(50), DOWN+'h', D(250), UP+'h', D(50), UP+L_CTL, D(50), UP+L_SHIFT, D(50), LOCK)


Edited by Drakoz
Link to comment
Share on other sites

  • 3 weeks later...
Hello smart people! I have a T16000M and have an idea to map the throttle slider as a ShiftButton for IO layer. Is this possible?

 

 

So I don't have a T16000M, but I imagine the slider is like the Friction lever on the WH.

This .tmc works for the WH. It will print in the status window "Shift State OUT" and "Shift State IN" when you move the slider appropriately.

 

Hope this helps.

 

include "target.tmh"

//program startup
int main()
{
   if(Init(&EventHandle)) return 1; // declare the event handler, return on error
   
   //add initialization code here
   ;
   
   
   SetKBRate(22, 35);
   
   SetShiftButton(&Joystick, S4, 0, 0, 0);

//AXIS init        
   MapAxis(&Joystick, JOYX, DX_X_AXIS);
   MapAxis(&Joystick, JOYY, DX_Y_AXIS);
   
   //MapAxis(&Throttle, THR_LEFT, DX_ZROT_AXIS);
   MapAxis(&Throttle, THR_RIGHT, DX_Z_AXIS);
   
//*********Slew Stick acting as Mouse    
   MapAxis(&Throttle, SCX, MOUSE_X_AXIS, AXIS_NORMAL, MAP_RELATIVE);
       SetSCurve(&Throttle, SCX, 0, 10, 0, 0, -4);
   MapAxis(&Throttle, SCY, MOUSE_Y_AXIS, AXIS_REVERSED, MAP_RELATIVE);
       SetSCurve(&Throttle, SCY, 0, 10, 0, 0, -4);

//*********Slew Stick acting as independent AXIS.  NOT Mouse!!!  Used to setup control of A/C TDC        
//    MapAxis(&Throttle, SCX, DX_XROT_AXIS, AXIS_NORMAL, MAP_ABSOLUTE);
//        SetSCurve(&Throttle, SCX, 0, 10, 0, 0, -4);
//    MapAxis(&Throttle, SCY, DX_YROT_AXIS, AXIS_REVERSED, MAP_ABSOLUTE);
//        SetSCurve(&Throttle, SCY, 0, 10, 0, 0, -4);
   //TDC Slew Control on Throttle Mini Stick    
   //KeyAxis(&Throttle, SCX, 0, AXMAP2(3,Throttle_Designator_Controller_Left,0,Throttle_Designator_Controller_Right));
   //KeyAxis(&Throttle, SCY, 0, AXMAP2(3,Throttle_Designator_Controller_Down,0,Throttle_Designator_Controller_Up));    
       
   MapAxis(&Throttle, THR_FC, DX_SLIDER_AXIS);
   KeyAxis(&Throttle, THR_FC,'ioumd',AXMAP2(3, EXEC( "Shift_State_OUT();"), 0, EXEC( "Shift_State_IN();")));// 3 SECTIONS:  Gear up, none, Gear Down
   
// Init Lights  Programing light below
//    ActKey(PULSE+KEYON+LED(&Throttle, LED_INTENSITY, 10)); //set Throttle backlight power to middle // set Throttle backlight power to low
//    ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT+LED1)); //set LED 1 On
//    ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT-LED2)); //set LED 2 OFF
//    ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT+LED3)); //set LED 3 On
//    ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT-LED4)); //set LED 4 OFF
//    ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT+LED5)); //set LED 5 On
// Flags...    
}
int Shift_State_OUT()
{
   printf("Setting Shift State OUT...\xa");
//////////////////////////////////////////////////////////////////////    
//BUTTON PROGRAMING STARTS BELOW
//////////////////////////////////////////////////////////////////

}
////////////*\\\\\\\\\\*//////////*\\\\\\\\\\*//////////*\\\\\\\\\\*//////////*\\\\\\\\\
//\\\\\\\\\\*//////////*\\\\\\\\\\*//////////*\\\\\\\\\\*//////////*\\\\\\\\\\*/////////
int Shift_State_IN()
////////////*\\\\\\\\\\*//////////*\\\\\\\\\\*//////////*\\\\\\\\\\*//////////*\\\\\\\\\
//\\\\\\\\\\*//////////*\\\\\\\\\\*//////////*\\\\\\\\\\*//////////*\\\\\\\\\\*/////////
{
   printf("Setting Shift State IN...\xa");
//////////////////////////////////////////////////////////////////////    
//BUTTON PROGRAMING STARTS BELOW
//////////////////////////////////////////////////////////////////

}

//event handler
int EventHandle(int type, alias o, int x)
{
   DefaultMapping(&o, x);
   
   //add event handling code here
}


Edited by SGT Coyle

Night Ops in the Harrier

IYAOYAS


 
Link to comment
Share on other sites

Another way to do it is to create virtual Shift IO or UMD buttons, and then set the UMD or IO state manually instead of using the SetShifttButton() command. This allows you to use MapKeyIO() or MapKeyUMD() normally vs. the method posted by SGT Coyle above. Both methods work great, and which you use depends on how you want to do your coding.

 

I posted how to do this in detail at SimHQ (see link below).

http://simhq.com/forum/ubbthreads.php/topics/4422100/activate-a-layer-by-code

 

I'll restate the main details below so as to not divert the discussion to another forum.

 

First, an example that explains how to manually change the IO or UMD state of a normal button - this is important to understand before showing how to create virtual buttons and do the same thing with a virtual button.

 

I am using the Warthog Throttle MSP button for my IO button, and the Warthog Throttle Boat Switch (BSF, BSB) for my U, M, and D modes. But these techniques will work with any TARGET compatible device.

 

Below, I mention Throttle[<button>]. This is really just &Throttle. &Throttle references the array Throttle[], and Throttle[] contains the current state of all the buttons and axis from the Warthog Throttle. For example, Throttle[MSP] equals the state of the Warthog Throttle MSP button (hence why I said <button> to generically mean you can insert any button name between the []). For other devices, you would use Joystick[] for the Warthog Joystick (referenced normally as &Joystick), T16000[] for the T16000 stick and throttle (referenced normally as &T16000), etc. These arrays are how TARGET tracks the current state of all buttons and axis for all connected devices, and they allow us a lot of power to manipulate stuff.

 

So, you can set the mode (I, O, U, M, or D) by setting the Throttle[<button>] value equal to 1 or 0 (1 is pressed, 0 is not pressed). Then call the EventHandler. But understand that EventHandle() in the bottom of your script file is not the master Event Handler. Instead, we have to call DefEventHandler() which is in target.tmh. DefEventHandler() does a few checks, and then calls EvenHandle() and EventHandle() then calls DefaultMapping() which handles all events. In this case, we are tricking TARGET into thinking that the MSP or Boat Switch changed.

 

In my example, I just used EXEC() routines connected to other buttons to fire off the change in IO or UMD. You can confirm it changed by pressing TG1. Also, if you actually press the IO or UMD buttons, it will override this of course because it will set a new IO or UMD mode.

 

SetShiftButton(&Joystick, MSP, &Joystick, BSF, BSB);

// Set Shift mode to I
MapKey(&Joystick, S1, EXEC("Throttle[MSP]=1; DefEventHandler(EV_HID_INPUT_DATA, &Throttle, MSP);"));
// Set Shift mode to O
MapKey(&Joystick, S2, EXEC("Throttle[MSP]=0; DefEventHandler(EV_HID_INPUT_DATA, &Throttle, MSP);"));

// Set UMD mode to U
MapKey(&Joystick, H1U, EXEC("Throttle[bSF]=1; DefEventHandler(EV_HID_INPUT_DATA, &Throttle, BSF);"));
// Set UMD mode to M (reset U mode)
MapKey(&Joystick, H1D, EXEC("Throttle[bSF]=0; DefEventHandler(EV_HID_INPUT_DATA, &Throttle, BSF);")); 
// Set UMD mode to M (reset D mode)
MapKey(&Joystick, H1L, EXEC("Throttle[bSB]=0; DefEventHandler(EV_HID_INPUT_DATA, &Throttle, BSB);")); 
// Set UMD mode to D
MapKey(&Joystick, H1R, EXEC("Throttle[bSB]=1; DefEventHandler(EV_HID_INPUT_DATA, &Throttle, BSB);"));

// Use TG1 to test the result
MapKeyIOUMD(&Joystick, TG1, 
'4',	// IU
'3',	// OU
'2',	// IM
'1',	// OM
'6',	// ID
'5'	// OD
);

 

For Resetting the U or D mode to M, any action that sets M mode will reset either U or D.

 

It may work just as well to call EventHandle() directly (e.g. EventHandle(EV_HID_INPUT_DATA, &Throttle, MSP); ), but probably better to call DefEvenHandler() as this is what TARGET does for all new events. Also, in this example, EV_HID_INPUT_DATA has no impact on the result. You could probably leave it as 0 and it would still work. But EV_HID_INPUT_DATA seems to be the proper value for a generic controller input change. See hid.tmh for the definition of EV_HID_INPUT_DATA, though it is not clearly explained. I think this is related to a legacy feature, or something that was not completely implemented. EventHandle() completely ignores it.

 

 

 

But, I hear you say, you don't want to have to assign a real button as the IO or UMD buttons using SetShiftButton(). So we can use virtual buttons.

 

You can create virtual buttons to achieve this. Here is an updated code example using VBI, VBU, and VBD (buttons I created for the Warthog Joystick) as virtual IO and UMD buttons. This code example is a complete program. Copy and paste into the TARGET script editor and it will run. It should work with minor changes for the T16000. I did this to point out that the defines for VBI, VBU and VBD must be outside of main(), or must be in your .ttm file. This example does not use a .ttm.

 

You have a maximum of 52 real + virtual buttons which are numbered 0 through 51 (this has been discussed earlier in this thread). This maximum is defined by MAXKEYDATA in target.tmh. The Warthog Throttle uses all 52 of them, but the Warthog Joystick and most other TARGET supported devices use less than 52 buttons. You can see this in the defines.tmh file. Look at the "Warthog Joystick interface" definition. It has slots 0 - 18, assigned to real buttons, and 29 - 32 assigned to virtual buttons. So it is safe to use slots 40, 41, and 42. So I assigned VBI, VBU and VBD as 40, 41, and 42 and used them for the Warthog Joystick.

 

If Joystick[VBI] = 1, then the virtual button is "pressed", and = 0 means released. Now, everything you can do with a real button, you can do with VBI, VBU and VBD, including assigning them as the IO Shift and UMD Mode buttons.

 

My example below uses joystick buttons, but you can do the same by putting the EXEC() commands in a KeyAxis() command for the T16000 Throttle as SGT Coyle suggested.

 

include "target.tmh"

// Define virtual buttons for IO Shift and UMD mode for Warthog Joystick
define VBI	40	// Mode I virtual button
define VBU	41	// Mode U virtual button
define VBD	42	// Mode D virtual button

int main()
{
if(Init(&EventHandle)) return 1;

SetShiftButton(&Joystick, VBI, &Joystick, VBU, VBD, 0);		// IO Shift and UMD Setup (%DEV1, I button, $DEV, U, D, Toggle settings)

MapKey(&Joystick, S1, EXEC("Joystick[VBI]=1; DefEventHandler(EV_HID_INPUT_DATA, &Joystick, VBI);"));
MapKey(&Joystick, S2, EXEC("Joystick[VBI]=0; DefEventHandler(EV_HID_INPUT_DATA, &Joystick, VBI);"));

MapKey(&Joystick, H1U, EXEC("Joystick[VBU]=1; DefEventHandler(EV_HID_INPUT_DATA, &Joystick, VBU);"));
MapKey(&Joystick, H1D, EXEC("Joystick[VBU]=0; DefEventHandler(EV_HID_INPUT_DATA, &Joystick, VBU);")); 
MapKey(&Joystick, H1L, EXEC("Joystick[VBD]=0; DefEventHandler(EV_HID_INPUT_DATA, &Joystick, VBD);")); 
MapKey(&Joystick, H1R, EXEC("Joystick[VBD]=1; DefEventHandler(EV_HID_INPUT_DATA, &Joystick, VBD);")); 

// Test the result
MapKeyIOUMD(&Joystick, TG1, 
	'4',		// IU
	'3',		// OU
	'2',		// IM
	'1',		// OM
	'6',		// ID
	'5'		// OD
);		
}

int EventHandle(int type, alias o, int x)
{
DefaultMapping(&o, x);
}

 

If you want to use a different Thrustmaster device, make sure the numbers you choose do not conflict with the device definition in defines.tmh.

 

I assume if you increase MAXKEYDATA in target.tmh to a larger value, you can create more virtual buttons, up to 256 total buttons (real + virtual) because the joy1[], joy2[], joy3[], etc. arrays defined in hid.tmh allow for up to 256 buttons total. Note, joy1[], joy2[], etc. are the actual arrays which &Joystick, &Throttle, &HCougar, etc. point to.

 

See my post on SimHQ on "Re: How to detect Shift key"

http://simhq.com/forum/ubbthreads.php/topics/4408901/re-how-to-detect-shift-key#Post4408901

for more details on these arrays. Understanding them goes a long way toward understanding how to do all these more advanced TARGET scripts.

 

And for some more commentary on all this, go back to where I originally posted all this on SimHQ.

http://simhq.com/forum/ubbthreads.php/topics/4422100/activate-a-layer-by-code

Link to comment
Share on other sites

  • 4 weeks later...

New to this forum after stumbling across this thread.

 

I am not a programmer but have taught myself TARGET over the last year or so through trial and error. During this time, I have been scouring the internet for decent TARGET scripts that I can learn from.

I would consider myself "intermediate", so stumbling upon a forum where several people are advanced is a god send...AT LAST!

 

I have many questions, however, I will restrain myself and try to ask only one or two at a time!

The first one is this...

I have managed to work out how most of the string function in sys.tmh work along with most of the file operation functions but for the life of me I have not been able to get the "strcat(alias dst, alias src){}" function to work.

Can someone please confirm for me that this function (in sys.tmh) actually works and if so please post a working example?

 

 

Next is "int input(alias s){}"...no idea how to get this working.

I know that TARGET creates a virtual keyboard to send keystrokes, but how on earth would it capture same (from the keyboard presumably)?

 

Again, if anyone knows how this works and could give me a working example, that'd be great.

 

Cheers

dmonds


Edited by dmonds
Link to comment
Share on other sites

Hi dmonds ... for strcat:

include "target.tmh"
int main()
{
   // \xa .. UNICODE HEX VALUE FOR LINEFEED
   printf("--------------------\xa");

   alias    s1 = " s1 ";           // static string
   alias    s2 = " s2 ";           // static string

   char     buf;                   // dynamic string
   Dim(&buf, 256);                 // memory allocation

   buf[0] = 0;                     // initialize as an empty string
   printf("buf=[%s]\xa", &buf);

   strcat(&buf,          &s1);     // strcat 1
   printf("buf=[%s]\xa", &buf);

   strcat(&buf,          &s2);     // strcat 2
   printf("buf=[%s]\xa", &buf);

   //----------------------------  // ... sprintf can do much better than strcat
   int number = 42;
   sprintf(&buf, "FORMATED: number=[%d] .. s1=[%s] .. s2=[%s]", number, &s1, &s2);
   printf("buf=[%s]\xa", &buf);

   printf("--------------------\xa");
   exit(0);
}


Edited by ivanwfr
Link to comment
Share on other sites

Thanks so much Ivan for your reply.

 

I'll load that up and have a play to get my head around it.

 

I'm not that familiar with the complexities of C variables which is what I think has me tripped up.

 

Thanks again,

dmonds

 

p.s. ummm... "exit(0);" ??? "return 0;" perhaps?


Edited by dmonds
Link to comment
Share on other sites

Thanks so much Ivan for your reply.

 

I'll load that up and have a play to get my head around it.

 

I'm not that familiar with the complexities of C variables which is what I think has me tripped up.

 

Thanks again,

dmonds

 

p.s. ummm... "exit(0);" ??? "return 0;" perhaps?

 

Good point!

You're quite right about using the return instruction to terminate the main function.

I should have replaced this system call with a standard process status value.

That was just a copy-paste from my hijacked main that I wanted to ignore its original task.

 

And BTW, this is no C, it's a dialect of some sort where everything seems familiar but with a twist.

Watch out for address (&) and pointers (alias alias). I used to work with C for decades and here, I'm just a newbie sometimes ;)

Link to comment
Share on other sites

Changing curves on the fly

 

Hi,

 

Next question...

 

In my script I change the curves on the slider to vary the sensitivity depending on a game mode I'm in.

 

Issue: As soon as I switch game modes (which require the new curve) I get unwanted axis values being sent to the game until I move the slider. In effect, the slider is sending an axis value based on the previous curve.

 

Question: After changing the curves, is there a way to read/send (update) the new value of the slider without having to move the slider?

 

Thanks

dmonds


Edited by dmonds
formatting
Link to comment
Share on other sites

Sorry dmonds, but as I'm not as involved as I used to be, all these mappings became nearly as alien to me as they were during my first encounter.

 

Maybe you could get some clues from the code archive from my first post.

 

There is something dealing with SetSCurve in axis_THR_SC_STICK.tmc.

 

Maybe someone here could take over on this one...

 

If you don't reach a solution for a few days, I could try harder once again.

Link to comment
Share on other sites

OK...so, I'm already using these methods in my script...thanks anyway.

 

However other posts in this thread have given me an idea.... that is use digital axes instead of analogue.

 

I've never played with this but the game does have key bindings to increase/decrease as alternate for analogue axis, so worth a play.

 

If successful, I'll post my solution.

 

dmonds

Link to comment
Share on other sites

Sorry dmonds, but as I'm not as involved as I used to be, all these mappings became nearly as alien to me as they were during my first encounter.

 

Maybe you could get some clues from the code archive from my first post.

 

There is something dealing with SetSCurve in axis_THR_SC_STICK.tmc.

 

Maybe someone here could take over on this one...

 

If you don't reach a solution for a few days, I could try harder once again.

 

Hi,

 

I've been unable to work this out yet.

Trying digital instead of analogue does not help.

 

Looks like I need to somehow send the axis value of the current slider position to the game.

Easy enough if I move the slider itself. I can perservere with this if I need to.

 

However if there is a way to interrogate then send current value of slider without actually moving the slider, that'd be ideal.

 

For what it's worth, Device Analyzer also won't update until I move the slider as well.

 

Any help or suggestions would be gratefully received.

 

dmonds

Link to comment
Share on other sites

Hi dmonds,

 

I have no idea how to send a query to the device.

 

I too had to resort to waiting for an event to handle in order to initialize a parameter instead of applying some initial value.

 

What I found best was to rely on some user activation to sense the current value while moving the device actuator.

 

The only drawback is that this is a prerequisite for both the hardware and software values to get synchronized.

 

This is typically one of the reason why I gave up adding features to my code.

And now, I can see that the "Lua exporting in DCS" page I used to watch going nowhere back in 2011 has simply disappeared from ED site.

So, when you will get stuck somewhere, it'll be for good ;(

 

I had some contact with Guillemot at the time and I could get a bit of insight beyond the official TARGET book.

And this is how I could get some dynamic data at work in util/util_GameCB.tmc from PNP_ivanwfr_111222.zip.

Maybe you can get some launch-time state or run-time feedback from the sim this way...

Link to comment
Share on other sites

Thanks for the reply ivan,

 

I'll likely keep plugging away for a short while and see if I can work it out.

 

In the meantime, I'll just revert to moving the slider slightly each time I change the curves/sensitivity.

 

Cheers

Link to comment
Share on other sites

In my script I change the curves on the slider to vary the sensitivity depending on a game mode I'm in.

 

Issue: As soon as I switch game modes (which require the new curve) I get unwanted axis values being sent to the game until I move the slider. In effect, the slider is sending an axis value based on the previous curve.

 

Question: After changing the curves, is there a way to read/send (update) the new value of the slider without having to move the slider?

 

I have several ideas on how to solve this, but I'm not 100% sure about exactly the issue you are seeing. Can you post your TARGET script so I can see what you mean? I'll look at it and make some suggestions.

 

In the mean time, you may want to read this forum topic at SimHQ (SimHQ: Set an axis to a particular value) where I go into detail on many of the techniques that may help you. If you have questions, please post here on the ED forums. It is not my intention to divert this conversation to another forum, and I think there is a much bigger audience here.

 

In the topic above, I explain stuff like how to use DXAxis() to set an axis to a specific value, or how to create your own scripts to manually apply curves. Although that might be more difficult than simply using SetSCurve(), doing so would allow you to more easily control syncing up the physical lever on the Warthog with the position calculated for that axis in TARGET and prevent a jump like you are experiencing. I also have an example of a script that will allow you to move a lever until it is in sync with what TARGET thinks the lever is at, and then enable that lever to work - hence preventing a jump.

 

But toward your primary question.... Causing TARGET to update an axis without moving the axis

 

At first, I considered that you might just call EventHandle() from your button press that changes the axis curve, but then I realized that if you create a call to EventHandle() as a result of performing a button press (which causes a call to EventHandle() already), you would be calling EventHandle() within EventHangle(), which is perhaps not a good idea. Since calling EventHandle() is really just calling DefaultMapping(), you would be calling DefaultMapping() within itself (nested), and I believe all the code in DefaultMapping() is designed to run unnested. I haven't tried this, so it might be worth a try (CORRECTION: I did try this - see my post below). Worst thing is TARGET might lock up, or just do weird things.

 

The code might look like the following. I'm using EACON on the Throttle to change the curve. EAOFF would set a different curve for example.

 

MapKey(&Throttle, EACON, 
CHAIN(
	SetSCurve(&Joystick, THR_FC, 0, 0, 0, 0, 0), 	// Set new curve (my example is just a flat curve, no deadzone)
	EXEC("DefaultMapping(&Thorttle, THR_FC);" )		// This will cause TARGET to recalculate the curve and move the axis
),
);

 

But since changing the state of EACON would call EventHandle(), and since the commands for EACON also does an EXEC to call DefaultMapping(), I believe this will be a nested call to DefaultMapping(), and that might screw up some global variables that expect DefaultMapping() to NOT be nested.

 

Again, please post your code, and I can make some better suggestions.

 

Regards,

Michael


Edited by Drakoz
Link to comment
Share on other sites

Ok, here's snippets of my code:-

 

In my initialization routine I have...

 

MapAxis(&Throttle, THR_FC, DX_SLIDER_AXIS, AXIS_NORMAL,MAP_ABSOLUTE);
fnSetSliderCurve(1);

 

...my fnSetSliderCurve() routine...

 

int fnSetSliderCurve(int x) {
DXCurveSetting = x;
if (x == 0) {
	SetSCurve(&Throttle, THR_FC, 0, 0, 0, 0, 0);
}
if (x == 1)	{
	SliderCurve = LIST(0,0, 40,25, 75,50, 85,75, 100,100);
	SetCustomCurve(&Throttle, THR_FC, SliderCurve);
}
if (x == 2)	{
	SliderCurve = LIST(0,0, 50,10, 75,30, 90,50, 100,100);
	SetCustomCurve(&Throttle, THR_FC, SliderCurve);
}
}

 

I detect within the game (Elite Dangerous) when the flight mode changes then call fnSetSliderCurve() parsing the appropriate value (0, 1 or 2).

These flight modes (for some inexplicable reason) use different scales for the HUD Radar.

The above three modes approximate what's required as far as , when the slider is in the middle detent position, the radar range scale in game is also in the middle.

 

Like I said, this works well with the only exception being that the new curve doesn't kick in until I move the slider.

 

Thanks for the reply and the reference to what you've written at SimHQ.

I will give these a read and try to get my head around it.

 

Many thanks

DMonds


Edited by dmonds
Link to comment
Share on other sites

Hi again @Drakoz,

 

Brilliant stuff!

 

I've added...

 

DefaultMapping(&Throttle, THR_FC);

 

... to my routine and it seems to do exactly what I was after (at least in device analyzer).

I'll test it in game and report back the result.

(Tomorrow as it's now quite late here and my better half won't take too kindly if I spin up a game at this hour!)

 

Again...many thanks

dmonds

Link to comment
Share on other sites

dmonds, OK, I reviewed DefaultMapping() for nesting issues as well as found my previous notes about how EventHandle() and DefaultMapping() should be called, and realize I got it wrong. Instead of calling DefaultMapping(), you should use the following command instead:

 

DefEventHandler(EV_HID_INPUT_DATA, &Throttle, THR_FC);

 

See below for the details....

 

How to call EventHandle() or DefaultMapping() manually

 

To call EventHandle() or DefaultMapping() manually, you need to call DefEventHandler(). DefEventHandler() is defined in target.tmh.

 

For example, in this discussion at SimHQ (Activate a layer by code), I explain how to call DefEventHandler() to manually change the layer (IO or UMD) using TARGET code instead of using the assigned IO or UMD shift buttons. dmonds, this is similar to your original question where you wanted to change an axis and get it to update. But in my case, I changed the IO or UMD layer status, and had to get TARGET to accept and update the change. I had to call DefEventHandler(), which does a few checks, and then calls EventHandle().

 

Here is my example from the SimHQ forums which explains the proper way to call DefEventHandler().

 

I am using the Warthog Throttle MSP button for my IO button, and the Warthog Throttle Boat Switch (BSF, BSB) for my U, M, and D modes. Hence, I have the following command in my script:

 

SetShiftButton(&Joystick, MSP, &Joystick, BSF, BSB);

 

You set the mode (I, O, U, M, or D) by manually setting the Throttle[<button>] value equal to 1 or 0 (1 is pressed, 0 is not pressed). Then call the DefEventHandler(). DefEventHandler() does a few important checks, and then calls EvenHandle() and EventHandle() then calls DefaultMapping() which handles all events. In this case, we are tricking TARGET into thinking that the MSP or Boat Switch changed.

 

In my example, I just used EXEC() routines connected to other buttons to fire off the change in IO or UMD. You can confirm it changed by pressing TG1 and seeing which number is pressed in an keyboard event viewer. Also, if you actually press the IO or UMD buttons, it will override this of course because it will set a new IO or UMD mode.

 

// Set Shift mode to I
MapKey(&Joystick, S1, EXEC("Throttle[MSP]=1; DefEventHandler(EV_HID_INPUT_DATA, &Throttle, MSP);"));
// Set Shift mode to O
MapKey(&Joystick, S2, EXEC("Throttle[MSP]=0; DefEventHandler(EV_HID_INPUT_DATA, &Throttle, MSP);"));

// Set UMD mode to U
MapKey(&Joystick, H1U, EXEC("Throttle[bSF]=1; DefEventHandler(EV_HID_INPUT_DATA, &Throttle, BSF);"));
// Set UMD mode to M (reset U mode)
MapKey(&Joystick, H1D, EXEC("Throttle[bSF]=0; DefEventHandler(EV_HID_INPUT_DATA, &Throttle, BSF);")); 
// Set UMD mode to M (reset D mode)
MapKey(&Joystick, H1L, EXEC("Throttle[bSB]=0; DefEventHandler(EV_HID_INPUT_DATA, &Throttle, BSB);")); 
// Set UMD mode to D
MapKey(&Joystick, H1R, EXEC("Throttle[bSB]=1; DefEventHandler(EV_HID_INPUT_DATA, &Throttle, BSB);"));

// Use TG1 to test the result
MapKeyIOUMD(&Joystick, TG1, 
'4',	// IU
'3',	// OU
'2',	// IM
'1',	// OM
'6',	// ID
'5'	// OD
);

 

For Resetting the U or D mode to M, any action that sets M mode will reset either U or D.

 

Originally I said just call DefaultMapping(), but because there are some important checks and configurations that occur in DefEventHandler(), calling DefaultMapping() or EventHandle() directly is a bad idea. This is what TARGET does for all new events as well (the background TARGET Service calls DefEvenHandler() in reaction to any new button press or axis change).

 

Also, in this example, I use EV_HID_INPUT_DATA, but it has no impact on the result. You could probably leave it as 0 and it would still work. But EV_HID_INPUT_DATA seems to be the proper value for a generic controller input change. See hid.tmh for the definition of EV_HID_INPUT_DATA, though it is not clearly explained. I think this is related to a legacy feature, or something that was not completely implemented. EventHandle() completely ignores it, and DefaultMapping() doesn't even receive this value.

 

Note, if you look at DefEventHandle() in target.tmh, you'll see it calls _evh(), but has no reference to EventHandle(). But, actually, _evh() is EventHandle(). This is set up in the if(Init(&EventHandle)) return 1; line at the start of every TARGET script. Go look at Init() in target.tmh if you want to see how it happens.

 

 

What about Nesting issues in DefaultMapping()

 

I am still unsure about this. DafaultMapping() does affect a few global variables, and makes some calls to Map() and ActKey(), which may cause some issues depending on how you call DefaultMapping() (or DefEventHandler() ). For example you know how there are certain times when you are not allowed to call SEQ, CHAIN, EXEC, TEMPO, etc. (read the TARGET manual on these commands for further explanation). This is exactly the kind of issue I am talking about. The first thing DefEventHandle() does is set alloc_locked = 1. This prevents ASMAlloc() from working to prevent nesting or other issues. ASMAlloc() is used by SEQ, CHAIN, etc. Search on ASMAlloc() in target.tmh and you'll see what I mean.

 

Anyway, the answer is, if you call DefEventHandle(), be aware your code may do something abnormal depending how or where you call it. If so, rethink how you are calling, and perhaps use the techniques described for calling SEQ, CHAIN, EXEC, TEMPO, etc. instead to call DefEventHandle().

 

 

 

Using Virtual Buttons for IO and UMD Shift Layers

 

Finally, I'll repost my comments from SimHQ on how to do the IO and UMD stuff without having to assign actual buttons. Virtual Buttons were discussed a lot in the early pages of the TARGET - Advanced programming forum topic. But here is a quick explaination of using virtual buttons to control IO and UMD purely in code, without having to assign a specific button to do it.

 

Here is an updated code example using VBI, VBU, and VBD (buttons I created for the Warthog Joystick) as virtual IO and UMD buttons. This code example is a complete program. Copy and paste into the TARGET script editor and it will run. I did this to point out that the defines for VBI, VBU and VBD must be outside of main(), or must be in your .ttm file. This example does not use a .ttm.

 

You have a maximum of 52 real + virtual buttons which are numbered 0 through 51. This maximum is defined by MAXKEYDATA in target.tmh. The Warthog Throttle uses all 52 of them, but the Warthog Joystick and most other TARGET supported devices use less than 52 buttons. You can see this in the defines.tmh file. Look at the "Warthog Joystick interface" definition. It has slots 0 - 18, assigned to real buttons, and 29 - 32 assigned to virtual buttons. So it is safe to use slots 40, 41, and 42. So I assigned VBI, VBU and VBD as 40, 41, and 42 and used them for the Warthog Joystick.

 

If Joystick[VBI] = 1, then the virtual button is "pressed", and = 0 means released. Now, everything you can do with a real button, you can do with VBI, VBU and VBD, including assigning them as the IO Shift and UMD Mode buttons.

 

include "target.tmh"

// Define virtual buttons for IO Shift and UMD mode for Warthog Joystick
define VBI	40	// Mode I virtual button
define VBU	41	// Mode U virtual button
define VBD	42	// Mode D virtual button

int main()
{
if(Init(&EventHandle)) return 1;

SetShiftButton(&Joystick, VBI, &Joystick, VBU, VBD, 0);		// IO Shift and UMD Setup (%DEV1, I button, $DEV, U, D, Toggle settings)

MapKey(&Joystick, S1, EXEC("Joystick[VBI]=1; DefEventHandler(EV_HID_INPUT_DATA, &Joystick, VBI);"));
MapKey(&Joystick, S2, EXEC("Joystick[VBI]=0; DefEventHandler(EV_HID_INPUT_DATA, &Joystick, VBI);"));

MapKey(&Joystick, H1U, EXEC("Joystick[VBU]=1; DefEventHandler(EV_HID_INPUT_DATA, &Joystick, VBU);"));
MapKey(&Joystick, H1D, EXEC("Joystick[VBU]=0; DefEventHandler(EV_HID_INPUT_DATA, &Joystick, VBU);")); 
MapKey(&Joystick, H1L, EXEC("Joystick[VBD]=0; DefEventHandler(EV_HID_INPUT_DATA, &Joystick, VBD);")); 
MapKey(&Joystick, H1R, EXEC("Joystick[VBD]=1; DefEventHandler(EV_HID_INPUT_DATA, &Joystick, VBD);")); 

// Test the result
MapKeyIOUMD(&Joystick, TG1, 
	'4',		// IU
	'3',		// OU
	'2',		// IM
	'1',		// OM
	'6',		// ID
	'5'		// OD
);		
}

int EventHandle(int type, alias o, int x)
{
DefaultMapping(&o, x);
}

 

If you want to use a different Thrustmaster device, make sure the numbers you choose do not conflict with the device definition in defines.tmh.

 

If you increase MAXKEYDATA in target.tmh to a larger value, you can create more virtual buttons, up to 256 total buttons (real + virtual) because the joy1[], joy2[], joy3[], etc. arrays defined in hid.tmh allow for up to 256 buttons total. Note, joy1[], joy2[], etc. are the actual arrays which &Joystick, &Throttle, &HCougar, etc. point to. See my post on SimHQ on Re: How to detect Shift key for more details on these arrays. Understanding them goes a long way toward understanding how to do all these more advanced TARGET scripts. That post also explains the layer_sw[] array, which is used to set the IO and UMD keys, for anyone that is curious.

 

Again, it is not my intent to redirect this conversation to SimHQ. If you read anything I linked to SimHQ and want to ask a question, please redirect the question here on the ED forums. There appears to be a much larger Thrustmaster TARGET audience here.


Edited by Drakoz
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...