Previous Thread
Next Thread
Print Thread
Rate This Thread
Hop To
Page 1 of 2 1 2
#4421705 - 05/20/18 09:39 AM Set an axis to a particular value  
Joined: May 2001
Posts: 468
Joao Muas Offline
Member
Joao Muas  Offline
Member

Joined: May 2001
Posts: 468
Portugal
Hello all.

I would like to be able to set an axis to a particular value with a key press.

I believe this was possibke with the old Cougar syntax, but now with Target I dont know how to achieve this.

The idea is to preset some power settings of a throttle axis to a key.

Ive been trying with the trimaxis and lock but to no success... there should be a set function for an axis value but I dont know how to do it...

Any ideas?

Thanks in advance.

Inline advert (2nd and 3rd post)

#4421819 - 05/21/18 01:44 AM Re: Set an axis to a particular value [Re: Joao Muas]  
Joined: Jul 2016
Posts: 61
Drakoz Offline
Junior Member
Drakoz  Offline
Junior Member

Joined: Jul 2016
Posts: 61
You can set a specific DirectX Axis to a value with DXAxis().

DXAxis(index, value)
Where index would the DirectX Axis you want to change (e.g. DX_X_AXIS, DX_SLIDER_AXIS, MOUSE_X_AXIS, etc.), and value is the value you want to set the axis to (-32767 to 32767 range). You have to use EXEC() to execute DXAxis().

It doesn't matter if the axis is already configured (mapped) to a physical axis. As long as that real axis doesn't move, the value set by DXAxis() will remain. The moment you move the physical axis, however, the value will immediately jump to the exact position of the physical axis.

Yes, it even works with the mouse X, Y, and Z (Z is the scroll wheel I think) where -32767 is (for X axis) the far left side of the screen and 32767 is the far right side.

Here is an example using the Warthog Throttle EAC Switch. In this example, I have mapped the DX_THROTTLE_AXIS to the Warthog Friction Control lever, but I have not mapped the DX_SLIDER_AXIS to anything. But if you run the following code, you will see you can set either axis to an absolute value, and as long as the Friction Control lever doesn't move, the value set for DX_THROTTLE_AXIS will stay at the value you set.

Code
// Throttle Friction Control
MapAxis(&Throttle, THR_FC, DX_THROTTLE_AXIS, AXIS_NORMAL, MAP_ABSOLUTE);
// No MapAxis() for DX_SLIDER_AXIS.  

// EAC Switch
MapKey(&Throttle, EACON, EXEC("DXAxis(DX_SLIDER_AXIS, 32000);"));
MapKey(&Throttle, EACOFF, EXEC("DXAxis(DX_SLIDER_AXIS, -32000);"));

// Radar Altimeter Switch
MapKey(&Throttle, RDRNRM, EXEC("DXAxis(DX_THROTTLE_AXIS, 32000);"));
MapKey(&Throttle, RDRDIS, EXEC("DXAxis(DX_THROTTLE_AXIS, -32000);"));


If you don't want the axis to jump as soon as you move the mapped axis, then of course you would use TrimDXAxis(). TrimDXAxis() actually uses DXAxis() to set the new value. Look in the target.tmh file in your scripts folder for TrimDXAxis() and DXAxis() and you wlll see some other examples of how DXAxis() works.

Note that TrimDXAxis() adds it's value to the value set by DXAxis() except that TrimDXAxis() has a range of -1024 to +1024. But this range maps to -32767 to +32767 for DXAxis(). So one point on TrimDXAxis() is equivalent to 32 points on the actual axis value.

Regards,
Michael

#4421987 - 05/21/18 07:43 PM Re: Set an axis to a particular value [Re: Drakoz]  
Joined: May 2001
Posts: 468
Joao Muas Offline
Member
Joao Muas  Offline
Member

Joined: May 2001
Posts: 468
Portugal
Exactly whar I was looking for...
I did look into target.tmh and tried DXSetAxis but it didnt work...
Let me try this this one now...

#4422021 - 05/21/18 10:37 PM Re: Set an axis to a particular value [Re: Joao Muas]  
Joined: Jul 2016
Posts: 61
Drakoz Offline
Junior Member
Drakoz  Offline
Junior Member

Joined: Jul 2016
Posts: 61
DXAxis() uses DXSetAxis(), but does some other important checks, calculations, and status updates first including setting Axis[index].pos which retains the current value of a DirectX axis, adding/subtracting the TrimAxis value, as well as performing the angular adjustment calculations if you have enabled a RotateDXAxis(). So you had the right idea, but just needed to move one level up from DXSetAxis() to DXAxis().

