Previous Thread
Next Thread
Print Thread
Rate This Thread
Hop To
Page 1 of 2 1 2
#4268354 - 06/08/16 06:40 PM Advanced Question: system(spawn) and running external scripts  
Joined: Jan 2001
Posts: 2,477
HomeFries Offline
Air Dominance Project
HomeFries  Offline
Air Dominance Project
Member

Joined: Jan 2001
Posts: 2,477
I would like to have a routine in my DCS TARGET profile for when a particular aircraft is selected, it will call a script (currently VBS) that will use MS Speech to say the name of the aircraft.

For example, my F15C.vbs script:
Code:
set speech = Wscript.CreateObject("SAPI.spVoice")
speech.speak "F 15 C Eagle"

This script works from the command line, but when I try to run it from TARGET it doesn't work. I have put the script call into a one-line function to keep the number of quotations to a minimum. I have tried each of the lines in the sysf15() functions (remmed or otherwise), but have had no luck.

Code:
include "target.tmh"
int main()
{
    if(Init(&EventHandle)) return 1; // declare the event handler, return on error
MapKey(&Joystick,	S2,		EXEC("sysf15();"));
}

int sysf15()
{
//system("spawn -w \"D:\\TM\\TARGET\\HF\\DCS\\Speech\" \"D:\\TM\\TARGET\\HF\\DCS\\Speech\\F15C.vbs\"");
//system("spawn -w \"D:\\TM\\TARGET\\HF\\DCS\\Speech\" \"D:\\TM\\TARGET\\HF\\DCS\\Speech\\wscript F15C.vbs\"");
//system("spawn \"D:\\TM\\TARGET\\HF\\DCS\\Speech\" \"D:\\TM\\TARGET\\HF\\DCS\\Speech\\F15C.vbs\"");
system("spawn \"D:\\TM\\TARGET\\HF\\DCS\\Speech\" \"D:\\TM\\TARGET\\HF\\DCS\\Speech\\wscript F15C.vbs\"");
}

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


There's nothing in the TARGET script editor manual about system (beyond a very limited example), and I can't find anything on spawn other than it being a unix command. Can I do anything that can be run from a command line, or do I actually need to create and compile a BAT file?

EDIT: When I create a BAT to launch the vbs, pressing S2 will actually generate the cmd window. However, no speech happens. Here's the BAT:
Code:
start cscript f15c.vbs

Note: wscript caused an error 80004005, so I went with cscript.

Any advice would be greatly appreciated. Thanks in advance.

Last edited by HomeFries; 06/08/16 06:53 PM.

-Home Fries

"Pacifism is a shifty doctrine under which a man accepts the benefits of the social group without being willing to pay - and claims a halo for his dishonesty."
- Robert A. Heinlein

The average naval aviator, despite the sometimes swaggering exterior, is very much capable of such feelings as love, affection, intimacy, and caring. These feelings just don't involve anyone else.

Inline advert (2nd and 3rd post)

#4268437 - 06/08/16 10:30 PM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: Jan 2001
Posts: 2,477
HomeFries Offline
Air Dominance Project
HomeFries  Offline
Air Dominance Project
Member

Joined: Jan 2001
Posts: 2,477
Some updates:
I've since compiled a Win32 EXE in C++ (VS12) that also calls the MS speech. I can get TARGET to run the EXE when I press S2, but no sound comes out. Now I'm wondering if there are other limitations to what kinds of programs can be called with system(spawn -w).

Next step: I had the batch file start a cmd window, then tried running the Win32 EXE. the Win32 EXE works in a normally started cmd window, but not from the one called by TARGET. Could this be something with UAC?

Last edited by HomeFries; 06/08/16 10:40 PM.

-Home Fries

"Pacifism is a shifty doctrine under which a man accepts the benefits of the social group without being willing to pay - and claims a halo for his dishonesty."
- Robert A. Heinlein

