I asked a question on StackOverflow about a week ago. Since I’ve gotten no response there, I thought that I’ll post it here. Maybe someone has a solution. Before I get to the question, a short detour. If you are building custom grammars with the System.Speech API here’s a neat little trick that I found when assembling some complex grammars. If you spell the words in your grammar more like they sound than how they’re really spelled, the recognition engine often gives me better results. Let’s say you want to recognize the word “pun”. If you spell it “punn” in the grammar, the recognition is better. In addition to calibrating the audio settings, some creative rewriting of some words increases the recognition confidence. Especially on short words.
Now to the question:
Given the following sample code,
Choices choices = new Choices();
choices.Add(new GrammarBuilder(new SemanticResultValue("product", "<product/>")));
GrammarBuilder builder = new GrammarBuilder();
builder.Append(new SemanticResultKey("options", choices.ToGrammarBuilder()));
Grammar grammar = new Grammar(builder) { Name = Constants.GrammarNameLanguage };
grammar.Priority = priority;
_recognition.LoadGrammar(grammar);
How can I add additional words to the loaded grammar? I know this can be achieved both in native code and using the SpeechLib interop, but I prefer to use the managed library.
Update: What I want to achieve, is not having to load an entire grammar repeatedly because of individual changes. For small grammars I got good results by calling
_recognition.RequestRecognizerUpdate();
and then doing the unload of the old grammar and loading of a rebuilt grammar in the event:
void Recognition_RecognizerUpdateReached(object sender, RecognizerUpdateReachedEventArgs e)
For large grammars this becomes too expensive.
Update2: It actually works pretty well, and the performance is better than I first thought, but it still bothers me that I can’t add phrases to a loaded grammar. Anyone?
This is the last post in series on developing the navigate to an implementing method plugin. Here are links to the previous posts, part 1, part 2 and part 3.
Just to recap, the goal of the plugin is to be able to position the caret (what most people call the cursor), on a method call on an interface variable and navigate to specific implementations of the method.
In this post we’ll look at how we navigate to the correct method.
The call to navigate is made when the navigation provider (part of CodeRush) receives the navigation event.
private void navigationProvider1_Navigate(object sender, DevExpress.CodeRush.Library.NavigationEventArgs ea)
{
SubMenuItem selectedMenu = ea.SelectedSubMenuItem;
if (selectedMenu == null)
return;
Class implementor = _implementors.Where(c => c.FullName == selectedMenu.Name).FirstOrDefault();
if (implementor != null)
{
Navigator navigator = new Navigator(implementor, ea.Element);
navigator.Navigate();
}
}
In the code above we request the implementing class from our implementor finder and if one is found we instantiate a new Navigator and navigate. Here’s the navigation code.
public class Navigator
{
/// <summary>
/// The source code element that the navigation was initiated on.
/// </summary>
private LanguageElement _elementActivated;
/// <summary>
/// The class that contains the implementation of the invocation of _elementActivated.
/// </summary>
private Class _targetClass;
public Navigator(Class targetClass, LanguageElement element)
{
_elementActivated = element;
_targetClass = targetClass;
}
public void Navigate()
{
if (_elementActivated == null || _targetClass == null)
return;
Method activatedMethod = _elementActivated.GetDeclaration() as Method;
if (activatedMethod == null)
return;
Method matchingMethodInClass = FindMatchingMethodInClass(activatedMethod);
if (matchingMethodInClass == null)
return;
CodeRush.File.Activate(matchingMethodInClass.FileNode.FilePath);
CodeRush.Documents.ActiveTextView.Selection.Set(matchingMethodInClass.NameRange);
}
private Method FindMatchingMethodInClass(Method activatedMethod)
{
ISourceTreeResolver resolver = new SourceTreeResolver();
Method matchingMethod = null;
foreach (IElement node in _targetClass.Nodes)
{
if (node is Method)
{
if (node.Name != activatedMethod.Name)
continue;
if (SignatureHelper.SignaturesMatch(resolver, activatedMethod, node as Method))
{
matchingMethod = node as Method;
}
}
}
return matchingMethod;
}
}
The _elementActivated field is the method call. See Drive() in the screenshot above. I’m not going to walk through the code explaining every detail. The reason for this is that I think the code is not hard to read. The main difficulty in developing CodeRush plugins is to write code that you don’t have any samples for. So hopefully by putting this plugin I’ve added another reference point for anyone who is interested in taking advantage of the extremely powerful plugin model of CodeRush.
The code is available on Google code here http://dxcorecommunityplugins.googlecode.com/svn/trunk/CR_NavigationContrib - dxcorecommunityplugins. Check out the source using a Subversion client. For more instructions on downloading the code you can go to the home page of the community plugins.
If you prefer a zip file with code and binaries, just send me an email through the blog.
Binaries can be downloaded from here. (Linked against CodeRush 3.2.2)