# encoding: ascii
# api: powershell
# title: Speech Recognition 2
# description: This version of the script supports using “*” to capture dictation. The result is that you can now write macros to look up words online, or pass parameters to a function (within the constraints of your voice recognition accuracy).
# version: 0.1
# type: module
# author: Joel Bennett
# license: CC0
# function: Update-SpeechCommands
# x-poshcode-id: 1195
# x-archived: 2011-11-20T07:41:20
# x-published: 2011-07-06T22:20:00
#
#
$null = [Reflection.Assembly]::LoadWithPartialName("System.Speech")
## Create the two main objects we need for speech recognition and synthesis
if(!$Global:SpeechModuleListener){ ## For XP's sake, don't create them twice...
$Global:SpeechModuleSpeaker = new-object System.Speech.Synthesis.SpeechSynthesizer
$Global:SpeechModuleListener = new-object System.Speech.Recognition.SpeechRecognizer
}
$Script:SpeechModuleMacros = @{}
## Add a way to turn it off
$Script:SpeechModuleMacros.Add("Stop Listening", { $script:listen = $false; Suspend-Listening })
$Script:SpeechModuleComputerName = ${Env:ComputerName}
function Update-SpeechCommands {
#.Synopsis
# Recreate the speech recognition grammar
#.Description
# This parses out the speech module macros,
# and recreates the speech recognition grammar and semantic results,
# and then updates the SpeechRecognizer with the new grammar,
# and makes sure that the ObjectEvent is registered.
$choices = new-object System.Speech.Recognition.Choices
foreach($choice in $Script:SpeechModuleMacros.GetEnumerator()) {
$g = New-Object System.Speech.Recognition.GrammarBuilder
$phrases = @($choice.Key -split "\s*\*\s*")
for($i=0;$i -lt $phrases.Count;$i++) {
if($phrases[$i].Length -gt 0) {
$g.Append( $phrases[$i] )
if($i+1 -lt $phrases.Count) {
$g.AppendDictation()
}
} elseif($i -eq 0) {
$g.AppendDictation()
}
}
$choices.Add( (New-Object System.Speech.Recognition.SemanticResultValue $g, $choice.Value.ToString()).ToGrammarBuilder() )
}
if($VerbosePreference -ne "SilentlyContinue") { $Script:SpeechModuleMacros.Keys |
ForEach-Object { Write-Host "$Computer, $_" -Fore Cyan } }
$builder = New-Object System.Speech.Recognition.GrammarBuilder "$Computer, "
$builder.Append((New-Object System.Speech.Recognition.SemanticResultKey "Commands", $choices.ToGrammarBuilder()))
$grammar = new-object System.Speech.Recognition.Grammar $builder
$grammar.Name = "Power VoiceMacros"
## Take note of the events, but only once (make sure to remove the old one)
Unregister-Event "SpeechModuleCommandRecognized" -ErrorAction SilentlyContinue
$null = Register-ObjectEvent $grammar SpeechRecognized `
-SourceIdentifier "SpeechModuleCommandRecognized" `
-Action { $_ = $event.SourceEventArgs.Result.Text; iex $event.SourceEventArgs.Result.Semantics.Item("Commands").Value }
$Global:SpeechModuleListener.UnloadAllGrammars()
$Global:SpeechModuleListener.LoadGrammarAsync( $grammar )
}
function Add-SpeechCommands {
#.Synopsis
# Add one or more commands to the speech-recognition macros, and update the recognition
#.Parameter CommandText
# The string key for the command to remove
[CmdletBinding()]
Param([hashtable]$VoiceMacros,[string]$Computer=$Script:SpeechModuleComputerName)
## Add the new macros
$Script:SpeechModuleMacros += $VoiceMacros
## Update the default if they change it, so they only have to do that once.
$Script:SpeechModuleComputerName = $Computer
Update-SpeechCommands
}
function Remove-SpeechCommands {
#.Synopsis
# Remove one or more command from the speech-recognition macros, and update the recognition
#.Parameter CommandText
# The string key for the command to remove
Param([string[]]$CommandText)
foreach($command in $CommandText) { $Script:SpeechModuleMacros.Remove($Command) }
Update-SpeechCommands
}
function Clear-SpeechCommands {
#.Synopsis
# Removes all commands from the speech-recognition macros, and update the recognition
#.Parameter CommandText
# The string key for the command to remove
$Script:SpeechModuleMacros = @{}
## Default value: A way to turn it off
$Script:SpeechModuleMacros.Add("Stop Listening", { Suspend-Listening })
Update-SpeechCommands
}
function Start-Listening {
#.Synopsis
# Sets the SpeechRecognizer to Enabled
$Global:SpeechModuleListener.Enabled = $true
Say "Speech Macros are $($Global:SpeechModuleListener.State)"
Write-Host "Speech Macros are $($Global:SpeechModuleListener.State)"
}
function Suspend-Listening {
#.Synopsis
# Sets the SpeechRecognizer to Disabled
$Global:SpeechModuleListener.Enabled = $false
Say "Speech Macros are disabled"
Write-Host "Speech Macros are disabled"
}
function Out-Speech {
#.Synopsis
# Speaks the input object
#.Description
# Uses the default SpeechSynthesizer settings to speak the string representation of the InputObject
#.Parameter InputObject
# The object to speak
# NOTE: this should almost always be a pre-formatted string,
# most objects don't render to very speakable text.
Param( [Parameter(ValueFromPipeline=$true)][Alias("IO")]$InputObject )
$null = $Global:SpeechModuleSpeaker.SpeakAsync(($InputObject|Out-String))
}
function Remove-SpeechXP {
#.Synopis
# Dispose of the SpeechModuleListener and SpeechModuleSpeaker
$Global:SpeechModuleListener.Dispose(); $Global:SpeechModuleListener = $null
$Global:SpeechModuleSpeaker.Dispose(); $Global:SpeechModuleSpeaker = $null
}
set-alias asc Add-SpeechCommands
set-alias rsc Remove-SpeechCommands
set-alias csc Clear-SpeechCommands
set-alias say Out-Speech
set-alias listen Start-Listener
Export-ModuleMember -Function * -Alias * -Variable SpeechModuleListener, SpeechModuleSpeaker