The average naval aviator, despite the sometimes swaggering exterior, is very much capable of such feelings as love, affection, intimacy, and caring. These feelings just don't involve anyone else.

#4268449 - 06/08/16 11:52 PM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: Jan 2001
Posts: 2,477
HomeFries Offline
Air Dominance Project
HomeFries  Offline
Air Dominance Project
Member

Joined: Jan 2001
Posts: 2,477
I was able to get it working by pre-recording wav files, but this is a brittle solution and I'm still hoping to resolve the MS Speech.

Also, is there a way to use relative directory addresses instead of ablsolutes with spawn -w? I would rather use spawn -w \".\\DCS\\Speech\"... rather than the full folder.

Failing this, is there a way to import a path as a string or char type constant, then add \\DCS\\Speech to the end of the string? This could be as simple as applying a constant in a separate file.

Last edited by HomeFries; 06/09/16 05:46 AM.

-Home Fries

"Pacifism is a shifty doctrine under which a man accepts the benefits of the social group without being willing to pay - and claims a halo for his dishonesty."
- Robert A. Heinlein

The average naval aviator, despite the sometimes swaggering exterior, is very much capable of such feelings as love, affection, intimacy, and caring. These feelings just don't involve anyone else.

#4268521 - 06/09/16 07:29 AM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: Jan 2001
Posts: 2,477
HomeFries Offline
Air Dominance Project
HomeFries  Offline
Air Dominance Project
Member

Joined: Jan 2001
Posts: 2,477
I was able to get a working solution using the information in this thread. Thank you Nicu and Frenchy for showing me the way!

Here's what I ended up doing:

  • I made WAV files of the name of each aircraft using MS Anna
  • I downloaded an open source command line wav player
  • I created a batch file with contents "start swavplayer %1"
  • I added the following routine to my script:

Code:
int PlayWav(alias wavfile)
{
    char buffer;Dim(&buffer, 99);
    sprintf (&buffer, "spawn -w \"%s\\DCS\\Speech\" \"%s\\DCS\\Speech\\playsnd.bat %s\"", &ScriptPath,&ScriptPath,&wavfile);
    system(&buffer);
}

and
Code:
alias ScriptPath = "D:\\TM\\TARGET\\HF";

which is in the initial file and can be edited to match the end-user's path.

It's not perfect, but it will do just fine!


-Home Fries

"Pacifism is a shifty doctrine under which a man accepts the benefits of the social group without being willing to pay - and claims a halo for his dishonesty."
- Robert A. Heinlein

The average naval aviator, despite the sometimes swaggering exterior, is very much capable of such feelings as love, affection, intimacy, and caring. These feelings just don't involve anyone else.

#4271114 - 06/17/16 06:39 PM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: May 2006
Posts: 123
DarKcyde Offline
Member
DarKcyde  Offline
Member

Joined: May 2006
Posts: 123
I love where you're going with this. The issues are frustrating. Quick search turned up a command line tool to perform SAPI commands,

https://github.com/brookhong/tts

Try that out, seems like it should do what you want.

#4273443 - 06/25/16 10:13 PM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: Jan 2001
Posts: 2,477
HomeFries Offline
Air Dominance Project
HomeFries  Offline
Air Dominance Project
Member

Joined: Jan 2001
Posts: 2,477
Nice. I'll play with it.


-Home Fries

"Pacifism is a shifty doctrine under which a man accepts the benefits of the social group without being willing to pay - and claims a halo for his dishonesty."
- Robert A. Heinlein

The average naval aviator, despite the sometimes swaggering exterior, is very much capable of such feelings as love, affection, intimacy, and caring. These feelings just don't involve anyone else.

#4273456 - 06/25/16 11:30 PM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: May 2006
Posts: 123
DarKcyde Offline
Member
DarKcyde  Offline
Member

Joined: May 2006
Posts: 123
It might not work still. The problem is Target spawns things from the TM Service. Services don't have a desktop, so interactive programs that make sounds often won't work. The solution is to use some kernel32.dll functions to start the process as the current user. Search around for starting processes from a service. Calling the functions with C from inside target will be the biggest challenge. Most docs online assume you're using C++, and can just link the libs/headers required.

