I am developing a HoloLens project that has the following feature: User can use the voice command to instruct a game Object to do several things. For example, if the user says "Give me a candy", the game object will generate a candy and the total number of candies will increment by one.
I want to set the gameObject to be a global listener in the inputManager so that it can listen to the user's command without requiring user to look at it. But in the real implementation, it comes a problem. When user is indeed looking at it and saying "Give me a candy", the game object will actually generate two candies: one is handled as global listener, one is handled as the focused gameobject.
I want to prevent this scenario happening, which means when game object should be able to filter out either the global listener command or the focused gameobject command. One way I can think of right now is to unregister the game object away from the global listener queue when it becomes the focused game object and register it back when it becomes not focused game object. But I am suspicious about the performance. Actively register/unregister a gameobject (sounds) a lot of overhead. But I am not familiar with the architecture behind it, so can anyone help me better evaluate this solution?
Or is there any other ways that are more efficient to handle this double handling problem?
Thanks in advance
DK
I just tried to implement the solution I mentioned above: Inherit the IFocusable class, implement
OnFocusEnter(){
RemoveGlobalListener();
}
OnFocusExit(){
AddGlobalListener();
}
The result is that, the game object cannot recognize my voice when it is the FocusedObject, but can recognize my voice when it is not the FocusedObject. This result means the ISpeechHandler can only send keyword event to global listeners. If you are not global listener, you cannot receive the event even though you are FocusedObject.
Reverting back to the initial version, (the one without IFocusable), things happen: the double handling issue disappears! But I don't think the problem is solved, let me explain:
Right now, the set up of my project is: it has two game objects, both of them are registered as global listeners. A is the candy generator game object we were talking about. B is another game object which does completely different things than A.
I observe that even though A only catch up the voice command once at a time (which is what we want!), but B will catch up the voice command twice even though I deliberately put my gaze away from B.
This result shows that: I have one global listener handle the keyword only once at a time but another global listener handle the keyword twich at a time. So there is a discrepancy in global listeners.
This makes me start to suspect the implementation inside the InputManager. I am happy that A only handle the event once now, but I just feel like getting lucky. I wonder if someone can tell me whether my observations from the previous experiments are right or wrong.
@DKandrew do you have an example scene you can share with us?
Just make a fork of this repo and branch it with an added example scene.
Oops. I made a mistake. I set the B object to be OverrideFocusedObject in the InputManager. This can explain my two observations.
1, When A is unregistered from the Global Listener (GL), the FocusedObject will become B (since it is overridden) Therefore, the speech event cannot send to A.
2, Because B is always the FocusedObject, it will handle the input event twice. One as GL, and the other as FocusedObject. Since A is the GL and could never be the FocusedObject, it will receive the event only once.
I run an isolated test that confirms InputManager will send the input event to two objects: GLs and Focused Object. Then I implement my initial idea about avoiding doubling event handling.
OnFocusEnter(){
RemoveGlobalListener();
}
OnFocusExit(){
AddGlobalListener();
}
Now it works! The result is very good. I also run a memory test on my entire system and don't see any noticeable overhead which concludes that it could be a practical solution to my original question.
[Leaving this post open for several days before closing it just in case if there are any further issues]
I came across a similar problem but with the tap-gesture instead of a voice command. I used the following mechanic:
void OnInputClicked(InputClickedEventData eventData)
{
if(eventData.Used) return;
eventData.Use();
// do stuff
}
@HoloFan That is also a very interesting solution. Thank you!
This should be fixed now with the latest input updates.