Using dragonfly2, the voice command framework, you can make a grammar like so:
chrome_rules = MappingRule(
name='chrome',
mapping={
'down [<n>]': actions.Key('space:%(n)d'),
},
extras=[
IntegerRef("n", 1, 100)
],
defaults={
"n": 1
}
)
This lets me press space n times, where n is some integer. But what do I do if I want to use the same variable (n), multiple times in the same grammar? If I repeat it in the grammar, e.g. 'down <n> <n>' and then say something like "down three four", Dragonfly will parse it correctly, but it will only execute the actions.Key('space:%(n)d') with n=3, using the first value of n. How can I get it to execute it 3 times, and then 4 times using the same variable?
Ideally I don't want to have to duplicate the variable n, in the extras and defaults, because that seems like redundant code.
TL;DR: Your
MappingRulepasses data to yourAction(e.g.Key,Text) in the form of a dictionary, so it can only pass one value per extra. Your best bet right now is probably to create multiple extras.This is a side-effect of the way dragonfly parses recognitions. I'll explain it first with
Actionobjects, then we can break down why this happens at theRulelevel.When Dragonfly receives a recognition, it has to deconstruct it and extract any extras that occurred. The speech recognition engine itself has no trouble with multiple occurrances of the same extra, and it does pass that data to dragonfly, but dragonfly loses that information.
All
Actionobjects are derived fromActionBase, and this is the method dragonfly calls when it wants to execute anAction:This is how
Textworks, same withKey. It's not documented here, butdatais a dictionary of extras mapped to values. For example:See the issue? That means we can only communicate a single value per extra. Even if we combine multiple actions, we have the same problem. For example:
Under the hood, these two actions are combined into an
ActionSeriesobject - a single action. It exposes the sameexecuteinterface. One series of actions, onedatadict.Note that this doesn't happen with compound rules, even if each underlying rule shares an extra with the same name. That's because
datais decoded & passed per-rule. Each rule passes a differentdatadict to theActionit wishes to execute.If you're curious where we lose the second extra, we can navigate up the call chain.
Each rule has a
process_recognitionmethod. This is the method that's called when a recognition occurs. It takes the current rule'snodeand processes it. Thisnodemight be a tree of rules, or it could be something lower-level, like anAction. Let's look at the implementation inMappingRule:I'm going to skip some complexity - the
extrasvariable you see here is an early form of thedatadictionary. See where we lose the value?Which looks like:
So, you see the issue. Dragonfly tries to extract one value for each extra, and it gets the first one. Then, it stuffs that value into a dictionary and passes it down to
Action. Additional occurrences are lost.