Also, maybe not what you are looking for, but don't forget to check out the MAP_ABSOLUTE vs. MAP_RELATIVE options for MapAxis() as it may have some use for what you are doing. For example, if you mapped an axis with MAP_RELATIVE, and then set the axis to a specific value with DXAxis(), then when you move the axis, it will move it relatively (add or subtract the movement of the physical axis to the set value). This is similar to using TrimAxis(), but might be easier then trying to calculate the Trim Value as a +/-1024 value.

One more thing that may be useful to your needs is being able to read the current position of any physical axis. For example, Throttle[THR_RIGHT] equals the current position of the Warthog Right Throttle Axis. Or Joystick[JOYX] equals the current position for the Warthog Joystick X axis. You could use this information in a script as follows to perform some custom math on a physical axis before setting the DirectX axis using DXAxis().

Code
int MyTHR_RIGHTAxisCalc() {
     int position = Throttle[THR_RIGHT];
     int result = (position * 0.5) + 32767;      // just a useless mathematical example which would move the THR_RIGHT axis to adjust DX_SLIDER_AXIS only from 0 to 32767.
     DXAxis(DX_SLIDER_AXIS, result);
}


If you do not map THR_RIGHT with a MapAxis() command and place the above code either in your EventHandle() routine, or in some other appropriate location where it will get executed (like an EXEC() or RECEC() function), you can control DX_SLIDER_AXIS with THR_RIGHT on your own terms, performing your own mathematical or logical manipulations. By doing this, you are doing exactly what the TARGET EventHandle() routine is supposed to do, but instead of depending on the TARGET DefaultMapping() function to do it based on MapKey() and MapAxis() commands, you are doing it manually.

For example, you might call the above function when ever a button is pressed. Below, when S1 is pressed, we execute the custom function once. If you want it to repeat, you need to use an REXEC() function.

Code
MapKey(&Joystick, S1, EXEC("MyTHR_RIGHTAxisCalc();"));


Or here is an example of placing the above routing in the EventHandle() so that when ever the Warthog Right Throttle moves, it will perform this calculation and set the DX_SLIDER_AXIS. Note, in this example, I would _not_ use a MapAxis(&Throttle, THR_RIGHT, DX_SLIDER_AXIS); because the following code would effectively do the same thing but with the custom calculation.

Code
int EventHandle(int type, alias o, int x)
{
	if ((&o == &Throttle) & (x == THR_RIGHT)) MyTHR_RIGHTAxisCalc();
		
	DefaultMapping(&o, x);
}


