VBScript "Do Until" keypress - Possible?

Experts,

I'm playing with a VBScript that's using the SAPI.SpVoice - and it's going fairly easily...

Except, sometimes the computer can be fairly long winded when it's reading one of my variables I'm feeding it.

Currently, the script is VERY basic, but I'd like to add the ability to make the computer STOP talking when I hit any key / mouse click.

Is this an option?


        Dim objSpeech

        Set objSpeech = CreateObject("SAPI.SpVoice")
        ReadString = "Blah blah blah . . ."

        objSpeech.speak ReadString, SVSFlagsAsync + SVSFPurgeBeforeSpeak

Open in new window




I was thinking of doing something like:

Do Until ***User presses a key / clicks the mouse***
    objSpeech.speak ReadString, SVSFlagsAsync + SVSFPurgeBeforeSpeak
Loop



If anybody has any ideas on how to make this happen, I would be very greatful.
LVL 5
usslindstromAsked:
Who is Participating?
 
RobSampsonConnect With a Mentor Commented:
Hi, here's a HTA that I just got working.  Save the code into a file with a .HTA extension, and run it.  Clicking the button will toggle the speech on and off.

Regards,

Rob.

<html>
<head>
<title>Test</title>
<HTA:APPLICATION 
	ID = "objHTA"
	APPLICATIONNAME="Test"
	BORDER="dialog"
	SCROLL="no"
	SINGLEINSTANCE="yes"
	WINDOWSTATE="normal"
	Maximizebutton="no"
	ContextMenu="no"
>
<html>
	<head>
		<script language="vbscript">
	        
	        Dim objSpeech, ReadString
	        Const SVSFPurgeBeforeSpeak = 2
	        Const SVSFlagsAsync = 1
	        
			Sub Window_OnLoad
				intWidth = 800
				intHeight = 600
				Me.ResizeTo intWidth, intHeight
				Me.MoveTo ((Screen.Width / 2) - (intWidth / 2)),((Screen.Height / 2) - (intHeight / 2))
	        	Set objSpeech = CreateObject("SAPI.SpVoice")
				blnSpeaking = False
	        	ReadString = "This is a test message to see whether the computer is speaking or not."
			End Sub

			Sub Speak
				If objSpeech.Status.RunningState = 1 Then
					objSpeech.Speak ReadString, SVSFlagsAsync + SVSFPurgeBeforeSpeak
				Else
					objSpeech.Speak " ", SVSFlagsAsync + SVSFPurgeBeforeSpeak
				End If
			End Sub			
			
		</script>
	</head>
	<body>
		<input type="button" id="btn_speak" name="btn_speak" value="Toggle Speech" onclick="Speak">
	</body>
</html>

Open in new window

0
 
micropc1Connect With a Mentor Commented:
0
 
RobSampsonCommented:
VBScript can't hook into Windows events to know when a key is pressed or the mouse is moved, but if you were to build a HTA, then the windows.event.keycode method that micropc1 pointed to can be used.

When you launch the HTA, you can have it start reading the string, and capture any keypresses on the HTA's "form".

Regards,

Rob.
0
What Kind of Coding Program is Right for You?

There are many ways to learn to code these days. From coding bootcamps like Flatiron School to online courses to totally free beginner resources. The best way to learn to code depends on many factors, but the most important one is you. See what course is best for you.

 
usslindstromAuthor Commented:
Thank you both very much for the assistance.

I may need a bit more of a nudge if you guys have a few seconds.  Using this code (from the link that micropc1 provided)

I created a Boolian value that I'm "flipping the switch" on before and after the text to speech:

        SpeechInProgress = "True"

        objSpeech.speak ReadString, SVSFlagsAsync + SVSFPurgeBeforeSpeak

        SpeechInProgress = "False"

Open in new window



And then for testing I have the onClick for the Document...

Sub Document_onClick()
    If SpeechInProgress Then
        msgbox "Speech in Progress."
    Else
        Msgbox "No Speaka' da' Englais"
    End If

Open in new window




Unfortunately, the little program just sits and waits until the speech has finished, before it executes the SubRoutine.  Of course, once the speech api has finished, the 2nd msgbox is displayed.
0
 
RobSampsonCommented:
Note that I think one of your issues with it not showing the message until the speech finished is that you didn't have the constants defined with their values.

Rob.
0
 
