-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Closed
Labels
In-PR 🚀feature request 📬A request for new changes to improve functionalityA request for new changes to improve functionalityhelpers ✋in progress 🚧
Description
It would be nice if you could assign VoiceCommands to buttons using the UWP SpeechRecognizer. Maybe this must not be limited to buttons only.
<Button Click="ButtonSave_Click"
Content="Save">
<Button.VoiceCommands>
<VoiceCommand Text="Save" />
<VoiceCommand Text="Store it" />
</Button.VoiceCommands>
</Button>
Describe the solution
There are a lot of ways to implement this. You can create Attached Properties or use Behaviors. Not sure what the correct path is. I have created this issue to start the discussion.
Describe alternatives you've considered
As a test I have created this VoiceCommandTrigger (Behavior). It works fine. Not sure if this is the right path. It uses the Microsoft.Xaml.Behaviors.Uwp.Managed NuGet package.
public class VoiceCommandTrigger : Trigger {
public string Text {
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(nameof(Text), typeof(string), typeof(VoiceCommandTrigger), new PropertyMetadata(default(string), OnTextPropertyChanged));
private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var source = d as VoiceCommandTrigger;
if (source != null) {
var newValue = (string)e.NewValue;
var oldValue = (string)e.OldValue;
if (!string.IsNullOrEmpty(oldValue)) {
_triggers.Remove(oldValue);
}
if (!string.IsNullOrEmpty(newValue)) {
_triggers[newValue] = source;
}
}
}
private static SpeechRecognizer _sr;
private static readonly Dictionary<string, VoiceCommandTrigger> _triggers = new Dictionary<string, VoiceCommandTrigger>(StringComparer.InvariantCultureIgnoreCase);
static VoiceCommandTrigger() {
Task.Run(async () => {
_sr = new SpeechRecognizer();
_sr.ContinuousRecognitionSession.AutoStopSilenceTimeout = TimeSpan.MaxValue;
await _sr.CompileConstraintsAsync();
_sr.ContinuousRecognitionSession.ResultGenerated += ContinuousRecognitionSession_ResultGenerated;
await _sr.ContinuousRecognitionSession.StartAsync();
});
}
private static void ContinuousRecognitionSession_ResultGenerated(SpeechContinuousRecognitionSession sender, SpeechContinuousRecognitionResultGeneratedEventArgs args) {
Debug.WriteLine(args.Result.Text);
if (_triggers.TryGetValue(args.Result.Text, out var trigger)) {
_ = trigger.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
Interaction.ExecuteActions(trigger.AssociatedObject, trigger.Actions, args);
});
}
}
protected override void OnAttached() {
base.OnAttached();
_triggers[this.Text] = this;
}
protected override void OnDetaching() {
if (_triggers[this.Text] == this) {
_triggers.Remove(this.Text);
}
}
}
public class ClickAction : DependencyObject, IAction {
public object Execute(object sender, object parameter) {
if (sender is Button btn && btn.IsEnabled) {
var peer = new ButtonAutomationPeer(btn);
var invokeProv = peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
invokeProv?.Invoke();
}
return null;
}
}
In the following XAML I have use the VoiceCommandTrigger.
<Button Content="Speak" Height="153" Margin="138,460,0,0" VerticalAlignment="Top" Width="420"
Click="Button_Click">
<Custom:Interaction.Behaviors>
<local:VoiceCommandTrigger Text="Increase">
<Custom1:ChangePropertyAction PropertyName="Width" Value="500" />
</local:VoiceCommandTrigger>
<local:VoiceCommandTrigger Text="Decrease">
<local:ClickAction />
</local:VoiceCommandTrigger>
</Custom:Interaction.Behaviors>
</Button>
The used Button_Click method
private void Button_Click(object sender, RoutedEventArgs e) {
(sender as Button).Width -= 100;
}
niels9001, azchohfi, jamesmcroft and OneFingerCodingWarrior
Metadata
Metadata
Assignees
Labels
In-PR 🚀feature request 📬A request for new changes to improve functionalityA request for new changes to improve functionalityhelpers ✋in progress 🚧