See my previous posts in the topic "How to Detect Shift key" (http://SimHQ.com/forum/ubbthreads.php/topics/4394499/how-to-detect-shift-key#Post4394499) for more details on how to add a function to the EventHandle() routine.

Regards,
Michael

#4422032 - 05/22/18 12:13 AM Re: Set an axis to a particular value [Re: Drakoz]  
Joined: May 2001
Posts: 468
Joao Muas Offline
Member
Joao Muas  Offline
Member

Joined: May 2001
Posts: 468
Portugal
Works a treat!! Thank you very much.

#4447222 - 11/06/18 03:12 PM Re: Set an axis to a particular value [Re: Joao Muas]  
Joined: May 2001
Posts: 468
Joao Muas Offline
Member
Joao Muas  Offline
Member

Joined: May 2001
Posts: 468
Portugal
Hi Drakoz,

Still on this very interesting subject, please tell me if this is possible:

To define a virtual axis and have it set by specific values using DXAxis().

For example, I want to control the engine rpm's of my aircraft by 3 specific preset values only, and because of that, I don't want to map any physical axis to it.

Let's say, I just need 3 engine rpm settings of

2600 rpm (max setting)
2400 rpm
1500 rpm

The question is, can I create a virtual axis, map it to the game engine rpm's and then preset 3 keys (doing the math) like:

MapKey(&Joystick, B5, EXEC("DXAxis(MY_VIRTUAL_AXIS, 32767);")); // max rpm 2600
MapKey(&Joystick, B6, EXEC("DXAxis(MY_VIRTUAL_AXIS, 27726);")); // hi rpm 2400
MapKey(&Joystick, B7, EXEC("DXAxis(MY_VIRTUAL_AXIS, 5041);")); // lo rpm 1500

If it is possible to create this virtual axis, how do I map the game controls to it?... Because the game needs to recognize it as an axis... if I press one of the B5, B6 or B7 keys, the game should recognize it, right?

Thank for your best advice.

#4447359 - 11/07/18 10:37 AM Re: Set an axis to a particular value [Re: Joao Muas]  
Joined: Jul 2016
Posts: 61
Drakoz Offline
Junior Member
Drakoz  Offline
Junior Member

Joined: Jul 2016
Posts: 61
There are only 8 DX axes available for a single game controller (e.g. the "Thrustmaster Combined" controller in this case, but this is true with all game controllers). So you can only affect those 8 axes. There is no provisions in Windows to create a virtual axis.

All you can do is what I explained in my original post about DXAxis(). You don't have to assign a Thrustmaster axis to the DirectX axis. DXAxis() commands can affect the axis without such an assignment. But if you want to assign 8 Thrustmaster axis to all 8 DirectX axis, then that's it. You can't create a 9th axis.


More advanced options to do what you want...

One possible solution to this is to use a different programming language that can create multiple virtual game controllers. AutoHotKey (AHK) is one. With the help of vJoy, AHK can receive an input from any game device, keyboard, or mouse and remap that to any other game controller, keyboard or mouse output. AHK uses vJoy to create virtual game controllers. Then AHK can control those virtual controllers, including doing exactly what you would like to do.

Link to AutoHotKey: https://www.autohotkey.com
Link to vJoy: http://vjoystick.sourceforge.net/site/

In truth, AHK can do most of what TARGET does, and more. AHK isn't Thrustmaster specific, so it can take inputs from any DirectX device and combine that in a single script to control as many virtual (vJoy) game controllers you want, as well as do keyboard and mouse events.

I have long considered moving to AHK instead of TARGET. AHK is a glorified macro scripting program. It is generally based on Visual Basic, so it is a complete programming language but with commands to make it easier to do keyboard, mouse, and game controller events. TARGET is probably easier to use out of the box, but AHK ultimately has more overall generic capability, especially since it can do what TARGET does, but for all your game controllers.

Another option is Joystick Gremlin (https://whitemagic.github.io/JoystickGremlin/overview/). I only just learned about this one. It too uses vJoy to create virtual game controllers and do the kind of stuff TARGET does. It appears Joystick Gremlin has a UI for basic configuration, but it's underlying language is Python. Meaning, you can do custom programming in Python just like you can in TARGET or AHK.

#4447377 - 11/07/18 11:57 AM Re: Set an axis to a particular value [Re: Drakoz]  
Joined: May 2001
Posts: 468
Joao Muas Offline
Member
Joao Muas  Offline
Member

Joined: May 2001
Posts: 468
Portugal
First, thank you for your detailed answer.

Just focusing on the first part, since (for now) I don't intend to delve too much into AHK/vJoy.

I'm using the T16000, which as you know only uses 4 axis (not counting the mouse), which are:

DX_X_AXIS (JOYX)
DX_Y_AXIS (JOYY)
DX_ZROT_AXIS (RUDDER)
DX_SLIDER_AXIS (THROTTLE)

Now, can I use DX_Z_AXIS to do what I want to do? How can I get my T16000 to generate an input to an axis it doesn't have?...

MapKey(&T16000, B5, EXEC("DXAxis(DX_Z_AXIS, 32767);"));

I tried the above, but it didn't seem to work... maybe I'm missing something here...

#4447429 - 11/07/18 06:34 PM Re: Set an axis to a particular value [Re: Joao Muas]  
Joined: May 2001
Posts: 468
Joao Muas Offline
Member
Joao Muas  Offline
Member

Joined: May 2001
Posts: 468
Portugal
Originally Posted by Joao Muas
MapKey(&T16000, B5, EXEC("DXAxis(DX_Z_AXIS, 32767);"));

I tried the above, but it didn't seem to work... maybe I'm missing something here...

Not true!! This actually works! I don't know what I did wrong when I tried it first time, but now I'm having a 5th axis controlled by buttons.

What doesn't work is if I try to get one physical joystick axis to control 2 axis at the Thrustmaster Combined at the same time... only one will work...

For example if I want to control 2 axis with different response curves with one physical axis, it seems it can only recognize one of them...


By the way, I checked that JoystickGremlin software, and it seems very interesting, probably more complete than Target, and with an interface too.
It's worth checking out.

#4447487 - 11/08/18 12:27 AM Re: Set an axis to a particular value [Re: Joao Muas]  
Joined: Jul 2016
Posts: 61
Drakoz Offline
Junior Member
Drakoz  Offline
Junior Member

Joined: Jul 2016
Posts: 61
Probably to control two DX axis with one Thrustmaster Axis requires fully custom programming added to the EventHandle() routine as in my example above. I'll copy it again here:

Code
int EventHandle(int type, alias o, int x)
{
	if ((&o == &Throttle) & (x == THR_RIGHT)) MyTHR_RIGHTAxisCalc();
		
	DefaultMapping(&o, x);
}


Again, when a change is made to the Warthog Right Throttle, EventHandle is called with &o = &Throttle, and x = THR_RIGHT. Hence the if statement above will call MyTHR_RIGHTAxisCalc(). MyTHR_RIGHTAxisCalc() just needs to take the current value of the axis, run it through some math (to manually apply curves, etc.) and set the unused DX axis to the value you want using DXAxis(). You only have to do this with one of the two DX axis. Set up the other DX axis using the default TARGET routines for assigning it and setting curve, etc.

I believe everything in this thread explains the details you need to figure this out. If not, ask of course.

#4447544 - 11/08/18 10:08 AM Re: Set an axis to a particular value [Re: Drakoz]  
Joined: May 2001
Posts: 468
Joao Muas Offline
Member
Joao Muas  Offline
Member

Joined: May 2001
Posts: 468
Portugal
Very well noted.

It is not a priority at the moment, but I will try it out soon.

Thank you!

#4458154 - 01/21/19 02:23 PM Re: Set an axis to a particular value [Re: Drakoz]  
Joined: May 2001
Posts: 468
Joao Muas Offline
Member
Joao Muas  Offline
Member

Joined: May 2001
Posts: 468
Portugal
Originally Posted by Drakoz
Probably to control two DX axis with one Thrustmaster Axis requires fully custom programming added to the EventHandle() routine as in my example above. I'll copy it again here:

Code
int EventHandle(int type, alias o, int x)
{
	if ((&o == &Throttle) & (x == THR_RIGHT)) MyTHR_RIGHTAxisCalc();
		
	DefaultMapping(&o, x);
}


Again, when a change is made to the Warthog Right Throttle, EventHandle is called with &o = &Throttle, and x = THR_RIGHT. Hence the if statement above will call MyTHR_RIGHTAxisCalc(). MyTHR_RIGHTAxisCalc() just needs to take the current value of the axis, run it through some math (to manually apply curves, etc.) and set the unused DX axis to the value you want using DXAxis(). You only have to do this with one of the two DX axis. Set up the other DX axis using the default TARGET routines for assigning it and setting curve, etc.

I believe everything in this thread explains the details you need to figure this out. If not, ask of course.


Drakoz,

Still on this super interesting subject, I need some guidance on the following, please...

Let's say I have this code:
Code
include "target.tmh"

int main()
{
	.
	.
	.

	MapAxis(&T16000, THR, DX_SLIDER_AXIS, AXIS_REVERSED, MAP_ABSOLUTE);		
}
	
// Sync Axis routine

int SyncAxis() {
     int position = -T16000[THR] + 32767; 
     int result = position * 1.0225 - 32767; // some math to fine tune the result
     DXAxis(DX_Z_AXIS, result);
     DXAxis(DX_THROTTLE_AXIS, result);     
}

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

	if ((&o == &T16000) & (x == THR)) SyncAxis();
		
}
As you can see I got two extra axis that generate values along with my only slider, THR, apart from the DX_SLIDER_AXIS set by the MapAxis statement.
But now I want to set a button that "OFF" the sync and get my THR to move only DX_Z_AXIS. How can this be done?
I guess I can't use the MapAxis statement anymore... please advise.

And now a question:
Is it possible to read the value of an axis previously set by DXAxis, and not by the physical axis position?
I mean, is not the T16000[THR] value I want to know, but the value set by DXAxis on the DX axis assigned to THR by MapAxis.


BIG THANK YOU.

#4458228 - 01/22/19 12:53 AM Re: Set an axis to a particular value [Re: Joao Muas]  
Joined: Jul 2016
Posts: 61
Drakoz Offline
Junior Member
Drakoz  Offline
Junior Member

Joined: Jul 2016
Posts: 61
To create the "OFF" state, you need a global variable, and then use that global variable in SyncAxis() to change how you affect the axis as well as remap if THR controls DX_SLIDER_AXIS. See the code below. I commented the code to explain what I am doing. I didn't compile or test this code. So I might have a syntax error or minor mistake.

Code
// Set a global variable to control SyncAxis()
int EnableSyncAxis = 1;		// SyncAxis() enabled by default

int main()
{
	// Set the default axis that THR should control.
	MapAxis(&T16000, THR, DX_SLIDER_AXIS, AXIS_REVERSED, MAP_ABSOLUTE);		
	
	// Using the Cougar EAC toggle switch - Enable/disable SyncAxis
	// Following EXEC commands will set EnableSyncAxis as needed when the EAC 
	// toggle switch is flipped.
	MapKey(&Throttle, EACON, EXEC("EnableSyncAxis = 1;"));	// Enable SyncAxis()
	MapKey(&Throttle, EACOFF, EXEC("EnableSyncAxis = 0;"));	// Disable SyncAxis()
}

int SyncAxis() {
	int position = -T16000[THR] + 32767; 
	int result = position * 1.0225 - 32767; // some math to fine tune the result
	// If EnableSyncAxis = 1, then change DX_Z_AXIS and DX_THROTTLE_AXIS axis and re-enable THR to move DX_SLIDER_AXIS
	if (EnableSyncAxis) {
		DXAxis(DX_Z_AXIS, result);
		DXAxis(DX_THROTTLE_AXIS, result);  
		// Make sure THR controls DX_SLIDER_AXIS. If SyncAxis() was just enabled, 
		// this command will remap THR to drive DX_SLIDER_AXIS.
		MapAxis(&T16000, THR, DX_SLIDER_AXIS, AXIS_REVERSED, MAP_ABSOLUTE);
	}
	// Else, if EnableSyncAxis = 0, then only move DX_Z_AXIS, and disable THR from moving DX_SLIDER_AXIS
	else {
		DXAxis(DX_Z_AXIS, result);
		// Unmap DX_SLIDER_AXIS
		MapAxis(&T16000, THR, 0, 0, 0);  // THR now controls no axis.  
	}
}

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

	if ((&o == &T16000) & (x == THR)) SyncAxis();
}