#4507362 - 02/14/20 12:36 PM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: Jul 2016
Posts: 61
Drakoz Offline
Junior Member
Drakoz  Offline
Junior Member

Joined: Jul 2016
Posts: 61
I was able to get Text to Speech to work in TARGET. Like HomeFries final solution, I initially used the method of playing WAV files, but then I figured out how to get Text so Speech working directly in TARGET. I give my examples of both below.

For playing WAV files, I am using the same sWavPlayer.exe as mentioned above, but I'm not using a batch file. I deal with all directory path names and file names directly in TARGET. So perhaps I don't have much to add here except that yes it can be very confusing dealing with the \\ and quotes when using system(spawn....) in TARGET, but it is possible to build the command using sprintf(&buffer, ...) and get it working without an external batch file. Instead of reposting what I did here, I'll refer people to my post on the DCS Forums. Go here:
https://forums.eagle.ru/showpost.php?p=4203806&postcount=12

But more interesting is I got text to speech to work in TARGET directly, using only programs that are a part of Windows, no custom programs you have to download and no custom batch files. Like HomeFries, I used SAPI.SpVoice using VBScript (VBS), but I got it to work without the issues described above. Again, I posted this on the DCS Forums. Go here:
https://forums.eagle.ru/showpost.php?p=4203886&postcount=13

Both the above posts are part of a larger discussion about using speech in TARGET here: https://forums.eagle.ru/showthread.php?t=262400

But I will repost the text to speech stuff here and add some comments which I did not make on the DCS forums.

Here is a working TARGET script that demonstrates how to do it.

Code
include "target.tmh"

// Disable Speak() output - disabled =0, enabled =1
define	SpeakEnabled	1

int main()
{
    if(Init(&EventHandle)) return 1; // declare the event handler, return on error

    Speak("Script Loaded");
    Speak("Press LDGH to say more");

    MapKey(&Throttle, LDGH, EXEC("Speak(\"Hello World\");"));
}

//******************************************************************
// Speak()
//	Text to Speech - this function uses Windows mshta.exe and a simple Visual Basic script to perform text to speech
//	text - the text or phrase to speak
//	The concept of using mshta vbscript was found here:  https://stackoverflow.com/questions/1040655/ms-speech-from-command-line
//	No extra programs are required for this to work.
int Speak(alias text)
{
    if (!SpeakEnabled) return 0;		// disable TextToSpeech sounds
    if (&text == "") return 0;			// exit if no parameter given

    //printf("Speaking:  %s\xa", &text);
    char buffer; Dim(&buffer, 256);
    sprintf(&buffer, "spawn mshta vbscript:Execute(\"CreateObject(\"\"SAPI.SpVoice\"\").Speak(\"\"%s\"\")(window.close)\")", &text);
    system(&buffer);
}

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


