OnButtonClicked is triggered twice on input clicks. Once from the InputClickedEvent and once from InputDown.
This happens spread over some frames and thus causes unintended side effects with dialogs and button actions that spawn gameObjects infront of the user. For example the first InpudClicked event will open a Dialog and the second will imediately dismiss it.
OnInputClicked is only fired once
OnInputClicked is fired twice
OnButtonClicked2017.3.1f1
dev branch @ d46126f8bfb0d27355d40e37afe3ad4dee920601
Edit: Added commit hash
Similar with the HolographicButton prefab in dev working branch. Unity 2017.2.1p4
https://forums.hololens.com/discussion/6999/ui-button-on-click-event-firing-twice#latest
I'm currently solving this by simply debouncing the invocation of OnButtonClicked a few hundered milliseconds, but haven't had the time to test if this has any unintended side effects.
eventData.Use();
Button.OnButtonClicked recieves a GameObject as payload, no eventData. the trace i attached also shows that the calls originate from two different event sources (InputDown and InputClicked).
You'll have to show me how you've got it setup in the inspector and in code.
Unfortunately i just left my windows machine at work, but i will try to flesh out my description a bit.
This seems to be not reproducible in the Unity Editor, it only fails on the HoloLens itself.
using UnityEngine;
using MixedRealityToolkit.UX.Buttons;
class Test : MonoBehaviour {
int frame = 0;
private void Start() {
Button button = this.GetComponent<Button>();
button.OnButtonClicked += (target) => {
Debug.Log(frame);
Debug.Log(System.Environment.StackTrace);
}
}
private void Update() {
frame++;
}
}
Run.
The Issue seems to be in the handling of input events in Button.cs itself. I'll try to outline it here.
Input events were triggered for me in the following order: InputDown, InputUp, InputClicked
public void OnInputDown(InputEventData eventData)
{
if (enabled)
{
if(ButtonPressFilter == InteractionSourcePressInfo.None || ButtonPressFilter == eventData.PressType)
{
DoButtonPressed(); // This calls button pressed on
// Set state to Pressed
ButtonStateEnum newState = ButtonStateEnum.Pressed;
this.OnStateChange(newState);
}
}
}
public void OnInputClicked(InputClickedEventData eventData)
{
if (enabled)
{
if (ButtonPressFilter == InteractionSourcePressInfo.None || ButtonPressFilter == eventData.PressType)
{
DoButtonPressed(true);
}
}
}
// As you can see both events result in DuButtonPressed() being called.
// This then triggers OnButtonClicked
protected void DoButtonPressed(bool bRelease = false)
{
ButtonStateEnum newState = ButtonStateEnum.Pressed;
this.OnStateChange(newState);
if (OnButtonPressed != null)
{
OnButtonPressed(gameObject);
}
if(OnButtonClicked != null)
{
OnButtonClicked(gameObject);
}
if (bRelease)
{
StartCoroutine(DelayedRelease(0.2f));
}
}
here's a basic project where i am trying to use additional button in AppBar
http://bradensmith.com/vrar/_testHoloButtons.7z
Click on button 'test' and it prints debug line twice
Not a fan of just downloading binaries. Could you make a public repo here on Github?
public void OnInputDown(InputEventData eventData)
{
if (enabled)
{
if(ButtonPressFilter == InteractionSourcePressInfo.None || ButtonPressFilter == eventData.PressType)
{
DoButtonPressed(); // This calls button pressed on
// Set state to Pressed
ButtonStateEnum newState = ButtonStateEnum.Pressed;
this.OnStateChange(newState);
eventData.Use(); // <-- Call this to prevent input from falling to the next handler.
}
}
}
public void OnInputClicked(InputClickedEventData eventData)
{
if (enabled)
{
if (ButtonPressFilter == InteractionSourcePressInfo.None || ButtonPressFilter == eventData.PressType)
{
DoButtonPressed(true);
eventData.Use(); // <-- Call this to prevent input from falling to the next handler.
}
}
}
I created a test scene for you in here:
https://github.com/thiemok/MixedRealityToolkit-Unity/tree/feature/button_test
You can find it in Assets/buttonTest.unity
I also went ahead and and added eventData.Use() to Button.cs, to show that the problems is not created by rehandeled events.
https://github.com/thiemok/MixedRealityToolkit-Unity/commit/ff2c4e395be3ebffc27b72cc8537a99e61a8433b
Disclaimer: i could not base the test of the current dev branch, because of some exception, so i used d46126f8bfb0d27355d40e37afe3ad4dee920601
I have the same or a similar problem it seems. Added eventData.Use() ... still both OnInputDown and OnInputClicked are called.
Seems in my case at least one event is from GestureRecognizer_Tapped, the other the other
InteractionManager_InteractionSourcePressed.
both coming from InteractionInputSource
In my case I temporarily set GestureRecognizer to manual start in my scene until I find/decide on a better way to handle it.
In the editor/player the call stack is:
1)
> Void MixedRealityToolkit.UX.Buttons.Button:OnInputDown (InputEventData)+0x34 at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\UX\Scripts\Buttons\Button.cs:126 C#
Void MixedRealityToolkit.InputModule.InputManager:<OnSourceDownEventHandler>m__6 (IInputHandler, BaseEventData)+0xa at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\InputModule\Scripts\InputManager.cs:449 C#
Boolean UnityEngine.EventSystems.ExecuteEvents:Execute (GameObject, BaseEventData, EventFunction`1)+0x73 at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\ExecuteEvents.cs:261 C#
GameObject UnityEngine.EventSystems.ExecuteEvents:ExecuteHierarchy (GameObject, BaseEventData, EventFunction`1)+0x28 at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\ExecuteEvents.cs:286 C#
Void MixedRealityToolkit.InputModule.InputManager:HandleEvent (BaseEventData, EventFunction`1)+0x147 at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\InputModule\Scripts\InputManager.cs:295 C#
Void MixedRealityToolkit.InputModule.InputManager:RaiseSourceDown (IInputSource, UInt32, InteractionSourcePressInfo, Object[])+0x1d at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\InputModule\Scripts\InputManager.cs:458 C#
Void MixedRealityToolkit.InputModule.InputSources.CustomInputSource:SendControllerStateEvents (Single)+0x31 at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\InputModule\Scripts\InputSources\CustomInputSource.cs:408 C#
Void MixedRealityToolkit.InputModule.InputSources.CustomInputSource:UpdateControllerState (DebugInteractionSourceState)+0x1a6 at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\InputModule\Scripts\InputSources\CustomInputSource.cs:395 C#
Void MixedRealityToolkit.InputModule.InputSources.CustomInputSource:UpdateControllerData ()+0x6f at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\InputModule\Scripts\InputSources\CustomInputSource.cs:338 C#
Void MixedRealityToolkit.InputModule.InputSources.CustomInputSource:Update ()+0x12 at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\InputModule\Scripts\InputSources\CustomInputSource.cs:275 C#
2)
> Void MixedRealityToolkit.UX.Buttons.Button:OnInputClicked (InputClickedEventData)+0x34 at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\UX\Scripts\Buttons\Button.cs:163 C#
Void MixedRealityToolkit.InputModule.InputManager:<OnInputClickedEventHandler>m__4 (IInputClickHandler, BaseEventData)+0xa at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\InputModule\Scripts\InputManager.cs:401 C#
Boolean UnityEngine.EventSystems.ExecuteEvents:Execute (GameObject, BaseEventData, EventFunction`1)+0x73 at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\ExecuteEvents.cs:261 C#
GameObject UnityEngine.EventSystems.ExecuteEvents:ExecuteHierarchy (GameObject, BaseEventData, EventFunction`1)+0x28 at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\ExecuteEvents.cs:286 C#
Void MixedRealityToolkit.InputModule.InputManager:HandleEvent (BaseEventData, EventFunction`1)+0x147 at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\InputModule\Scripts\InputManager.cs:295 C#
Void MixedRealityToolkit.InputModule.InputManager:RaiseInputClicked (IInputSource, UInt32, InteractionSourcePressInfo, Int32, Object[])+0x1f at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\InputModule\Scripts\InputManager.cs:410 C#
Void MixedRealityToolkit.InputModule.InputSources.CustomInputSource:SendControllerStateEvents (Single)+0xc2 at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\InputModule\Scripts\InputSources\CustomInputSource.cs:428 C#
Void MixedRealityToolkit.InputModule.InputSources.CustomInputSource:UpdateControllerState (DebugInteractionSourceState)+0x1a6 at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\InputModule\Scripts\InputSources\CustomInputSource.cs:395 C#
Void MixedRealityToolkit.InputModule.InputSources.CustomInputSource:UpdateControllerData ()+0x6f at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\InputModule\Scripts\InputSources\CustomInputSource.cs:338 C#
Void MixedRealityToolkit.InputModule.InputSources.CustomInputSource:Update ()+0x12 at D:\Dev\Unity3D\Customer\CustomerProcess\Assets\MixedRealityToolkit\InputModule\Scripts\InputSources\CustomInputSource.cs:275 C#
While debugging on HoloLens, the callstack is
1)
> Assembly-CSharp.dll!MixedRealityToolkit.UX.Buttons.Button.OnInputDown(MixedRealityToolkit.InputModule.EventData.InputEventData eventData) Line 126 Unknown
Assembly-CSharp.dll!MixedRealityToolkit.InputModule.InputManager..cctor.AnonymousMethod__114_6(MixedRealityToolkit.InputModule.InputHandlers.IInputHandler handler, UnityEngine.EventSystems.BaseEventData eventData) Line 449 Unknown
[External Code]
Assembly-CSharp.dll!MixedRealityToolkit.InputModule.InputManager.HandleEvent<MixedRealityToolkit.InputModule.InputHandlers.IInputHandler>(UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents.EventFunction<MixedRealityToolkit.InputModule.InputHandlers.IInputHandler> eventHandler) Line 295 Unknown
Assembly-CSharp.dll!MixedRealityToolkit.InputModule.InputManager.RaiseSourceDown(MixedRealityToolkit.InputModule.InputSources.IInputSource source, uint sourceId, MixedRealityToolkit.InputModule.InputSources.InteractionSourcePressInfo pressType, object[] tags) Line 458 Unknown
**Assembly-CSharp.dll!MixedRealityToolkit.InputModule.InputSources.InteractionInputSource.InteractionManager_InteractionSourcePressed(UnityEngine.XR.WSA.Input.InteractionSourcePressedEventArgs args)** Line 930 Unknown
[External Code]
2)
> Assembly-CSharp.dll!MixedRealityToolkit.UX.Buttons.Button.OnInputClicked(MixedRealityToolkit.InputModule.EventData.InputClickedEventData eventData) Line 163 Unknown
Assembly-CSharp.dll!MixedRealityToolkit.InputModule.InputManager..cctor.AnonymousMethod__114_4(MixedRealityToolkit.InputModule.InputHandlers.IInputClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) Line 401 Unknown
[External Code]
Assembly-CSharp.dll!MixedRealityToolkit.InputModule.InputManager.HandleEvent<MixedRealityToolkit.InputModule.InputHandlers.IInputClickHandler>(UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents.EventFunction<MixedRealityToolkit.InputModule.InputHandlers.IInputClickHandler> eventHandler) Line 295 Unknown
Assembly-CSharp.dll!MixedRealityToolkit.InputModule.InputManager.RaiseInputClicked(MixedRealityToolkit.InputModule.InputSources.IInputSource source, uint sourceId, MixedRealityToolkit.InputModule.InputSources.InteractionSourcePressInfo pressType, int tapCount, object[] tags) Line 410 Unknown
**Assembly-CSharp.dll!MixedRealityToolkit.InputModule.InputSources.InteractionInputSource.GestureRecognizer_Tapped(UnityEngine.XR.WSA.Input.TappedEventArgs args) Line 957** Unknown
[External Code]
DoButtonPressed is the problem here. It contains both, OnButtonPressed and OnButtonClicked, while it's been called from both, OnInputDown and OnInputClicked.
Maybe this problem is related with #2040
I have a rework in progress, so I'll be sure to double check #2040 as well.
The PopupMenu issue ended up needing a different fix, since it uses a different button class than this one. I've noted that, so we can clean up the various overlapping UX components.
Just opened #2367 to remove the duplicate events firing.