Some additional notes...

Global variables should be set before main() (e.g. EnableSyhncAxis).

You can use MapAxix() any time and anywhere in the script. So as shown below, I issue MapAxis() to de-map and re-map THR to control DX_SLIDER_AXIS in the SyncAxis() function.

You could also de-map and re-map THR in the EXEC commands in the mapping for EACON and EACOFF as follows:

Code
	MapKey(&Throttle, EACON, EXEC(
		"EnableSyncAxis = 1;"
		"MapAxis(&T16000, THR, DX_SLIDER_AXIS, AXIS_REVERSED, MAP_ABSOLUTE);"
	));	// Enable SyncAxis()
	MapKey(&Throttle, EACOFF, EXEC(
		"EnableSyncAxis = 0;"
		"MapAxis(&T16000, THR, 0, 0, 0);"	// THR now controls no axis.
	));	// Disable SyncAxis()


Don't forget to remove the MapAxis() commands from SyncAxis().

#4458231 - 01/22/19 01:20 AM Re: Set an axis to a particular value [Re: Joao Muas]  
Joined: Jul 2016
Posts: 61
Drakoz Offline
Junior Member
Drakoz  Offline
Junior Member

Joined: Jul 2016
Posts: 61
Originally Posted by Joao Muas
And now a question:
Is it possible to read the value of an axis previously set by DXAxis, and not by the physical axis position?
I mean, is not the T16000[THR] value I want to know, but the value set by DXAxis on the DX axis assigned to THR by MapAxis.