usslindstromAuthor Commented:
Holy crap!  You just did all of my work for me.  :)

Sorry it took a bit to respond here.  I was reading into what you were trying to show me and understand it completely, instead of just copy/pasting.

As it turns out, your HTA worked absolutely flawlessly - but I couldn't get mine to do anything other than what was described before.  (The computer would drone on and on about mission statements.  :)  * I felt like I was attending regularly schedule office meetings.  :) )

You're comment about the constants got me in the right direction.  I didn't declare those constants at ALL.  - Unfortunately, as soon as I set them though the computer stopped talking completely.  Not a peep.

So, instead of delcaring the constants, I just threw them as their numbers after the objSpeech.speak ReadString, *HERE* arguments.  - And now it works as required.

I could not have put it together AT ALL without your help, and it's VERY much appreciated.  People around the office here are either going to love the option, or just get tired of Microsoft Sam all together.  Either or, it's shaping out to be some very cool stuff, all thanks to you.
0
 
RobSampsonCommented:
OK, no problem.  I'm not sure why the constants didn't work for you, but yes, using their numeric values directly is another option.  Just so you now, I got the "status" code from here:
http://msdn.microsoft.com/en-us/library/ms722534(v=vs.85).aspx

You can change voices (if you have more installed), volume, pitch, and other cool stuff too.  Have a look through here:
http://msdn.microsoft.com/en-us/library/ms723602(v=vs.85).aspx

Finally, did you want help getting it to work based on pressing a key or moving the mouse?  That can be done, I'm sure....

Regards,

Rob.
0
 
usslindstromAuthor Commented:
Now that it's working, actually - I'm thinking of doing an image swap in the HTML.

Currently, in order for the text-to-speech to get acted on, the user will click on a small speaker icon in the bottom right of the form.

I'm thinking at this point, now that everything's working VERY well (Thank you for your help) - That I'll keep the control to the "onclick" function of the button.

I think it would be VERY professional looking if I just swapped the speaker button to the same pic, but with a Circle and a Line through it indicated to the user to make the computer stop talking, they push the button again.

Not sure how I'm going to pull it off, but that's the thought process.
0
 
RobSampsonCommented:
Hi, that sounds perfectly achievable.....one thing you might like to try doing is have the page also identify when the speech has stopped, and get it to change the "cancel" back to a "speak" button as well....I'll see if I can knock something up....

Rob.
0
 
RobSampsonCommented:
Actually, turns out far easier that I though, utilising a HTML Timer control.

Check this out.  It uses text instead of images, but shouldn't be hard to change.

Regards,

Rob.

<html>
<head>
<title>Test</title>
<HTA:APPLICATION 
	ID = "objHTA"
	APPLICATIONNAME="Test"
	BORDER="dialog"
	SCROLL="no"
	SINGLEINSTANCE="yes"
	WINDOWSTATE="normal"
	Maximizebutton="no"
	ContextMenu="no"
>
<html>
	<head>
		<script language="vbscript">
	        
	        Dim iTimerID, objSpeech, ReadString
	        Const SVSFPurgeBeforeSpeak = 2
	        Const SVSFlagsAsync = 1
	        
			Sub Window_OnLoad
				iTimerID = window.setInterval("CheckSpeech", 500)
				intWidth = 800
				intHeight = 600
				Me.ResizeTo intWidth, intHeight
				Me.MoveTo ((Screen.Width / 2) - (intWidth / 2)),((Screen.Height / 2) - (intHeight / 2))
	        	Set objSpeech = CreateObject("SAPI.SpVoice")
	        	ReadString = "This is a test message to see whether the computer is speaking or not."
			End Sub

			Sub Speak
				If objSpeech.Status.RunningState = 1 Then
					objSpeech.Speak ReadString, SVSFlagsAsync + SVSFPurgeBeforeSpeak
					btn_speak.Value = "Mute"
				Else
					objSpeech.Speak " ", SVSFlagsAsync + SVSFPurgeBeforeSpeak
					btn_speak.Value = "Speak"
				End If
			End Sub			
			
			Sub CheckSpeech
				If objSpeech.Status.RunningState = 1 Then
					btn_speak.Value = "Speak"
				Else
					btn_speak.Value = "Mute"
				End If
			End Sub
		</script>
	</head>
	<body>
		<input type="button" id="btn_speak" name="btn_speak" value="Speak" onclick="Speak">
	</body>