The key part is the "spawn mshta" line. This uses mshta.exe, a program that is part of Windows (assuming you didn't uninstall Internet Explorer) which runs .HTA files. HTA files are HTML Applications, a type of file I had not heard of before, but which are basically HTML files that have scripted programming in them (VBScirpt, JScript, etc.) which run at a higher level of authority, like a normal application. For more information, check out this link:
https://en.wikipedia.org/wiki/HTML_Application

But more importantly, in the example above, no external script file is needed. I'm not even calling an external .HTA file. Instead of using system(spawn...) to call an external script file, we use the vbscript:Execute() function to pass the call to SAPI.SpVoice directly to mshta.exe without using an external script file.

I've been trying many ideas to do this kind of thing without using external batch files or having to download executable files from other sources. When I share a TARGET script with someone, I like the idea of just being able to give them the .tmc and .ttm files. So this example achieves that.

#4507736 - 02/18/20 03:05 AM Re: Advanced Question: system(spawn) and running external scripts [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
I was able to get Text to Speech to work in TARGET.


Hi there.

This seems pretty interesting stuff, but I wasn't able to get any sound out of the above code...

Instead, I'm getting Windows Defender warnings about the threat Trojan:Win32/Kovter.G from the execution of the vbscript cmd line...

Am I doing something wrong, or shouldn't I expect to hear a voice saying "Hello World"?

#4507741 - 02/18/20 03:44 AM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: Jul 2016
Posts: 61
Drakoz Offline
Junior Member
Drakoz  Offline
Junior Member

Joined: Jul 2016
Posts: 61
Do you have the mshta.exe program in your Windows directory (C:\Windows\system32\mshta.exe and C:\Windows\SysWOW64\mshta.exe)? HTML Applications (the thing I am using to do this) may not work on all computers. For example, if you have uninstalled (or never installed) Internet Explorer, I don't think this will work. Also, HTML Applications are probably going away in the future. They are definitely not being developed anymore by Microsoft because there are other standards the industry has moved to for executing code on a web page.

Try this... Open up a Windows CMD prompt and copy and paste the command below into the CMD prompt. This will bypass any issues with using TARGET.

Code
mshta vbscript:Execute("CreateObject(""SAPI.SpVoice"").Speak(""Hello World"")(window.close)")


It should say Hello World. If the above doesn't work, did you get any error message? Did you check that you actually have mshta.exe installed?

Sadly, I have a feeling this will not universally work for everyone, and it may not be a long term solution as HTML Applications will probably be deprecated from Windows in a few years.

#4507755 - 02/18/20 08:11 AM Re: Advanced Question: system(spawn) and running external scripts [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
Do you have the mshta.exe program in your Windows directory (C:\Windows\system32\mshta.exe and C:\Windows\SysWOW64\mshta.exe)? HTML Applications (the thing I am using to do this) may not work on all computers.
Yes I have it in both locations.

Quote
For example, if you have uninstalled (or never installed) Internet Explorer, I don't think this will work. Also, HTML Applications are probably going away in the future. They are definitely not being developed anymore by Microsoft because there are other standards the industry has moved to for executing code on a web page.
I have IE installed.

Quote
Try this... Open up a Windows CMD prompt and copy and paste the command below into the CMD prompt. This will bypass any issues with using TARGET.

Code
mshta vbscript:Execute("CreateObject(""SAPI.SpVoice"").Speak(""Hello World"")(window.close)")


It should say Hello World. If the above doesn't work, did you get any error message?
I got an "Access Denied" message... and I still get Windows Security threat warning, maybe this is the one that is blocking the execution of the code...

Quote
Did you check that you actually have mshta.exe installed?
Yes.

#4507785 - 02/18/20 02:33 PM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: Jul 2016
Posts: 61
Drakoz Offline
Junior Member
Drakoz  Offline
Junior Member

Joined: Jul 2016
Posts: 61
Yes, it is a windows security issue. I was afraid of that. Sadly, this will likely be an issue for many people, making text to speech not viable for everyone. Seems differences in security settings is a common issue.

Try running the CMD prompt as administrator (right click on the CMD prompt and say 'run as administrator'". If that works, then it is probably a security issue with your login. Is your login set to have administrator rights? If this is the case, it might be possible to run TARGET as administrator and it will work, though that should not be necessary.

If that doesn't work, it might be an issue with the Internet Explorer security settings. Check the Internet Settings control panel. I am referring to the old control panel as explained in this web page: https://www.isunshare.com/windows-10/4-ways-to-open-internet-options-in-windows-10.html. Maybe temporarily set it to the lowest setting to see if it works - there is a simple slider to do this with. Then adjust setting to higher and higher setting until it doesn't work (back to what you had it at originally). There are dozens of settings for security IE, and quite a few of them would cause this not to work. We are, after all, running an executable program using Internet Explorer, so you can imagine the potential for abuse.

Last, maybe it is your virus software. Maybe disable your virus software temporarily and see if that works.

What version of Windows are you running (Win 10, but also what update, 1909, 1903, etc.)? Just curious for now.

#4507804 - 02/18/20 05:27 PM Re: Advanced Question: system(spawn) and running external scripts [Re: Drakoz]  
Joined: May 2001
Posts: 468
Joao Muas Offline
Member
Joao Muas  Offline
Member

Joined: May 2001
Posts: 468
Portugal
I ran CMD as administrator already, same result...
And I'm not using any anti-virus software other than the default Windows Security.
Left with messing around with the IE settings.
My OS is Win10 1903.

#4507843 - 02/18/20 09:52 PM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: Jul 2016
Posts: 61
Drakoz Offline
Junior Member
Drakoz  Offline
Junior Member

Joined: Jul 2016
Posts: 61
Hmm. Ya, hopefully you can find something in the IE Internet Settings.

I was running Windows 10 1809, and just updated to 1909 and it works for me in both cases. My Windows 10 install was freshly installed about 1.5 years ago (not updated from a previous install). I'll try testing this on some of my other Windows machines and see what else I can find.

#4507857 - 02/18/20 11:51 PM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: May 2001
Posts: 468
Joao Muas Offline
Member
Joao Muas  Offline
Member

Joined: May 2001
Posts: 468
Portugal
IT WORKS!!

My previous testing was on my Laptop, and it was not working...
I tried it again in my main PC (also Win10 1903) and after I opened IE (maybe for the first time?!?) and messing around with some settings it started to work... I don't know exactly what made it work, because I ended up putting all settings back as they were and it still kept working...

Now I have all my profile changes announced by voice!! Just need to make it announce only the last profile, otherwise, with fast changes, the announcement gets out of sync.

But this opens up inumerous possibilities of announcing some less obvious button presses, (like the TEMPO feature, modes U/M/D, etc.) specially when using the T16000 with no visual status of the buttons state.
Thank a lot! This is really useful!!


#4507863 - 02/19/20 02:21 AM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: Jul 2016
Posts: 61
Drakoz Offline
Junior Member
Drakoz  Offline
Junior Member

Joined: Jul 2016
Posts: 61
Cool, glad you got it working. Ya, gotta watch the lag (don't use multiple statements stacked up).

BTW, I just checked this on one of my Windows 7 setups (a virtual machine on my Mac) and it worked.

#4512959 - 03/26/20 11:38 PM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: Mar 2020
Posts: 12
dmonds Offline
Junior Member
dmonds  Offline
Junior Member

Joined: Mar 2020
Posts: 12
Auckland, New Zealand
Hi,

I use a small win32 app called voice.exe I got from https://www.elifulkerson.com/projects/commandline-text-to-speech.php.

Works well.

Here's my code to get it working under Win10 1909...

Code


alias VoicePath				= "d:\\Thrustmaster\\TargetScript\\voice.exe";
int VoiceVolume				= 75;
alias VoiceCMD				= "-n \"Microsoft Catherine\"";
int EnableVoice				= 1; 					// 0 = Disable, 1 = Enable. Enable this if you wish to use "voice.exe". 

char SysCmd;                                // Dynamically build command to send to system()

	int fnTextToSpeech(int text) {
		char volume;
		Dim (&volume, 4);
		volume[0] = 0;
		
		if (VoiceVolume) {
			sprintf(&volume, "%d", VoiceVolume);		
		}
		else {
			strcat(&volume, "75");
		}
		
		if (EnableVoice) {
			Dim(&SysCmd, 255);										// Increase buffersize if required
			SysCmd[0] = 0;
			strcat(&SysCmd, "start ");								// Starts command and returns immediately after speaking, removing the lag
			strcat(&SysCmd, &VoicePath);							// 'VoicePath' alias defined globally
			strcat(&SysCmd, " -v ");								// Seperate 'path' from 'arguments'
			strcat(&SysCmd, &volume);								// include volume argument
			strcat(&SysCmd, " ");									// Seperate arguments with a 'space'			
			strcat(&SysCmd, &VoiceCMD);								// 'VoiceCMD' alias defined globally 
			strcat(&SysCmd, " ");									// Seperate command from text with a 'space'
			strcat(&SysCmd, text);
			
			system(&SysCmd);										// send command to Windows
		}
	}
	

	// FUNCTION:	Volume Controller for 'voice' exe / fnTextToSpeech()
	// Parameter:	'x'. x=0 Decrease, x=1 Increase
	
	int fnVoiceVolume(int x) {

		char vol;													// for text value of VoiceVolume
		Dim(&vol, 4);
		vol[0] = 0;
		
		char c;														// for our VoiceTxt string to send to fnTextToSpeech()
		Dim(&c, 50);
		c[0] = 0;
		
		strcat(&c, "Voice volume ");								// ... start building the string
		
		if (x) {													// INCREASE Volume
			VoiceVolume = VoiceVolume + 5;
			
			if (VoiceVolume > 100) {
				VoiceVolume = 100;
				strcat(&c, "at maximum, ");
			}
			else {
				strcat(&c, "increased to ");			
			}
		}
		else {														// DECREASE Volume
			VoiceVolume = VoiceVolume - 5;
			
			if (VoiceVolume < 5) {
				VoiceVolume = 5;
				strcat(&c, "at minimum, ");
			}
			else {
				strcat(&c, "decreased to ");			
			}
		}
		sprintf(&vol, "%d", VoiceVolume);							// Convert integer to string
		strcat(&c, &vol);
		
		strcat(&c, " percent");
		
		printf("%s\x0a", &c);										// print our string
		fnTextToSpeech(&c);											// send to TextToSpeech
	}



AS you can see, I dynamically build a System() command.
I've included an example on how to use the command line switches like volume and nominating a specific voice (must be installed to use)

Edit: you may also replace the individual strcat() statements with;

sprintf(&SysCmd, "start %s -v %s %s %s", &VoicePath, &volume, &VoiceCMD, text);

...they both do the same thing.


I've also included a Volume Control function I use...just need to map to a switch or button etc.

Zero Lag but if you queue up multiple calls the speech will overlap as each call runs in parallel with the script.

Hope you find this useful.

dmonds

Last edited by dmonds; 03/27/20 11:44 PM.
#4513170 - 03/28/20 02:16 PM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: Jul 2016
Posts: 61
Drakoz Offline
Junior Member
Drakoz  Offline
Junior Member

Joined: Jul 2016
Posts: 61
I'll have to check out voice.exe as an alternative. I liked the mshta method because it doesn't require installing any extra software to work, but since some people have troubles getting it to work, I may have to abandon it for scripts I intend to share.

dmonds, A few comments on alternate ways to do some of the things you did in your script..... (these comments are mainly food for thought, including several things I haven't actually fully tested yet)

Yes, you mentioned the alternate method of using sprintf() instead of strcat(). I have tended to use sprintf() to build strings because being a single line, it is easier to see what string we are building (less code). Either is fine of course.

Variables such as SysCmd should be defined inside the function that uses them unless there is a particular need for it to be global. We discussed this before. So for example, instead of char SysCmd; outside the function, I would normally just do this:

char SysCmd; Dim (&volume, 4);

All in a single line because the char and Dim are all defining a single variable buffer. Doing it in a single line vs. two lines is a personal style preference, but the key point is, don't use a global unless there is a particular reason why you need it. So define the char locally (inside the function) along with the Dim().

If you actually need a string to be defined as a global, and you want to pass it into other functions (which requires the string to be referenced as an alias like &MyString), I believe you would create the string external to all functions as an array:

char gMyString[256]; // global var gMyString (defined outside any function)

and inside the function where you use it, I think you would have to do something like the following:

char mystring;
Map(&mystring, gMyString); Dim(&mystring, 256);

But I haven't tested this, and I'm pretty sure I got that statement wrong. There are many examples of Map(); Dim(); pairs in target.tmh that show what I am talking about, where Map() is used to map a local alias or variable to point to a global array of data or struct data structure.

Regarding spawn...

Spawn.exe is a program provided by Thrustmaster as part of TARGET. I haven't been able to confirm this yet, but it looks like spawn.exe is used to allow calling an extermal program with the system() command and allow that external program to execute in its own environment independently. So it may work exactly the same as using start, but again, I haven't taken the time to figure out the exact differences. For example, I don't remember if start works in Windows 7 or XP.

#4513444 - 03/30/20 04:28 AM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: Mar 2020
Posts: 12
dmonds Offline
Junior Member
dmonds  Offline
Junior Member

Joined: Mar 2020
Posts: 12
Auckland, New Zealand
Hi @Drakoz,

Thanks for the tips.

I agree and generally only use Globals when I need to share the contents/values across functions, or if I've not been able to get a local variable to work.
Such was the case when I was testing the voice.exe function.
TARGET kept throwing an error at run time (cannot remember off the top of my head), until I moved the 'char SysCmd;' statement outside of the function.

Thanks also for the tip and explanation of the Map() statement...I've never used this as I had no clue what it was for!
Is this a matter of proper coding practice, or, does it mitigate issues I may not be aware of?

Lastly, Spawn() worked in Win7 but I've not been able to get it to work on Win10.
Hence my system(&SysCmd); statements!

;-)

Cheers
dmonds

#4513477 - 03/30/20 11:05 AM Re: Advanced Question: system(spawn) and running external scripts [Re: HomeFries]  
Joined: Jul 2016
Posts: 61
Drakoz Offline
Junior Member
Drakoz  Offline
Junior Member

Joined: Jul 2016
Posts: 61
Map() is TARGET specific. It is not a normal C function, so not a matter of proper coding practice - just something Thrustmaster created to make TARGET work. Also, Map() has nothing to do with MapKey(). Well, it is used in MapKey(), but Map() is not some superset of MapKey(). It is something completely different.

Map() is used most in target.tmh to remap one variable to point to a different (usually more complex) variable. For example, the following is the definition for MapKey() from target.tmh:

Code
int MapKey(alias dev, int btnidx, int key=0, int layer=0)
{ 
	if(dev[btnidx]){ dev[btnidx] = 0; _evh(EV_HID_INPUT_DATA, &dev, btnidx); dev[btnidx] = 1;}
	layer = GetLayerBits(layer);
	GetDeviceData(&dev);
	Map(&btnidx, &&devdata.keymap+btnidx*KDATASIZE*4 + 24*!!(layer & 0x40)); Dim(&btnidx, 6);
	int i=6; while(i)     // cycle through all layers ou, iu, om, im, id, id and set btnidx = key for layers chosen by layer var bit = 1
	{
		i = i-1;
		if(layer & 1) btnidx[i] = key;
		layer = layer >> 1;
	}
}


Look at the Map(&btnidx, &&devdata.keymap+....) line including the Dim(&btnidx, 6) at the end of the line. This line is remapping &btnidx to point to a portion of the devdata.keymap data structure. Without going down the deep rabbit hole of understanding devdata, suffice to say that devdata.keymap is an array that stores all the key mappings as created by MapKey(), MapKeyIO(), etc. But accessing the data in devdata is messy to use the full devdata.keymap+btnidx*KDATASIZE*4 + 24*!!(layer & 0x40) code. So the Map() line above maps &btnidx to point the the specific 6 integers of devdata.keymap+btnidx*KDATASIZE*4 + 24*!!(layer & 0x40) that we care about. Those 6 integers store the key press data for the 6 layers (IO and UMD layers) that define the keypresses connected to a button or switch on a controller. So after the Map(&btnidx...) command, we can simply use btnidx[i] to access those 6 integers, where i = 0 through 5 (6 layers).

Hence we can do things like this:

if(layer & 1) btnidx[i] = key;

where btnidx[] allows MapKey() to fill out the IO and UMD array with key press info, but without having to access devdata.keymap+btnidx*KDATASIZE*4 + 24*!!(layer & 0x40). This is important not just to simplify devdata.keymap... down to btnidx[], but also because we can't access devdata.keymap....[] as an array in the way that we want to. So by remapping access to devdata.keymap... to btnidx[], life is much easier.

You may be confused that btnidx is part of devdata.keymap+btnidx*KDATASIZE*4 + 24*!!(layer & 0x40). That is just because btnidx is being reused for two different purposes. When we start MapKey(), btnidx refers to the button or switch number that was pressed (e.g. TG1, S1, HAT1U, etc.). But after the Map() line, btnidx now points to the 6 integers within devdata.keymap that we care about, and no longer refers to the joystick button.

Also, note that we define &btnidx (an alias) to point to a memory address located in the middle of devdata by using &&devdata.keymap+..... The && gives the address within devdata.keymap, or &&devdata.keymap+.... points to the memory address within devdata that points to the specific 6 integers we care about. Then we can access that data using btnidx[], an array. See how powerful that is?



Now go back to my example with strings. (again I have not tested this so I assume I have gotten some of this wrong or maybe this isn't even necessary, but understanding the concept is my point...)

char gMyString[256]; // global var gMyString (defined outside any function)

and inside a function....

char mystring;
Map(&mystring, gMyString); Dim(&mystring, 256);

Hence we have created an array of char, 256 bytes long, but to use it, we need an alias to point to it, &mystring, because in TARGET, you must use an alias to use strings in many cases. So the Map() function allows us to map &mystring to refer to the global char array, gMyString[].

But after writing all that, I realize probably the main thing I have wrong is that you can probably just access the global string, gMyString, directly with &gMyString since we already defined it as an array of char, 256 bytes long. But again, the point of saying all this is to help point out ways you might need to or want to use aliases and Map() to access and manipulate strings. This is not something that has been done in target.tmh, but I can see there may be some reasons why we might want to use Map() with strings.

Specifically, once I was trying to create a function that built strings for passing to EXEC() or REXEC() functions like the following:

MapKey(&Joystick, HAT1U, EXEC(&mystring) );

...but to be able to create those strings within a function like above, but have those string exist globally after creating them. This is because EXEC() must store a string as a parameter to be accessed later. But if we create that string within a function that is not global, we loose it, or rather we can loose access to it. But by using a global alias to refer to memory created locally within a function, we can preserve access to the string for EXEC(). I never tested this concept as I gave up on the project.

Joao, if you are reading all this, I am talking my attempt to make all hats work 8 way from your request a couple years ago. I failed at that because I couldn't get EXEC(&mystring) to work where &mystring referred to a variable string that changed every time you pressed a hat swtich. Back then I didn't understand all that I know about strings now. I could probably get the 8 way hat thing to work today, given what I have learned, and it may require using the Map() thing I discuss above.

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
Actors portraying US Presidents
by PanzerMeyer. 04/19/24 12:19 PM
Dickey Betts was 80
by Rick_Rawlings. 04/19/24 01:11 AM
Exodus
by RedOneAlpha. 04/18/24 05:46 PM
Grumman Wildcat unique landing gear
by Coot. 04/17/24 03:54 PM
Peter Higgs was 94
by Rick_Rawlings. 04/17/24 12:28 AM
Whitey Herzog was 92
by F4UDash4. 04/16/24 04:41 PM
Anyone can tell me what this is?
by NoFlyBoy. 04/16/24 04:10 PM
10 Years ago MV Sewol
by wormfood. 04/15/24 08:25 PM
Pride Of Jenni race win
by NoFlyBoy. 04/15/24 12:22 AM
Copyright 1997-2016, SimHQ Inc. All Rights Reserved.

Powered by UBB.threads™ PHP Forum Software 7.6.0