Look at target.tmh for the definition of DXAxis(). Just before this function, you'll see an array called Axis[] of type DXAxisStatus. Here is the definition of this array from target.tmh:

Code
struct DXAxisStatus
{
	int pos, trim;
	char coupling;
	char lock;
	float cos, sin;
}
DXAxisStatus Axis[12]; 


It looks like Axis[index].pos is equal to the position of the DirectX Axis defined by "index" (where index is a axis name like DX_Z_AXIS).

See defines.tmh (about line 804) and you'll find the list of DX Axis names and the index number (e.g. DX_X_AXIS is 0). Just FYI. You only need the axis names.

So the following should return the current position of DX_X_AXIS.

XAxisPos = Axis[DX_X_AXIS].pos;

Note,
- Axis[index].pos is the axis position.
- Axis[index].trim is the trim value if the user sets a trim value.
- Axis[index].coupling is used if the X/Y axis are rotated using RotateDXAxis.
- Axis[index].lock is used to tell if the DX Axis is currently locked (to prevent changing it at the wrong time I assume)
- Axis[index].cos and Axis[index].sin are probably the pre-calculated values for rotating the X/Y axis when enabled with RotateDXAxis.

So, we really only care about .pos.

See DXAxis() and DXSetAxis() in target.tmh for more about all this.

I've never used Axis.pos, but looking at DXAxis(), I think I've got this all correct.

Last edited by Drakoz; 01/25/19 06:58 AM. Reason: Fixed Axis.pos[index] to read Axis[index].pos, etc.
#4458254 - 01/22/19 10:49 AM Re: Set an axis to a particular value [Re: Drakoz]  
Joined: May 2001
Posts: 468
Joao Muas Offline
Member
Joao Muas  Offline
Member

Joined: May 2001
Posts: 468
Portugal
The first part seems easier than I thought, I didn't know we could de-map and re-map an axis that way. It's very straight forward.

As for the DXAxis() values, I would never get there, but with your explanation seems very easy too.

I will try those and revert back.

THANK YOU!!

#4458362 - 01/23/19 11:15 AM Re: Set an axis to a particular value [Re: Joao Muas]  
Joined: May 2001
Posts: 468
Joao Muas Offline
Member
Joao Muas  Offline
Member

Joined: May 2001
Posts: 468
Portugal
SUCCESS!!

The axis un-mapping and re-mapping solution works successfully, but... it works definitely better using EXEC commands in the mapping for the buttons.
I noticed there is a side effect when un-mapping and re-mapping using a function, for the first instant move of the new re-mapped axis, there is still a slightly spillover to one of the others.
This can be easily seen on the TARGET axis analyzer. So EXEC commands are definitely the way to go, as there is no side effect whatsoever.

