Re: identifying the shift key without knowing what it is....
Yes, layer_sw[0] stores the value you are looking for, but how to use it is confusing. You have to understand the mapping of the &(devices) (e.g. &Joystick and &Throttle).
First some background. Bear with me here. Let's assume you have a Warthog Throttle and Joystick plugged in only (no other Thrustmaster devices). I'll use the Throttle as an example and the Throttle MSP button as the IO shift button.
&Throttle and &Joystick are simply referencing the memory addresses for joy1[0] and joy2[0]. Go look up joy1, joy2, etc. in hid.tmh (short joy1[296]). They are 296 element arrays of type short (a 16 bit or 2 byte integer). As each device is initialized by TARGET, the device is assigned to point to joy1, joy2, etc. in the order the devices are initialized. This is shown in the TARGET script editor output window as something like:
1: "Throttle -
HOTAS Warthog" - "USB\VID_........"
2: "Joystick -
HOTAS Warthog" - "USB\VID_......"
USB HID device "Throttle -
HOTAS Warthog" (USB\VID_.....) selected
USB HID device "Joystick -
HOTAS Warthog" (USB\VID_.....) selected
In the above, the Throttle is selected to be joy1, and the Joystick is selected to be joy2. It is the "selected" line that actually indicates a joy1 or joy2 has been assigned, not the 1: and 2: lines. For example if you used Configure(&Joystick, MODE_EXCLUDED); at the start of your script to exclude TARGET from using the Joystick, you would see:
1: "Throttle -
HOTAS Warthog" - "USB\VID_........"
2: "Joystick -
HOTAS Warthog" - "USB\VID_......"
USB HID device "Throttle -
HOTAS Warthog" (USB\VID_.....) selected
No "selected" line for the Joystick. Only &Throttle points to joy1.
What is joy1[] or what is Throttle[]? Both represent the same thing - Throttle is an alias of joy1 meaning both are interchangeable. Hence Throttle[] is a 296 element array of short, and points to the same array as joy1[]. Being an array, we can access elements as Throttle[1] or joy1[1]. Both will return the same value as they are aliases of each other.
MSP is our current IO Shift button, and MSP = 1 according to the define statements in defines.tmh (define MSP 1). So Throttle[MSP] is the same as Throttle[1], and always contains the current state of the MSP button (1 means MSP pressed, 0 means MSP released).
So how do we use this to determine what the current IO shift button is without knowing?
&Throttle is the address in memory of the Throttle[] array. The & simply means "the address of". So &Throttle is the address of Throttle[0]. Since Throttle[1] is the value of the MSP button, &Throttle+2 is the address of the value of the MSP button. Why 2? Because Throttle is an array of short, and each short is 2 bytes long. So the address of Throttle[0] is &Throttle, and the address of Throttle[1] is &Throttle+2.
layer_sw[0] contains the address of the current IO shift button. So layer_sw[0] = &Throttle+2 when the MSP button is the shift button. If you assigned FLAPU as the IO Shift button, then layer_sw[0] = &Throttle+42 because FLAPU = 21 in defines.tmh.
Try the following. Add this to a script file and run it (add it anywhere before the end of main() and run the script and it will print out in the TARGET Script editor window).
printf("layer_sw[0]: %x \xa", layer_sw[0]);
printf("&&Throttle: %x \xa", &&Throttle);
The result will be memory addresses in hexidecimal. For example, I got the following:
layer_sw[0]: 44ba42
&&Throttle: 44ba40
The && is needed to properly use &Throttle in this case because we want to work directly with the value of &Throttle. Forgive me, I'm a little off on my understanding of & and &&, but I know how to use them.
So if you write a routine that can calculate and find out that layer_sw[0] = &&Throttle+2, then you know that the shift button is MSP.Where you go from here depends on how you want to use this. That is why I explained it instead of just writing some code to do what you need. Now two examples - a complex one using EventHandle() and a simple example.
If you knew what the shift key was, you could simply use it in a script like my example above in the previous post to turn on/off the LED where I used o[MSP]. This is the same as saying Throttle[MSP]. But we don't know that it is MSP. We do know the address for the IO Shift button is layer_sw[0]. So we can get the same result with Throttle[layer_sw[0]-&&Throttle)] assuming we already knew that the IO shift key was on the Throttle. So in your EventHandle() routine, you could do the following:
include "target.tmh"
int main()
{
if(Init(&EventHandle)) return 1;
SetShiftButton(&Throttle, MSP, &Throttle, 0, 0, 0);
ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT-LED1)); // LED 1 off
//MapKey() statements here
}
int EventHandle(int type, alias o, int x)
{
int ShiftButtonVal = (layer_sw[0] - &&Throttle) >> 1;
printf("ShiftButtonVal: %d\xa", ShiftButtonVal);
if ((&o == &Throttle) & (x == ShiftButtonVal)) {
if (o[ShiftButtonVal]) { // If Shift key pressed,
printf("LED ON\xa");
ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT+LED1)); // LED 1 on
}
else { // When Shift key released,
printf("LED OFF\xa");
ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT-LED1)); // LED 1 off
}
}
DefaultMapping(&o, x);
}
Again, this assumes we know the IO Shift key is set to the Throttle (more on that below). In the above example, the user set IO Shift as the MSP key. I use an ActKey() in main() to turn off LED1 just to make sure it is off for the purposes of my example.
Anytime any event occurs (a key is pressed or an axis is moved), EventHandle() is called by the TARGET FAST service and passed the following:
- alias o is the device, so &o is the same as &Throttle if a key was pressed on the Throttle.
- x is the event that happened. E.g. if the MSP key was pressed, x = MSP = 1.
int ShiftButtonVal = (layer_sw[0] - &&Throttle) >> 1; calculates the value of the button that is the shift key. In this case, with MSP as the shift key, ShiftButtonVal should equal 1 now. (layer_sw[0] - &&Throttle) = 2, and the >> 1 effectively does a divice by 2 (a bit wise right shift by 2 bits performs a divide by 2).
Then we just use ShiftButtonVal as if we were saying MSP. ShiftButtonVal is interchangable anywhere you would say MSP.
If you want to use int ShiftButtonVal = (layer_sw[0] - &&Throttle) >> 1; globally, then you need to do the following - define ShiftButtonVal before main() and then calculate ShiftButtonVal at some point before you try to use it. Here's a simple example.
include "target.tmh"
int ShiftButtonVal;
int main()
{
if(Init(&EventHandle)) return 1;
SetShiftButton(&Throttle, MSP, &Throttle, 0, 0, 0);
ShiftButtonVal = FindShiftButton();
// now you can use ShiftButtonVal in your own functions defined below.
// MapKey() statements here
}
FindShiftButton()
{
return (layer_sw[0] - &&Throttle) >> 1);
}
int EventHandle(int type, alias o, int x)
{
DefaultMapping(&o, x);
}
To do this with the UMD mode button, you would use layer_sw[3] for the U mode button and layer_sw[6] for the D button.
The only thing left is to figure out which device the IO Shift button is on. TARGET only supports 9 different controllers, so you could just brute force an if else routine to figure it out. The trick is to understand that layer_sw[0] is a number that is no greater than 296 * 2 from the address of joy1, joy2, etc. So you could update FindShiftButton() above with the following:
alias ShiftButtonDev; // Global var that retains value of the device that has the shift button
int ShiftButtonVal; // Global var that retains value of the shift button
int FindShiftButton()
{
// Figure out which device has the shift button
int x = layer_sw[0];
if ( x >= &&Throttle & x <= &&Throttle + 596 ) &ShiftButtonDev = &Throttle;
else if ( x >= &&Joystick & x <= &&Joystick + 596 ) &ShiftButtonDev = &Joystick;
else if ( x >= &&HCougar & x <= &&HCougar + 596 ) &ShiftButtonDev = &HCougar;
// ... continue with all the devices you want to check
// Calculate the value of the shift button
ShiftButtonVal = (layer_sw[0] - &&Throttle) >> 1;
}
Putting it all together, here's my original EventHandle() routine using this to figure out when an unknown IO Shift key is pressed and turning an LED on and off as it is pressed.
include "target.tmh"
alias ShiftButtonDev; // Global var that retains value of the device that has the shift button
int ShiftButtonVal; // Global var that retains value of the shift button
int main()
{
if(Init(&EventHandle)) return 1;
SetShiftButton(&Throttle, MSP, &Throttle, 0, 0, 0);
ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT-LED1)); // LED 1 off
FindShiftButton(); // Go find the shift button
// MapKey() statements here
}
int FindShiftButton()
{
// Figure out which device has the shift button
int x = layer_sw[0];
if ( x >= &&Throttle & x <= &&Throttle + 596 ) &ShiftButtonDev = &Throttle;
else if ( x >= &&Joystick & x <= &&Joystick + 596 ) &ShiftButtonDev = &Joystick;
// Calculate the value of the shift button
ShiftButtonVal = (layer_sw[0] - &&Throttle) >> 1;
}
int EventHandle(int type, alias o, int x)
{
if ((&o == &ShiftButtonDev) & (x == ShiftButtonVal)) {
if (o[ShiftButtonVal]) { // If Shift key pressed,
printf("LED ON\xa");
ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT+LED1)); // LED 1 on
}
else { // When Shift key released,
printf("LED OFF\xa");
ActKey(PULSE+KEYON+LED(&Throttle, LED_ONOFF, LED_CURRENT-LED1)); // LED 1 off
}
}
DefaultMapping(&o, x);
}
Lengthy reply, but figuring this out as I wrote it helped me with greater understanding of &Throttle, &Joystick, joy1[], joy2[], etc. which is something I was working on this weekend anyway. The mud is a little more clear now.