Macro of the Day: Mute the speakers!
A user wrote in to me via my blog the other day and asked:
“Is there a way to control volume using WSR? I can't find any command that will do it. Can you point to a WSR Macro that might help me? Thanks for any help you can give.”
Great question. Vista’s Windows Speech Recognition doesn’t have such a voice command built-in, but with WSR Macros, it can be added. With today’s macro, you can say:
Turn off the speakers
Turn on the speakers
Turn the speakers off
Turn the speakers on
Mute ?the speakers
Mute ?the audio
Un-mute ?the speakers
Un-mute ?the audio
In addition, I thought I’d also add a few other commands. Like:
Increase/Decrease ?the volume
Increase/Decrease ?the volume ?by [1to100] ?times
And:
Set the volume to [1to100]
If that’s what can be done, how does the macro do it? Another good question. For today’s macro, I am simply emulating the sending of application commands, otherwise known as WM_APPCOMMAND messages. To learn more about that, you can read about WM_APPCOMMAND on MSDN here.
Here’s what the macro looks like in total:
<speechMacros>
<!--
This macro demonstrates how to use the <sendMessage> element.
It also demonstrates how to use WM_APPCOMMAND via the
<sendMessage> element.WM_APPCOMMAND is documented on MSDN here:
https://msdn.microsoft.com/en-us/library/ms646275(VS.85).aspxWM_APPCOMMAND is defined as 0x319 in WINUSER.H, which is
793 in decimalWM_APPCOMMAND's wParam needs to be set to the window that
generated the command.For this macro, we're pretending that the window that
generated the command is the desktop window (whose handle
can be retrieved by calling GetDesktopWindow()).On Windows Vista and Windows XP, it turns out that the
desktop window handle is always set to 0x000010010 (or 793
in decimal). Thus for each SendMessage in this macro, we'll
set the wParam to that value (793).WM_APPCOMMAND's lParam needs to be set to the a combination
of the application command to generate, combined with what
device generated the command, and also combined with any
keyboard modifiers that are held down at the same time.For this macro, we'll always set the device to be
FAPPCOMMAND_KEY (0).For this macro, we'll always set the keyboard modifiers to
none (0).Thus, the lParam ends up just being the application command,
shifted into the right position in the lParam.APPCOMMAND_VOLUME_MUTE is 8,
APPCOMMAND_VOLUME_MUTE << 16 is 0x00080000, or 524288APPCOMMAND_VOLUME_DOWN is 9,
APPCOMMAND_VOLUME_DOWN << 16 is 0x00090000, or 589824APPCOMMAND_VOLUME_UP is 10,
APPCOMMAND_VOLUME_UP << 16 is 0x000A0000, or 655360Now that I've described (briefly) how the WM_APPCOMMAND works,
we'll also need to pick a specific window to send the
application command to. It turns out that it's not really
important where we send it, as long as that window doesn't
ever process the message. That way, the application command
will ultimately end up being handled by the system itself.One easy to find window that doesn't process these application
commands itself is the Start button. So ... the className can
be set to "Button" and the windowName can be set to "Start".-->
<command>
<listenFor>Turn off the speakers</listenFor>
<listenFor>Turn on the speakers</listenFor>
<listenFor>Turn the speakers off</listenFor>
<listenFor>Turn the speakers on</listenFor>
<listenFor>Mute ?the speakers</listenFor>
<listenFor>Mute ?the audio</listenFor>
<listenFor>Unmute ?the speakers</listenFor>
<listenFor>Unmute ?the audio</listenFor>
<setTextFeedback>Toggling audio mute...</setTextFeedback>
<sendMessage className="Button" windowName="Start" message="793" wParam="6552" lParam="524288"/>
</command><command>
<listenFor>[incOrDec] ?the volume</listenFor>
<listenFor>[incOrDec] ?the volume ?by 1 ?time</listenFor>
<listenFor>[incOrDec] ?the volume ?by [volumeTimes] ?times</listenFor>
<setTextFeedback>Changing the volume...</setTextFeedback>
<script language="vbscript">
<![CDATA[times = "{[times]}"
If times = "" Then times = "2"lParam = {[incOrDec.lParam]}
For i = 1 to Int(times) / 2
Application.SendMessage "Button", "Start", 793, 6552, lParam
Next]]>
</script>
</command><command>
<listenFor>Set the volume to [volumeTimes]</listenFor>
<emulateRecognition>Decrease the volume by 100</emulateRecognition>
<setTextFeedback>Setting the volume to {[volumeTimes]}...</setTextFeedback>
<waitFor seconds=".50" />
<emulateRecognition>Increase the volume by {[volumeTimes]}</emulateRecognition>
<setTextFeedback>Volume set to {[volumeTimes]}</setTextFeedback>
</command><command>
<listenFor>Show ?the volume</listenFor>
<setTextFeedback>Showing the volume</setTextFeedback>
<sendKeys>{WIN}</sendKeys>
<waitFor seconds=".750" />
<emulateRecognition>Move mouse to Volume</emulateRecognition>
<sendKeys>{WIN}</sendKeys>
</command>
<listenForList name="incOrDec" propname="lParam">
<item propval="655360">Increase</item>
<item propval="589824">Decrease</item>
</listenForList>
<numbers name="volumeTimes" start="2" stop="100" propname="times"/></speechMacros>
Comments
Anonymous
September 14, 2008
hi. i tried creating the macros and signing the macro but i get an error. 0x80004005 error. any idea what this means? i tried making simple macros using the macros tool like opening firefox but even that doesn't work. it just says can't create...Anonymous
September 15, 2008
This usually means that something has gone wrong with your signing certificate. You can create a new one by doing this:
- Right click on the Windows Speech Recognition Macros icon in the task bar.
- Select Security
- Select Create signing certificate...
- Follow the on screen instructions Try re-signing your macro.
- Anonymous
September 16, 2008
ah ha. got it fixed now. thank you =)