Now there is a small issue that I would like to sort out if possible - the "jumping" of a new remapped axis to the current physical axis position.
Here is an example to better illustrate the issue: I have THR mapped to DX_Z_AXIS, and set it at the desired position; then by the EXEC command from a button press, I will un-map it and re-map it to DX_SLIDER_AXIS. What immediately happens is that as soon as I move THR, the DX_SLIDER_AXIS immediately "jumps" to the physical position of THR which causes an undesired result.
Instead of jumping to the physical axis position, I wanted DX_SLIDER_AXIS to remain at its current position until THR sweeps the range and "captures" it's value. Only then, the new mapping should take effect. That would be the logic of it, and it will sure provide a smooth operation. Is there any way to do it? If there is, then this solution will get from good to perfect. Maybe if we read the DX_Z_AXIS value, and then lock it; when T16000[THR] is equal to the DX_Z_AXIS value, we unlock it, and allow the new mapping to perform. I tried it but to I'm pretty sure I didn't get it right, also because...

...on the second question, I'm afraid I didn't get Axis.pos[DX_Z_AXIS] to work... I always got an index error. By looking at target.tmh, I tried Axis[DX_Z_AXIS].pos but the result was the same...
This goes definitely beyond my very limited programming skills.

What do you think?

#4458587 - 01/25/19 10:45 AM Re: Set an axis to a particular value [Re: Joao Muas]  
Joined: Jul 2016
Posts: 61
Drakoz Offline
Junior Member
Drakoz  Offline
Junior Member

Joined: Jul 2016
Posts: 61
Originally Posted by Joao Muas

The axis un-mapping and re-mapping solution works successfully, but... it works definitely better using EXEC commands in the mapping for the buttons.
.....


Oh, right. That's because just changing the EnableSyncAxis variable to enable or disable the SyncAxis() function doesn't actually remap the axis. That is done in the SyncAxis() function, which doesn't get called right away. I should have made a call to the SyncAxis() function to actually remap the axis. But as you found, my second example did it OK.


Quote

Now there is a small issue that I would like to sort out if possible - the "jumping" of a new remapped axis to the current physical axis position.
....


Yes, this can be done. There are several ways you could do it. I'll give an example below.

Quote
...on the second question, I'm afraid I didn't get Axis.pos[DX_Z_AXIS] to work... I always got an index error. By looking at target.tmh, I tried Axis[DX_Z_AXIS].pos but the result was the same...
This goes definitely beyond my very limited programming skills.


First, yes, I had the syntax wrong. As you pointed out, it should be Axis[index].pos. I have fixed my original post on this.

Second, I did a test where I created a script to print out the current Warthog Throttle THR_FC and DirectX DX_SLIDER_AXIS positions (using Axis[DX_SLIDER_AXIS].pos) on the TARGET console. This is a complete and tested script. Copy and paste it into TARGET, change it to match your T16000 Throttle, and you can see how Axis[index].pos works.

Code
// Script to print out the Throttle THR_FC position and the DX_SLIDER_AXIS position
// when the Warthog Throttle LTB button is pressed. 
include "target.tmh"
int main()
{
	if(Init(&EventHandle)) return 1;

	// Throttle Friction Control
	MapAxis(&Throttle, THR_FC, DX_SLIDER_AXIS, AXIS_NORMAL, MAP_ABSOLUTE);
	
	// Left Throttle Button
	//  Call a function to print out axis positions
	MapKey(&Throttle, LTB, EXEC("AxisPosition();"));
}

// Printout the current THR_FC axis position and the current DX_SLIDER_AXIS axis position.
//   They should match since I mapped THR_FC to control DX_SLIDER_AXIS.
//   Throttle[THR_FC] will always return the current Warthog THR_FC position.
//   Axis[DX_SLIDER_AXIS].pos will always return the current position of the DirectX Slider Axis.
int AxisPosition()
{
	printf("Throttle[THR_FC]=%d,  DXAxis[DX_SLIDER_AXIS].pos=%d\xa", Throttle[THR_FC], Axis[DX_SLIDER_AXIS].pos);
}

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



Here is an example of how to use a button (the LTB button on my Warthog Throttle) to swap the THR_FC axis to control the DX_SLIDER_AXIS or DX_Z_AXIS. When swapping the axis THR_FC controls, this script will wait for you to move the THR_FC axis to the position that matches the previous position of DX_SLIDER_AXIS or DX_Z_AXIS (as you wanted) before it will allow THR_FC to control the newly selected axis. Meaning, the script will sync the THR_FC axis to the DX axis preventing the axis from jumping.