</html>

Open in new window

0
 
RobSampsonCommented:
Here's another version that works with images ;-)

Rob.

<html>
<head>
<title>Test</title>
<HTA:APPLICATION 
	ID = "objHTA"
	APPLICATIONNAME="Test"
	BORDER="dialog"
	SCROLL="no"
	SINGLEINSTANCE="yes"
	WINDOWSTATE="normal"
	Maximizebutton="no"
	ContextMenu="no"
>
<html>
	<head>
		<script language="vbscript">
	        
	        Dim iTimerID, objSpeech, ReadString
	        Const SVSFPurgeBeforeSpeak = 2
	        Const SVSFlagsAsync = 1
	        
			Sub Window_OnLoad
				iTimerID = window.setInterval("CheckSpeech", 500)
				intWidth = 800
				intHeight = 600
				Me.ResizeTo intWidth, intHeight
				Me.MoveTo ((Screen.Width / 2) - (intWidth / 2)),((Screen.Height / 2) - (intHeight / 2))
	        	Set objSpeech = CreateObject("SAPI.SpVoice")
	        	ReadString = "This is a test message to see whether the computer is speaking or not."
			End Sub

			Sub Speak
				If objSpeech.Status.RunningState = 1 Then
					objSpeech.Speak ReadString, SVSFlagsAsync + SVSFPurgeBeforeSpeak
					span_speak.innerHTML = "<img id=""btn_speak"" name=""btn_speak"" src=""speaker_on.jpg"" onclick=""Speak"" onmouseover=""btn_speak.style.cursor='hand'"">"
				Else
					objSpeech.Speak " ", SVSFlagsAsync + SVSFPurgeBeforeSpeak
					span_speak.innerHTML = "<img id=""btn_speak"" name=""btn_speak"" src=""speaker_off.jpg"" onclick=""Speak"" onmouseover=""btn_speak.style.cursor='hand'"">"
				End If
			End Sub			
			
			Sub CheckSpeech
				If objSpeech.Status.RunningState = 1 Then
					span_speak.innerHTML = "<img id=""btn_speak"" name=""btn_speak"" src=""speaker_on.jpg"" onclick=""Speak"" onmouseover=""btn_speak.style.cursor='hand'"">"
				Else
					span_speak.innerHTML = "<img id=""btn_speak"" name=""btn_speak"" src=""speaker_off.jpg"" onclick=""Speak"" onmouseover=""btn_speak.style.cursor='hand'"">"
				End If
			End Sub
		</script>
	</head>
	<body>
		<span id="span_speak"><img id="btn_speak" name="btn_speak" src="speaker_on.jpg" onclick="Speak" onmouseover="btn_speak.style.cursor='hand'"></span>
	</body>
</html>

Open in new window

0
 
usslindstromAuthor Commented:
ABSOLUTELY BRILLIANT!

When I implemented your last suggestion, it turned out better than I could have even imagined!

I'm going to be including your name in the script "credits" if that's alright.
0
 
RobSampsonCommented:
Yeah, that's totally fine.  Thanks.  I like it when stuff works better that we'd hoped ;-)

Rob.
0
 
usslindstromAuthor Commented:
Just for ref, I ended it making it a little easier on the processor (If anybody references this EE page to accomplish the same sort of task)...

Instead of replacing the image on each pass through, I thew a Variable in the mix that sees if a change is needed.  - Not much of a change, but I'd imagine the little HTA has a tiny bit more breathing room on CPU cycles.  :)

    Sub CheckSpeech
        If SpeechStatus <> objSpeech.Status.RunningState Then
            SpeechStatus = objSpeech.Status.RunningState
            If objSpeech.Status.RunningState = 1 Then
                SP_TextToSpeech.InnerHTML = "<img src=""Images/Button_Spkr_On.gif"" Height=10 Width=13 onclick=""TextToSpeech"" style=""cursor:pointer"" style=""float:right"">"
            Else
                SP_TextToSpeech.InnerHTML = "<img src=""Images/Button_Spkr_Off.gif"" Height=10 Width=13 onclick=""TextToSpeech"" style=""cursor:pointer"" style=""float:right"">"
            End If
        End If
      End Sub

Open in new window

0
 
RobSampsonCommented:
Yep cool.  Good idea.  I set the timer to 500 milliseconds, so if timing is all that critical you could increase that value as well.

Rob.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.