Home Fries Posted June 15, 2024 Posted June 15, 2024 (edited) I'm currently working on version 3.0 of my CTS script, and one of the things I want to do to minimize the stack size (for expandability) is to use aliases for each controller set instead of having separate routines for mapping the Warthog, Cougar, F-18 stick, etc. I tried to create the following code as a proof of concept for being able to assign aliases to the already existing aliases of &Joystick, &Throttle, and &HCougar: alias CJoy0="Joystick"; alias CJoy1="HCougar"; alias CThr0="Throttle"; alias CThr1="HCougar"; int Test_Init(int secondary = 0) { if (secondary) { MapAxis (&CJoy1, JOYX, DX_X_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&CJoy1, JOYY, DX_Y_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&CThr1, THR_LEFT, DX_THROTTLE_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&CThr1, THR_RIGHT, DX_Z_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); } else { MapAxis (&CJoy0, JOYX, DX_X_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&CJoy0, JOYY, DX_Y_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&CThr0, THR_LEFT, DX_THROTTLE_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&CThr0, THR_RIGHT, DX_Z_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); } } int main() { Test_Init(0); } The error I get is: Runtime Error: Index out of bounds for: devicedata in GetDeviceData ( line 329 in target.tmh ) and the routine in target.tmh is int GetDeviceData(alias dev) // fill global devdata alias based on device name (joy1, joy2,...) { char t; Dim(&t, 16); strname(&dev, &t); Map(&devdata, &&devicedata[t[3]-'0']); } note: Map(&devdata, &&devicedata[t[3]-'0']); is line 329. I've also tried assigning the CJoy/CThr values as chars (dim 15) and I get the same problem. I'm unsure what needs to be done because my aliases don't seem to map properly to an array. I'm open to any suggestions. Being able to crack this would go a long way to modularizing my code for version 3.0. Edited June 15, 2024 by Home Fries -Home Fries My DCS Files and Skins My DCS TARGET Profile for Cougar or Warthog and MFDs F-14B LANTIRN Guide
Drakoz Posted June 15, 2024 Posted June 15, 2024 (edited) It has been a while since I looked this deep into target.tmh and the Map() function, so I am mostly guessing, but.... The issue might be the index for [T[3]-'0']. If subtracting '0' from the value at T[3] is going negative, that would cause an error. Or more likely, the value T[3], regardless of -'0' is too high. The reason for this is probably because these routines are meant to work with names like Joy0, Joy1, not CJoy0, CJoy1. T[3] is supposed to be 0, 1 for Joy0, Joy1, but for CJoy0, CJoy1, T[3] is y. 'y'-'0' is too high of an index number for devicedata[]. I assume you understand, but just in case... The purpose of the -'0' is to take the character '0' or '1' and subtract the character '0' which converts the ASCII character '0' or '1' to a number, 0 or 1 in order to index the array devicedata. '0' is 48 on the ASCII table, '1' is 49. Hence, '1'-'0' = 1 decimal. But 'y' is 121. 'y'-'0'=73. This exceeds the bounds for devicedata[]. Here is the definition of devicedata[] from target.tmh. It is only a 16 element array. So devicedata[73] would cause "index out of bounds". sDevice devicedata[16], devdata; For GetDeviceData() to work, you must use names like abc1, xyz2, Joy0. The number must always be the 4th character in the name. Edited June 15, 2024 by Drakoz
Home Fries Posted June 16, 2024 Author Posted June 16, 2024 Thanks. I'll try it out! -Home Fries My DCS Files and Skins My DCS TARGET Profile for Cougar or Warthog and MFDs F-14B LANTIRN Guide
Home Fries Posted June 16, 2024 Author Posted June 16, 2024 (edited) Ok, I shortened the variable names to 4 characters with the last character being the number 0 or 1 as before. I was still getting the index out of bounds using "alias", but converted the variable to char (dimmed at 15) and I was able to compile without the index error. Problem is now that I cant get the commands to carry, even though it looks like it should work. I'm sure I'm missing a subtlety somewhere. I don't have a lot of experience working with alias/register logic. Here's the new code: char CJy0; char CJy1; char CTh0; char CTh1; //alias CJy0="Joystick"; //alias CJy1="HCougar"; //alias CTh0="Throttle"; //alias CTh1="HCougar"; int main() { Dim(&CJy0, 15); Dim(&CJy1, 15); Dim(&CTh0, 15); Dim(&CTh1, 15); sprintf (&CJy0, "Joystick"); sprintf (&CJy1, "HCougar"); sprintf (&CTh0, "Throttle"); sprintf (&CTh1, "HCougar"); if(Init(&EventHandle)) return 1; // declare the event handler, return on error Test_Init(0); } int Test_Init(int secondary = 0) { if (secondary) { MapAxis (&CJy1, JOYX, DX_X_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&CJy1, JOYY, DX_Y_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&CTh1, THR_LEFT, DX_THROTTLE_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&CTh1, THR_RIGHT, DX_Z_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); } else { MapAxis (&CJy0, JOYX, DX_X_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&CJy0, JOYY, DX_Y_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&CTh0, THR_LEFT, DX_THROTTLE_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&CTh0, THR_RIGHT, DX_Z_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); } } I get a good compile, but no axis response in the Device Analyzer. Edited June 16, 2024 by Home Fries -Home Fries My DCS Files and Skins My DCS TARGET Profile for Cougar or Warthog and MFDs F-14B LANTIRN Guide
Drakoz Posted June 16, 2024 Posted June 16, 2024 (edited) I believe the issue is that CJy0, etc, are not being initialized by Init(), which is part of the Init EventHandle line: if(Init(&EventHandle)) return 1; &joy1, &joy2, &Joystick, &Throttle, etc. are special and initialized by Init() once the first time main() is executed. These pre-initialized aliases point to data structures which must be initialized correctly the first time main() runs, or they won't work. Study Init() in great detail if you haven't already, noticing how the "alias Throttle = "VID_044F&PID_0404"" and similar aliases are initialize and turned into the device structures called joy1, joy2, joy3, etc. After Init() runs, &Throttle, for example, points to &joy1 if a Warthog Throttle is the only connected device. I believe either you must make CJy0, CJy1, etc. an alias for &joy1, &joy2 or &Throttle, &Joystick, etc. since now &CJy0, etc. will point to the correctly initialized &Joystick, &Throttle, etc. Or you must create your own version of Init() to initialize CJy0, etc. in a similar way how Throttle, Joystick, etc, are initialized. This is a complicated initialization and it is highly likely trying to do anything to create your own version of these special names will fail or require a lot of re-writing of target.tmh. Since I always try to avoid creating a custom version of the Thrustmaster files (target.tmh, sys.tmh, etc.), I suggest you re-alias your own names to point to &Joystick, &HCougar, etc. Or just write your routine to use the already initialized names... To do what I think you are trying to do, I would use an if/then/else (e.g. your if (secondary), else) to call a single MapAxisInit() routine that contains the series of MapAxis() commands. Something like the following: if (secondary) MapAxisInit(&HCougar) else MapAxisInit(&Joystick); Where MapAxisInit() is as follows. MapAxisInit(alias devjoy, alias devthr) { MapAxis (&devjoy, JOYX, DX_X_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&devjoy, JOYY, DX_Y_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&devthr, THR_LEFT, DX_THROTTLE_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&devthr, THR_RIGHT, DX_Z_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); } My syntax might be wrong, but I hope you get the idea. My point is, MapAxis() works with &Joystick and &HCougar because these have already been initialized in Init(). To make your code work, you either need to actually pass in &Joystick or &HCougar, or you need to pass in your own variable which points to the same location as &Joystick, etc. I don't think you can just initialize your own &CJy1 and expect it to work. I believe your goal is to use aliases instead of individual routines to map each type of controller. I think what you mean by that is you don't want to MapAxis &Joystick and &HCougar since only one or the other is connected, not both, right? If so, the above method does that, but I probably don't understand the greater issue you are trying to achieve (saving stack space). I haven't looked at your CTS script. Is that a "one script to rule them all" kind of script? Again, spend some time studying how target.tmh handles &Joystick, &HCougar, &Throttle etc. and &joy0 (which is a dummy alias) vs. &joy1, &joy2, etc. on initialization in Init() and study how these data structures work. I am being loose on some of the details, because I believe you are already an expert on TARGET and things in target.tmh, right? If not, I can explain these things in more detail, or I can offer my notes and a more documented version of target.tmh that I always refer to to remember how all this works. Edited June 17, 2024 by Drakoz
Home Fries Posted June 19, 2024 Author Posted June 19, 2024 (edited) On 6/16/2024 at 5:23 PM, Drakoz said: I believe the issue is that CJy0, etc, are not being initialized by Init(), which is part of the Init EventHandle line: if(Init(&EventHandle)) return 1; &joy1, &joy2, &Joystick, &Throttle, etc. are special and initialized by Init() once the first time main() is executed. These pre-initialized aliases point to data structures which must be initialized correctly the first time main() runs, or they won't work. Study Init() in great detail if you haven't already, noticing how the "alias Throttle = "VID_044F&PID_0404"" and similar aliases are initialize and turned into the device structures called joy1, joy2, joy3, etc. After Init() runs, &Throttle, for example, points to &joy1 if a Warthog Throttle is the only connected device. I believe either you must make CJy0, CJy1, etc. an alias for &joy1, &joy2 or &Throttle, &Joystick, etc. since now &CJy0, etc. will point to the correctly initialized &Joystick, &Throttle, etc. Or you must create your own version of Init() to initialize CJy0, etc. in a similar way how Throttle, Joystick, etc, are initialized. This is a complicated initialization and it is highly likely trying to do anything to create your own version of these special names will fail or require a lot of re-writing of target.tmh. Since I always try to avoid creating a custom version of the Thrustmaster files (target.tmh, sys.tmh, etc.), I suggest you re-alias your own names to point to &Joystick, &HCougar, etc. Or just write your routine to use the already initialized names... To do what I think you are trying to do, I would use an if/then/else (e.g. your if (secondary), else) to call a single MapAxisInit() routine that contains the series of MapAxis() commands. Something like the following: if (secondary) MapAxisInit(&HCougar) else MapAxisInit(&Joystick); Where MapAxisInit() is as follows. MapAxisInit(alias devjoy, alias devthr) { MapAxis (&, JOYX, DX_X_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&, JOYY, DX_Y_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&devthr, THR_LEFT, DX_THROTTLE_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); MapAxis (&devthr, THR_RIGHT, DX_Z_AXIS, AXIS_NORMAL, MAP_ABSOLUTE); } My syntax might be wrong, but I hope you get the idea. My point is, MapAxis() works with &Joystick and &HCougar because these have already been initialized in Init(). To make your code work, you either need to actually pass in &Joystick or &HCougar, or you need to pass in your own variable which points to the same location as &Joystick, etc. I don't think you can just initialize your own &CJy1 and expect it to work. I believe your goal is to use aliases instead of individual routines to map each type of controller. I think what you mean by that is you don't want to MapAxis &Joystick and &HCougar since only one or the other is connected, not both, right? If so, the above method does that, but I probably don't understand the greater issue you are trying to achieve (saving stack space). I haven't looked at your CTS script. Is that a "one script to rule them all" kind of script? Again, spend some time studying how target.tmh handles &Joystick, &HCougar, &Throttle etc. and &joy0 (which is a dummy alias) vs. &joy1, &joy2, etc. on initialization in Init() and study how these data structures work. I am being loose on some of the details, because I believe you are already an expert on TARGET and things in target.tmh, right? If not, I can explain these things in more detail, or I can offer my notes and a more documented version of target.tmh that I always refer to to remember how all this works. Thank you for such a great write-up. My goal in this is to allow up to two sticks and two throttles to be connected in the profile, with one being primary and the other secondary (user's choice). For example, someone can use the Warthog throttle with the F-18 Stick as a primary config, with something like HCougar as the secondary config for a F-16 throttle and side stick configuration. I'm hoping to keep this generic to add the new F-16 TQS and the AVA and any other peripherals. Then within the same profile, someone flying the F-18 can use the primary configuration, and then loading the F-16 profile can use the secondary configuration and those axes will be selected for the TM virtual controller. Ideally, the alias is what I would like to do, and you're right that I don't want to modify existing TM libraries because that's a can of worms for both myself and the end user. What I'd really like is in the database config the end user selects controllers for the primary (CJy0 and CTh0) and secondary (CJy1 and CTh1) HOTAS, then for each profile can choose to use the secondary stick or throttle instead of the primary. I also want to create consistent button mapping for both primary and secondary buttons, (so all buttons can be used), with the profile mainly changing axis assignments on the fly. With 120 buttons I can make this happen, and this is part of my strategy going forward to keep the script smaller and allow more expandability against the TM stack limit. Putting the alias into the axis mapping function may be exactly what the doctor ordered, and then I'll better figure out a static button mapping scheme. I'll give this a try. Edited June 19, 2024 by Home Fries 1 -Home Fries My DCS Files and Skins My DCS TARGET Profile for Cougar or Warthog and MFDs F-14B LANTIRN Guide
Drakoz Posted June 20, 2024 Posted June 20, 2024 I am curious, what are the issues you have had with the stack? Do you mean you are running out of program stack (getting stack overflow crashes on TARGET), or do you mean you have issues with the keyalloc[] array which is used to store all key and function (e.g. EXEC) assignments? I know you have been developing your CTS script for over a decade now and it is a complex system that allows changing profiles (configurations) on the fly, so if anyone has reached a stack limit, I can imagine your script could. I have done a profile swapping system completely within TARGET, but not as complex as what you did (no external software to configure it, etc.). In my script, similar to yours, I can swap between dozens of configurations or profiles on the fly using several different Thrustmaster controllers. I use sub-functions that reconfigure everything for each profile swap. I only use main() to configure things that are common between all profiles like the button used to change profiles. If I understand correctly, you were trying to avoid having sub-functions to reconfigure for each profile, so my method is not directly useful to you. But I mention it only to say I have never seen a stack over flow, or run out of space in keyalloc[] using this method, even when I have had the script running for hours doing hundreds of profile changes without reloading the script. Anyway, just curious to know more about the stack issue and maybe I can better understand suggestions to help you. My script was made for Train Sim World, but I comment about it on the DCS forums at the link below. As the title says, the main purpose of this script is to create a better AXMAP() function in order to map controller's axes to do key presses better than what AXMAP1 and AXMAP2 can do. This is not very useful for DCS. I only point it out because of my implementation of a profile swapping system.
rdalcroft Posted August 13, 2024 Posted August 13, 2024 Hello Just to chime in on this thread? With the release of the NEW AVA thrustmaster base, there are now 2 more aliases you may need to consider for the warthog sticks: Warthog F16 (original): &joystick Warthog F18: &JoystickF18 AVA base with F16 stick: &AVA_F16 AVA base with F18 stick: &AVA_F18 But reading the Target.tmh file I am sure there must be a way for the script to know which stich is actually connected? rather that having to physically select and replace all instances off &joystick to get the new base to work with the scripts??: } // BUT HAT X Y Z Rx Ry Rz Thrtl SLD1 SLD2 SLD3 SLD4 stGameCfg virtualj = { 120, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0}; define CREATE_JOYSTICK 1 define CREATE_KEYBOARD 2 define CREATE_MOUSE 4 int Init(alias h, int cfg=CREATE_JOYSTICK+CREATE_KEYBOARD+CREATE_MOUSE) { &Throttle = GetIndexJoy(Select(&Throttle)); // expect a Warthog Throttle to be plugged on USB &Joystick = GetIndexJoy(Select(&Joystick)); // expect a Warthog Stick to be plugged on USB &JoystickF18 = GetIndexJoy(Select(&JoystickF18)); // expect a Warthog Stick F18 to be plugged on USB &LMFD = GetIndexJoy(Select(&LMFD)); // expect a LMFD to be plugged on USB &RMFD = GetIndexJoy(Select(&RMFD)); // expect a RMFD to be plugged on USB &HCougar = GetIndexJoy(Select(&HCougar)); // expect a Hotas Cougar to be plugged on USB &T16000 = GetIndexJoy(Select(&T16000)); // expect a T16000 to be plugged on USB &T16000L = GetIndexJoy(Select(&T16000L)); // expect a T16000 left handed to be plugged on USB &TWCSThrottle = GetIndexJoy(Select(&TWCSThrottle)); // expect a TWCSThrottle to be plugged on USB &TFRPRudder = GetIndexJoy(Select(&TFRPRudder)); // expect a TFRPRudder to be plugged on USB &TFRPHARudder = GetIndexJoy(Select(&TFRPHARudder)); // expect a TFRPHA Rudder Pendular to be plugged on USB &A320Pilot = GetIndexJoy(Select(&A320Pilot)); // expect a A320Pilot to be plugged on USB &A320Copilot = GetIndexJoy(Select(&A320Copilot)); // expect a A320Copilot to be plugged on USB &TCAQuadrant12 = GetIndexJoy(Select(&TCAQuadrant12));// expect a TCA Quadrant Eng1&2 to be plugged on USB &TCAQuadrant34 = GetIndexJoy(Select(&TCAQuadrant34));// expect a TCA Quadrant Eng3&4 to be plugged on USB &TCAQBoeing12 = GetIndexJoy(Select(&TCAQBoeing12));// expect a TCA Q Boeing Eng1&2 to be plugged on USB &TCAQBoeing34 = GetIndexJoy(Select(&TCAQBoeing34));// expect a TCA Q Boeing Eng3&4 to be plugged on USB &TCAYokeBoeing = GetIndexJoy(Select(&TCAYokeBoeing));// expect a TCA Yoke Boeing to be plugged on USB &ViperTQS = GetIndexJoy(Select(&ViperTQS)); // expect a Viper TQS to be plugged on USB &ViperBBox = GetIndexJoy(Select(&ViperBBox)); // expect a Viper BBox to be plugged on USB &TCASidestickXPilot = GetIndexJoy(Select(&TCASidestickXPilot)); // expect a TCASidestickXPilot to be plugged on USB &TCASidestickXCopilot = GetIndexJoy(Select(&TCASidestickXCopilot)); // expect a TCASidestickXCopilot to be plugged on USB &FarmStickRight = GetIndexJoy(Select(&FarmStickRight)); // expect a FarmStickRight to be plugged on USB &FarmStickLeft = GetIndexJoy(Select(&FarmStickLeft)); // expect a FarmStickLeft to be plugged on USB &AVA_F16 = GetIndexJoy(Select(&AVA_F16)); // expect an AVA base + F16 handle to be plugged on USB &AVA_F18 = GetIndexJoy(Select(&AVA_F18)); // expect an AVA base + F18 handle to be plugged on USB if(cfg & CREATE_JOYSTICK) PlugGame(&virtualj, "Thrustmaster Combined"); // create a Virtual device if(cfg & CREATE_KEYBOARD) PlugKeyboard(); if(cfg & CREATE_MOUSE) PlugMouse(1); &_evh = &h; SetEventHandler(&DefEventHandler); SEQ(); // initialize SEQ function as VPN CHAIN(); // initialize CHAIN function as VPN AXMAP2(); int i; while(i<256) { USB[i] = i+1000; i = i+1; } // fill the USB table MapList(&Joystick, &JoystickMap); // default DX buttons mapping for all devices MapList(&JoystickF18, &JoystickMap); MapList(&Throttle, &ThrottleMap); MapList(&HCougar, &JoystickMap); MapList(&HCougar, &HCougarMap); MapList(&LMFD, &MFDMap); MapList(&RMFD, &MFDMap); MapList(&T16000, &T16000Map, 16); MapList(&T16000L, &T16000Map, 16); MapList(&TWCSThrottle, &TWCSThrottleMap); MapList(&TFRPRudder, &TFRPRudderMap); MapList(&TFRPHARudder, &TFRPHARudderMap); MapList(&A320Pilot, &T16000Map); MapList(&A320Copilot, &T16000Map); MapList(&TCAQuadrant12, &TCAQuadrantMap); MapList(&TCAQuadrant34, &TCAQuadrantMap); MapList(&TCAQBoeing12, &TCAQBoeingMap); MapList(&TCAQBoeing34, &TCAQBoeingMap); MapList(&TCAYokeBoeing, &TCAYokeBoeingMap); MapList(&ViperTQS, &ViperTQSMap); MapList(&ViperBBox, &ViperBBoxMap); MapList(&TCASidestickXPilot, &T16000Map); MapList(&TCASidestickXCopilot, &T16000Map); MapList(&FarmStickRight, &FarmStickMap); MapList(&FarmStickLeft, &FarmStickMap); MapList(&AVA_F16, &JoystickMap); MapList(&AVA_F18, &JoystickMap); i=elements(&vbtntbl); while(i>0) // initialize Throttle virtual buttons with 1 { i = i-1; if(vbtntbl[i]) Throttle[vbtntbl[i]] = 1; } HCougar[DFM] = 1; // initialize Cougar virtual buttons with 1 HCougar[SPDM] = 1; DXAxis(MOUSE_X_AXIS, 0); DXAxis(MOUSE_Y_AXIS, 0); }
Drakoz Posted August 14, 2024 Posted August 14, 2024 (edited) Yes, there are several ways to know what controllers are attached and act on that information. It isn't difficult determine this after Init() has run as you suggest. But since each controller has different buttons, switches, and axes, you still have to configure each controller with a custom script. E.g. TG1 on one stick may not exist on another stick of be called something else. Normally people who use TARGET just have a different script for each controller or aircraft/controller combo. Normally it isn't worth the effort to create a single script that detects the controller and then runs the portion of the script for that particular controller. This is what I do for DCS. One script per controller/aircraft. For Train Sim World, I created a single huge script to allow changing configurations for different locomotives, but each script used the same controllers. I created different scripts for different sets of controllers. The permutations just gets to be too much for a single script to support all those options. It was complicated enough just allowing the ability to swap locomotives on the fly without reloading the script. Also, most people keep all their controllers plugged in all the time and maybe switch between different devices depending on the aircraft or purpose (e.g. one controller for DCS, but another one for a different game maybe, or fixed wing vs. helicopter). Now if your goal is to create a script that you pass out to other people with different controllers and have it just work for everyone generically, then yes, the stuff we discussed above about changing the script to detect and configure each controller applies. It is a lot of coding, and error prone due to complexity, but it can be done. I would still probably create separate scripts for each controller, but I would use several include (.tmh) files with the common code to reduce how much coding I need. Home Fries, has been creating such script to rule them all for many years. Bravo for his investment in time and effort to do this. It is a huge effort. Edited August 14, 2024 by Drakoz 1
rdalcroft Posted August 14, 2024 Posted August 14, 2024 (edited) Hello Thanks for the reply. But the NEW AVA base although it changes the Alias ID, the Sticks are the same, therefore the axis and button mappings are identical. So my question was for users who already have scripts for their old warthog stick and base F16, F18, A10c, (&joystick) and want to use the new AVA base with the same sticks. Then it's just a matter of changing the Naming of the &joystick to &AVA_F16 (or &AVAF18). I thought maybe there could be a simple line of code to state that &joystick needs to be replaced with &AVA_F16 And do this for all script pages (as some scripts have 4-5 pages? Right now I am using Notepad++ to Change all of these entries, and it works fine, But in the case with the CTS script for DCS, there are so many different scripts and pages, I do not know if by doing this I may mess up some other links within the script? Edited August 15, 2024 by rdalcroft Naming of AVAF16 to AVA_F16
Drakoz Posted August 14, 2024 Posted August 14, 2024 Oh, right. Yes, if the sticks have the same buttons, axes, etc. you are correct, it would be useful and easy to figure out which stick is connected and use a custom alias to represent the connected stick like I explained on my June 16th comment above. Of course, Home Fries CTS script doesn't support this, but below is one way to do it. Maybe Home Fries is already planning to add something like this? You would use a routine such as the following to generically map all the buttons, axes, etc. for an F16 or F18 like stick. This is similar to the example I posted above in my June 16th post. MapJoystick(alias devjoy) { MapKeyIO(&devjoy, TG1, ...); MapKeyIO(&devjoy, S1, ....); // etc.... } You call MapJoystick() with a line such as the following depending on which stick is connected. MapJoystick(&Joystick); or MapJoystick(&AVAF16); This makes it so that inside MapJoystick, &devjoy is the same as &Joystick or &AVAF16. Hence the same commands can be used to configure either joystick. But how to you tell which stick is connected? When the script starts, in target.tmh, a controller's handle (e.g. &Joystick) is defined as a string of text which is the USB ID (e.g. Joystick = "VID_044F&PID_0402"). This is just a temporary thing and will be replaced in the Init() routine by a line similar to the following. &Joystick = GetIndexJoy( Select(&Joystick) ); Select(&Joystick) calls the TARGET routine that initialized the controller USB port. This is the command that prints out in the TARGET console what devices are connected or failed to be detected. Select() returns a number from 0 to 16. GetIndexJoy() takes the number and converts it into &joy0, &joy1, &joy2, ..., &joy16. Hence, the line of code above sets &Joystick = &joy0, or &joy1, or &joy2, etc. depending on whether the stick is connected or not. Bottom line is..... If the stick is NOT connected, Select() fails with -1 which causes &Joystick to be set equal to &joy0. If &Joystick is connected, it will be set equal to &joy1, &joy2, &joy3, etc. up to &joy16 depending on the order the controllers are detected. That order is determined by Init(). This works the same if you use a Configure() statement to disable &Joystick such as the following. The following statement will cause &Joystick to be set equal to &joy0. Configure(&Joystick, MODE_EXCLUDED); // Exclude Warthog Joystick Below I copied a snip of Init() that sets a controller to &joy0, &joy1, etc. &Throttle is configured first, then &Joystick, then &JoystickF18. This may be different for the latest version of TARGET, but the concept is the same. int Init(alias h, int cfg=CREATE_JOYSTICK+CREATE_KEYBOARD+CREATE_MOUSE) { &Throttle = GetIndexJoy(Select(&Throttle)); // expect a Warthog Throttle to be plugged on USB &Joystick = GetIndexJoy(Select(&Joystick)); // expect a Warthog Stick to be plugged on USB| &JoystickF18 = GetIndexJoy(Select(&JoystickF18)); // expect a Warthog Stick F18 to be plugged on USB ... } In the example above, if a Warthog Throttle (&Throttle) and Warthog Joystick (&Joystick) are connected, but NOT an F18 stick (&JoystickF18), then these three controllers will be configured as follows: &Throttle = &joy1 &Joystick = &joy2 &JoystickF18 = &joy0 Now, anywhere you want to use &Joystick, you can say &joy2. They ware interchangeable. Any other devices that are NOT connected will be set to &joy0. Assuming only one stick or the other is connected, but not both at the same time, you can tell which one you need to configure. &joy0 is a dummy variable used for non-connected controllers and is not used for anything else. Here is an example of how to check which one is connected. I included the AVA F16 and F18 in the example below. If (&Joystick != &joy0) MapJoystick(&Joystick); else if (&JoystickF18 != &joy0) MapJoystick(&JoystickF18); else if (&AVAF16 != &joy0) MapJoystick(&AVAJ6); else if (&AVAF18 != &joy0) MapJoystick(&&AVAF18); Do the same for the Throttle Quadrant if using two throttles that have similar or the same key mappings. There are several ways you might choose to use this, but the key is to check if the &Joystick or &AVAF18, etc. is equal to &joy0. If so, that device is NOT connected. What is &Joystick and &joy0 or &joy1? The & just means Joystick, joy0, joy1, etc. are an "alias" (a variable of type alias). It is similar to a pointer in C programming. An alias with & in the name (e.g. &joy1) is just a pointer (memory address) to the contents of the variable joy1. In this case, joy0, joy1, joy2, etc, are just arrays of 296 elements. These arrays contains the current status of all buttons switches, hats, etc. on the controller. If TG1 on a Warthog Joystick is pressed, Joystick[TG1] = 1. Otherwise, Joystick[TG1] = 0. Looking at defines.tmh, we see that TG1 = 0, so Joystick[TG1] is the first element in the array. All controller handles (e.g. &Joystick, &Throttle, &AVAF16, &AVAF18, etc.) are set equal to &joy1, &joy2, &joy3, etc., so Joystick[TG1] is the same as joy1[TG1] if a Warthog Joystick is the only controller connected. Sometimes the code in target.tmh uses joy0, joy1, joy2 instead of Joystick, AVAF16, etc. That's all it is. Knowing this is useful for other purposes, but not important for this discussion. We only care if a controller is set to equal joy0 instead of joy1, joy2, etc.
rdalcroft Posted August 15, 2024 Posted August 15, 2024 Wow! Thank you for taking the time to explain all this. I will need to study this for a while, before it finally clicks in my brain. lol But I will go away and play with this on one of my simpler scripts to practice. Much appreciated, I will let you know how I get on with it!!. Cheers! 1
dmonds Posted August 15, 2024 Posted August 15, 2024 (edited) Hi @Drakoz, So are you saying that if I replace all instances of &Joystick with &joy2 and all instances of Joystick[button name] with joy2[button name] in my scripts then it would not matter if I had a WARTHOG, F18 Flight stick, AVA F16 or AVAF18 connected since they all have the exact same button mappings? ...and therefore, the script should just work? Regards dmonds Edited August 15, 2024 by dmonds incomplete question
Drakoz Posted August 15, 2024 Posted August 15, 2024 44 minutes ago, dmonds said: So are you saying that if I replace all instances of &Joystick with &joy2 and all instances of Joystick[button name] with joy2[button name] in my scripts then it would not matter if I had a WARTHOG, F18 Flight stick, AVA F16 or AVAF18 connected since they all have the exact same button mappings? ...and therefore, the script should just work? That is kind of true, but not likely to work. I wouldn't go around replacing Joystick witih joy2. Not unless you really understand how all this works. First of all, I said &Joystick = &joy2 only for my example. Depending on which controllers you have connected, it might be &joy1 or &joy6 or something else. I will explain this a bit more below. Also, I haven't tested this or played with these kind of things for a couple years so I would have to experiment to be sure. Besides, if you are going to search and replace all instances of &Joystick with something else, you should replace it with something like &devjoy as in my example above instead of using &joy1 or &joy2, etc. My example posted earlier worked by putting all configuration statements in a subroutine called MapJoystick(), but you could just as easily hard code a statement at the top of your TARGET script (after Init() of course) saying "&devjoy = &Joystick", and replace all occurrences of &Joystick with &devjoy. Then if you switch to a AVA F16, change the hard coded statement to say "&devjoy = &AVAF16". This is the eaiest way to switch back and forth between different Joysticks with the same button combos. Don't forget, you must define &devjoy, so place the following statement in your TARGET script before the main() statement. alias devjoy FYI, am explaining all this assuming everyone here has some basic understanding of C Language programming. TARGET is basically C Language with a few adjustments, and one of those big adjustments is they use an "alias" in place of a C Language pointer. They largely work the same, but not always. Understanding these advanced techniques in TARGET significantly requires understanding aliases. If you don't understand this, don't hesitate to ask questions, spend a little time reading up on C Language pointers, or just do some experiments to figure out how things work. Regarding &joy1, &joy2, &joy6 etc. How do we tell which will be assigned? The &joy1, &joy2, etc. are asssigned in order, 1, 2, 3, 4... to 16. As each controller is detected, it is assigned the next unused number. If a controller is not connected (or disabled using the Configure() command), then it is assigned &joy0. All controllers that are not connected are assigned to &joy0 as I explained in my last email. The order of assignments is determined in the Init() routine in target.tmh. I pasted the commands from Init() below that perform this configuration. Note the order of the commands - each one is written to identify and initialize a specific controller (Throttle, Joystick, JoystickF18, etc.). If you have a Warthog Throttle, Warthog Joystick, and a TWCS Throttle connected, and nothing else, then you will get the following assignment order: &Throttle = &joy1 &Joystick = &joy2 &TWCSThrottle = &joy3 Everything else will be set to &joy0. Note the F18 stick is 3rd in order below, but the AVA F16 and AVA F18 sticks are last. So if instead, we have a Warthog Throttle, Warthog base with F18 stick, and a TWCS Throttle, the order will be: &Throttle = &joy1 &JoystickF18 = &joy2 &TWCSThrottle = &joy3 If you have an AVA F16 stick, Warthog Throttle and TWCS Throttle, the order will be: &Throttle = &joy1 &TWCSThrottle = &joy2 &AVAF16 = &joy3 Hopefully this makes it clear how the joy0, joy1, etc. are assigned. So yes, if you have the same controllers connected all the time, you know exactly which joy1, joy2, joy3 etc. will be assigned to which controller. But add a new controller and it can all change. That is why I do not suggest using joy1, joy2, joy3, etc. directly in your scripts. I copied the statements below from rdalcroft's post earlier, and I assume this is from the latest version of TARGET. I haven't upgraded to this version yet. I see the list has grown a lot since I last saw it. This makes me wonder if they have more than 16 joy__ arrays now. If so, then maybe they have joy1 through joy24 or something like that now. You can tell by looking in the hid.tmh file. The joy__[] arrays are defined in that file. &Throttle = GetIndexJoy(Select(&Throttle)); // expect a Warthog Throttle to be plugged on USB &Joystick = GetIndexJoy(Select(&Joystick)); // expect a Warthog Stick to be plugged on USB &JoystickF18 = GetIndexJoy(Select(&JoystickF18)); // expect a Warthog Stick F18 to be plugged on USB &LMFD = GetIndexJoy(Select(&LMFD)); // expect a LMFD to be plugged on USB &RMFD = GetIndexJoy(Select(&RMFD)); // expect a RMFD to be plugged on USB &HCougar = GetIndexJoy(Select(&HCougar)); // expect a Hotas Cougar to be plugged on USB &T16000 = GetIndexJoy(Select(&T16000)); // expect a T16000 to be plugged on USB &T16000L = GetIndexJoy(Select(&T16000L)); // expect a T16000 left handed to be plugged on USB &TWCSThrottle = GetIndexJoy(Select(&TWCSThrottle)); // expect a TWCSThrottle to be plugged on USB &TFRPRudder = GetIndexJoy(Select(&TFRPRudder)); // expect a TFRPRudder to be plugged on USB &TFRPHARudder = GetIndexJoy(Select(&TFRPHARudder)); // expect a TFRPHA Rudder Pendular to be plugged on USB &A320Pilot = GetIndexJoy(Select(&A320Pilot)); // expect a A320Pilot to be plugged on USB &A320Copilot = GetIndexJoy(Select(&A320Copilot)); // expect a A320Copilot to be plugged on USB &TCAQuadrant12 = GetIndexJoy(Select(&TCAQuadrant12));// expect a TCA Quadrant Eng1&2 to be plugged on USB &TCAQuadrant34 = GetIndexJoy(Select(&TCAQuadrant34));// expect a TCA Quadrant Eng3&4 to be plugged on USB &TCAQBoeing12 = GetIndexJoy(Select(&TCAQBoeing12));// expect a TCA Q Boeing Eng1&2 to be plugged on USB &TCAQBoeing34 = GetIndexJoy(Select(&TCAQBoeing34));// expect a TCA Q Boeing Eng3&4 to be plugged on USB &TCAYokeBoeing = GetIndexJoy(Select(&TCAYokeBoeing));// expect a TCA Yoke Boeing to be plugged on USB &ViperTQS = GetIndexJoy(Select(&ViperTQS)); // expect a Viper TQS to be plugged on USB &ViperBBox = GetIndexJoy(Select(&ViperBBox)); // expect a Viper BBox to be plugged on USB &TCASidestickXPilot = GetIndexJoy(Select(&TCASidestickXPilot)); // expect a TCASidestickXPilot to be plugged on USB &TCASidestickXCopilot = GetIndexJoy(Select(&TCASidestickXCopilot)); // expect a TCASidestickXCopilot to be plugged on USB &FarmStickRight = GetIndexJoy(Select(&FarmStickRight)); // expect a FarmStickRight to be plugged on USB &FarmStickLeft = GetIndexJoy(Select(&FarmStickLeft)); // expect a FarmStickLeft to be plugged on USB &AVA_F16 = GetIndexJoy(Select(&AVA_F16)); // expect an AVA base + F16 handle to be plugged on USB &AVA_F18 = GetIndexJoy(Select(&AVA_F18)); // expect an AVA base + F18 handle to be plugged on USB Here is the joy__[] array definition from hid.tmh from my version of TARGET. short joy1[296]; //1st selected USB device input vector short joy2[296]; //2nd selected USB device input vector short joy3[296]; //3rd selected USB device input vector short joy4[296]; //4th selected USB device input vector short joy5[296]; //5th selected USB device input vector short joy6[296]; //6th selected USB device input vector short joy7[296]; //7th selected USB device input vector short joy8[296]; //8th selected USB device input vector short joy9[296]; //9th selected USB device input vector short joy10[296]; //10th selected USB device input vector short joy11[296]; //11th selected USB device input vector short joy12[296]; //12th selected USB device input vector short joy13[296]; //13th selected USB device input vector short joy14[296]; //14th selected USB device input vector short joy15[296]; //15th selected USB device input vector short joy16[296]; //16th selected USB device input vector
rdalcroft Posted August 15, 2024 Posted August 15, 2024 1 hour ago, Drakoz said: That is kind of true, but not likely to work. I wouldn't go around replacing Joystick witih joy2. Not unless you really understand how all this works. First of all, I said &Joystick = &joy2 only for my example. Depending on which controllers you have connected, it might be &joy1 or &joy6 or something else. I will explain this a bit more below. Also, I haven't tested this or played with these kind of things for a couple years so I would have to experiment to be sure. Besides, if you are going to search and replace all instances of &Joystick with something else, you should replace it with something like &devjoy as in my example above instead of using &joy1 or &joy2, etc. My example posted earlier worked by putting all configuration statements in a subroutine called MapJoystick(), but you could just as easily hard code a statement at the top of your TARGET script (after Init() of course) saying "&devjoy = &Joystick", and replace all occurrences of &Joystick with &devjoy. Then if you switch to a AVA F16, change the hard coded statement to say "&devjoy = &AVAF16". This is the eaiest way to switch back and forth between different Joysticks with the same button combos. Don't forget, you must define &devjoy, so place the following statement in your TARGET script before the main() statement. alias devjoy FYI, am explaining all this assuming everyone here has some basic understanding of C Language programming. TARGET is basically C Language with a few adjustments, and one of those big adjustments is they use an "alias" in place of a C Language pointer. They largely work the same, but not always. Understanding these advanced techniques in TARGET significantly requires understanding aliases. If you don't understand this, don't hesitate to ask questions, spend a little time reading up on C Language pointers, or just do some experiments to figure out how things work. Regarding &joy1, &joy2, &joy6 etc. How do we tell which will be assigned? The &joy1, &joy2, etc. are asssigned in order, 1, 2, 3, 4... to 16. As each controller is detected, it is assigned the next unused number. If a controller is not connected (or disabled using the Configure() command), then it is assigned &joy0. All controllers that are not connected are assigned to &joy0 as I explained in my last email. The order of assignments is determined in the Init() routine in target.tmh. I pasted the commands from Init() below that perform this configuration. Note the order of the commands - each one is written to identify and initialize a specific controller (Throttle, Joystick, JoystickF18, etc.). If you have a Warthog Throttle, Warthog Joystick, and a TWCS Throttle connected, and nothing else, then you will get the following assignment order: &Throttle = &joy1 &Joystick = &joy2 &TWCSThrottle = &joy3 Everything else will be set to &joy0. Note the F18 stick is 3rd in order below, but the AVA F16 and AVA F18 sticks are last. So if instead, we have a Warthog Throttle, Warthog base with F18 stick, and a TWCS Throttle, the order will be: &Throttle = &joy1 &JoystickF18 = &joy2 &TWCSThrottle = &joy3 If you have an AVA F16 stick, Warthog Throttle and TWCS Throttle, the order will be: &Throttle = &joy1 &TWCSThrottle = &joy2 &AVAF16 = &joy3 Hopefully this makes it clear how the joy0, joy1, etc. are assigned. So yes, if you have the same controllers connected all the time, you know exactly which joy1, joy2, joy3 etc. will be assigned to which controller. But add a new controller and it can all change. That is why I do not suggest using joy1, joy2, joy3, etc. directly in your scripts. I copied the statements below from rdalcroft's post earlier, and I assume this is from the latest version of TARGET. I haven't upgraded to this version yet. I see the list has grown a lot since I last saw it. This makes me wonder if they have more than 16 joy__ arrays now. If so, then maybe they have joy1 through joy24 or something like that now. You can tell by looking in the hid.tmh file. The joy__[] arrays are defined in that file. &Throttle = GetIndexJoy(Select(&Throttle)); // expect a Warthog Throttle to be plugged on USB &Joystick = GetIndexJoy(Select(&Joystick)); // expect a Warthog Stick to be plugged on USB &JoystickF18 = GetIndexJoy(Select(&JoystickF18)); // expect a Warthog Stick F18 to be plugged on USB &LMFD = GetIndexJoy(Select(&LMFD)); // expect a LMFD to be plugged on USB &RMFD = GetIndexJoy(Select(&RMFD)); // expect a RMFD to be plugged on USB &HCougar = GetIndexJoy(Select(&HCougar)); // expect a Hotas Cougar to be plugged on USB &T16000 = GetIndexJoy(Select(&T16000)); // expect a T16000 to be plugged on USB &T16000L = GetIndexJoy(Select(&T16000L)); // expect a T16000 left handed to be plugged on USB &TWCSThrottle = GetIndexJoy(Select(&TWCSThrottle)); // expect a TWCSThrottle to be plugged on USB &TFRPRudder = GetIndexJoy(Select(&TFRPRudder)); // expect a TFRPRudder to be plugged on USB &TFRPHARudder = GetIndexJoy(Select(&TFRPHARudder)); // expect a TFRPHA Rudder Pendular to be plugged on USB &A320Pilot = GetIndexJoy(Select(&A320Pilot)); // expect a A320Pilot to be plugged on USB &A320Copilot = GetIndexJoy(Select(&A320Copilot)); // expect a A320Copilot to be plugged on USB &TCAQuadrant12 = GetIndexJoy(Select(&TCAQuadrant12));// expect a TCA Quadrant Eng1&2 to be plugged on USB &TCAQuadrant34 = GetIndexJoy(Select(&TCAQuadrant34));// expect a TCA Quadrant Eng3&4 to be plugged on USB &TCAQBoeing12 = GetIndexJoy(Select(&TCAQBoeing12));// expect a TCA Q Boeing Eng1&2 to be plugged on USB &TCAQBoeing34 = GetIndexJoy(Select(&TCAQBoeing34));// expect a TCA Q Boeing Eng3&4 to be plugged on USB &TCAYokeBoeing = GetIndexJoy(Select(&TCAYokeBoeing));// expect a TCA Yoke Boeing to be plugged on USB &ViperTQS = GetIndexJoy(Select(&ViperTQS)); // expect a Viper TQS to be plugged on USB &ViperBBox = GetIndexJoy(Select(&ViperBBox)); // expect a Viper BBox to be plugged on USB &TCASidestickXPilot = GetIndexJoy(Select(&TCASidestickXPilot)); // expect a TCASidestickXPilot to be plugged on USB &TCASidestickXCopilot = GetIndexJoy(Select(&TCASidestickXCopilot)); // expect a TCASidestickXCopilot to be plugged on USB &FarmStickRight = GetIndexJoy(Select(&FarmStickRight)); // expect a FarmStickRight to be plugged on USB &FarmStickLeft = GetIndexJoy(Select(&FarmStickLeft)); // expect a FarmStickLeft to be plugged on USB &AVA_F16 = GetIndexJoy(Select(&AVA_F16)); // expect an AVA base + F16 handle to be plugged on USB &AVA_F18 = GetIndexJoy(Select(&AVA_F18)); // expect an AVA base + F18 handle to be plugged on USB Here is the joy__[] array definition from hid.tmh from my version of TARGET. short joy1[296]; //1st selected USB device input vector short joy2[296]; //2nd selected USB device input vector short joy3[296]; //3rd selected USB device input vector short joy4[296]; //4th selected USB device input vector short joy5[296]; //5th selected USB device input vector short joy6[296]; //6th selected USB device input vector short joy7[296]; //7th selected USB device input vector short joy8[296]; //8th selected USB device input vector short joy9[296]; //9th selected USB device input vector short joy10[296]; //10th selected USB device input vector short joy11[296]; //11th selected USB device input vector short joy12[296]; //12th selected USB device input vector short joy13[296]; //13th selected USB device input vector short joy14[296]; //14th selected USB device input vector short joy15[296]; //15th selected USB device input vector short joy16[296]; //16th selected USB device input vector @Drakoz Using the hard coded alias thing worked! I could not figure out how to do it with your first example though: MapJoystick(alias devjoy) { MapKeyIO(&devjoy, TG1, ...); MapKeyIO(&devjoy, S1, ....); // etc.... }
Recommended Posts