This script is a bit more messy than I would like. But it demonstrates the concept. There are better ways to do it. This is just the first method that came to mind. You may want to use the Beep function that I have mentioned in other posts to beep when the axis are in sync. I did a similar script where one axis was controlling 3 different controls in a sim (Train Sim World) and I used the beep to tell me when the Throttle axis was in sync with the game. It helps a lot. Or if you have any Thrustmaster device with LEDs, you could flash the LEDs (like change the backlight intensity quickly) to give feedback that you have synced the axis. The beep or flashing LEDs helps prevent going to far past the sync point accidentally.

I tested this script. You should be able to copy and paste it in to TARGET and run it without problems after you change the axis and swap button to match your T16000 throttle .

Code
// Script to demonstrate using Warthog THR_FC to control two different
// DirectX axis, and to sync to the DirectX axis position when swapping to 
// prevent the axis from jumping after swapping.  
include "target.tmh"
int main()
{
	if(Init(&EventHandle)) return 1;

	// Throttle Friction Control
	MapAxis(&Throttle, THR_FC, DX_SLIDER_AXIS, AXIS_NORMAL, MAP_ABSOLUTE);
	
	// Left Throttle Button
	//  Call a function to print out axis positions
	MapKey(&Throttle, LTB, EXEC("SwapAxis();"));
}

// Swap THR_FC between controlling DX_SLIDER_AXIS and DX_Z_AXIS
int CurrentAxis = DX_SLIDER_AXIS;	// Remember which DX axis we are controlling, defaults to DX_SLIDER_AXIS
int CurrAxisInSync = 1;				// 1 means currently selected DirectX axis is in sync with controller axis
int PrevAxisPosition;				// Stores previous THR_FC axis position at last swap (used in EventHandle)
int SwapAxis()
{
	if (CurrentAxis == DX_SLIDER_AXIS) {	// Swap to DX_Z_AXIS
		MapAxis(&Throttle, THR_FC, DX_Z_AXIS, AXIS_NORMAL, MAP_ABSOLUTE);
		CurrentAxis = DX_Z_AXIS;
		printf("SwapAxis:  CurrentAxis = DX_Z_AXIS,  PrevAxisPosition=%d\xa", Throttle[THR_FC]);
	}
	else {									// Swap to DX_SLIDER_AXIS
		MapAxis(&Throttle, THR_FC, DX_SLIDER_AXIS, AXIS_NORMAL, MAP_ABSOLUTE);
		CurrentAxis = DX_SLIDER_AXIS;
		printf("SwapAxis:  CurrentAxis = DX_SLIDER_AXIS,  PrevAxisPosition=%d\xa", Throttle[THR_FC]);
	}
	CurrAxisInSync = 0;		// axis not in sync until we test this in EventHandle()
	PrevAxisPosition = Throttle[THR_FC];	// Remember THR_FC position for use in EventHandle
}

int EventHandle(int type, alias o, int x)
{
	// For the Warthog Throttle THR_FC axis, and only if not in sync...
	if ((&o == &Throttle) & (x == THR_FC) & (!CurrAxisInSync)) {
		// Figure out when THR_FC reaches or passes DirectX axis so we can call it synced and enable axis control.
		if ( ((PrevAxisPosition <= Axis[CurrentAxis].pos) & (o[x] >= Axis[CurrentAxis].pos)) |
		     ((PrevAxisPosition >= Axis[CurrentAxis].pos) & (o[x] <= Axis[CurrentAxis].pos)) ) 
		{
			CurrAxisInSync = 1;		// ... Axis and DXAxis are in sync
			printf("EventHandle: CurrAxisInSync = Yes,   Axis=%d, DXAxis=%d\xa", o[x], Axis[CurrentAxis].pos);
		} 
		if (CurrAxisInSync) {		// only call DefaultMapping() if THR_FC axis and DXAxis are in sync.
			DefaultMapping(&o, x);
		}
	}
	// For all other controls...
	else {
		DefaultMapping(&o, x);
	}
}

#4458619 - 01/25/19 04:00 PM Re: Set an axis to a particular value [Re: Drakoz]  
Joined: May 2001
Posts: 468
Joao Muas Offline
Member
Joao Muas  Offline
Member

Joined: May 2001
Posts: 468
Portugal
Great!!

Let me try this out, and I will revert back.

Thank you!!

#4458643 - 01/25/19 06:17 PM Re: Set an axis to a particular value [Re: Joao Muas]  
Joined: Jul 2016
Posts: 61
Drakoz Offline
Junior Member
Drakoz  Offline
Junior Member

Joined: Jul 2016
Posts: 61
Over night I realized a much better way to do this that doesn't require all the code in EventHandle(). I try to avoid adding any more code to EventHandle than absolutely needed since EventHandle() gets called with every single Thrustmaster controller event.

I'll figure it out and post later, but the basic concept is as follows:

A new function called MapAxisSync() is created and can be used just like MapAxis(), with the same parameters (and a couple more to help configure how syncing should work). The difference between MapAxis() and MapAxisSync() is MapAxisSync() will de-map the Thrustmaster axis immediately from it's current DX Axis, and then only remap the axis to the new DX Axis once the Thrustmaster axis and the DX Axis are in sync.

To do this, MapAxisSync() would demap the TM axis, then remap it using AXMAP1() or AXMAP2() (haven't decided which mode is best yet - zones or directional movement) to call an EXEC() every time the TM Axis moves that would run a function to watch for the axes to be in sync. E.g. EXEC("MapAxisInSync(...);"). The AXMAP1 or AXMAP2 function would call MapAxisInSync() approximately ever 1 to 2 percent of TM axis travel using EXEC(), and MapAxisInSync() would check to see if the TM Axis is within 1 to 2 percent of the position of the DX Axis. If it is, then MapAxisInSync() would remove the AXMAP definition and perform the MapAxis() call to now map the TM Axis to the new DX Axis. Hence the final MapAxis() command would only occur when the TM Axis and the DX Axis are synchronized. No jumping.

This method requires no code in EventHandle(), it leverages mostly existing TARGET functions, and it works without any concern for the previous axis that the TM axis was assigned to. My previous method above uses several global variables to remember what the previous mapped axis and position was, but with MapAxisSync() and MapAxisInSync(), we don't care about the previous mapping of the TM Axis. Hence no global variables need to be defined either. A much cleaner way to do it. Also, the generic functions MapAxisSync() and MapAxisInSync() would work with any Thrustmaster device and axis without having to edit them for the T16000 or the Warthog Throttle for example.

I don't know if I'll get a chance to write these functions any time soon, so I wanted to give the suggestion and maybe you can figure it out if you want.

The only hard part is deciding how you want to tell if the TM Axis and the DX Axis are in sync. Notice in my previous example, I have a long and complicated if statement in EventHandle() to do this. You can't just say if (TM Axis == DX Axis) because if you move the TM Axis quickly, it will not register a value that is exactly equal to the current DX Axis. So you have to look for the case where the TM Axis has passed through the DX Axis. So if TM Axis starts out less than DX Axis, you need to look for the case where TM Axis has become >= DX Axis. Or vice versa. AXMAP1() can help with this as it is the directional AXMAP function. It would call MapAxisInSync() only when TM Axis is moved toward DX Axis.

Or, alternatively, you can use zones using AXMAP2() set to approximately ever 1% to 2% of the axis travel (50 to 100 equally spaced zones). Every time you cross a zone determined by AXMAP2(), you perform a check to see if the TM Axis is close to DX Axis. If the zones are too small, you might miss the event, but with zones that are 1-2% of travel, it should catch the event where TM Axis and DX Axis are close to each other every time. This is the easier way to do it, but I don't know if it will be 100% reliable. The 1-2% zone size is still small enough to prevent radical jumping of the DX Axis.

#4458664 - 01/25/19 08:44 PM Re: Set an axis to a particular value [Re: Drakoz]  
Joined: May 2001
Posts: 468
Joao Muas Offline
Member
Joao Muas  Offline
Member

Joined: May 2001
Posts: 468
Portugal
In my simplistic mind I was about to ask, can't we just do it like this...

1) De-map de "previous" axis
2) Check if (TM Axis == DX Axis)
3) If yes, then re-map to the new axis

But you just said that a "high speed pass" might not capture it... I didn't think of that, but this is what I was trying to do...

How about if we check if ((TM Axis - DX Axis < 3276) , like within 2.5% to each side of the DX Axis value...

I might try your suggestions though, it never came to mind using the AXMAP statements.

Page 1 of 2 1 2

Moderated by  RacerGT 

Quick Search
Recent Articles
Support SimHQ

If you shop on Amazon use this Amazon link to support SimHQ
.
Social


Recent Topics
Carnival Cruise Ship Fire....... Again
by F4UDash4. 03/26/24 05:58 PM
Baltimore Bridge Collapse
by F4UDash4. 03/26/24 05:51 PM
The Oldest WWII Veterans
by F4UDash4. 03/24/24 09:21 PM
They got fired after this.
by Wigean. 03/20/24 08:19 PM
Grown ups joke time
by NoFlyBoy. 03/18/24 10:34 PM
Anyone Heard from Nimits?
by F4UDash4. 03/18/24 10:01 PM
RIP Gemini/Apollo astronaut Tom Stafford
by semmern. 03/18/24 02:14 PM
10 years after 3/8/2014
by NoFlyBoy. 03/17/24 10:25 AM
Copyright 1997-2016, SimHQ Inc. All Rights Reserved.

Powered by UBB.threads™ PHP Forum Software 7.6.0