@@ -3922,22 +3922,13 @@ public void UI_CanDriveVirtualMouseCursorFromGamepad()
39223922 // can have a reference to UITK that doesn't break things in previous versions of Unity.
39233923 [ UnityTest ]
39243924 [ Category ( "UI" ) ]
3925- [ TestCase ( UIPointerBehavior . AllPointersAsIs , ExpectedResult = 1 ) ]
3926- [ TestCase ( UIPointerBehavior . SingleMouseOrPenButMultiTouchAndTrack , ExpectedResult = 1 ) ]
3927- [ TestCase ( UIPointerBehavior . SingleUnifiedPointer , ExpectedResult = 1 ) ]
3928- #if UNITY_ANDROID || UNITY_IOS || UNITY_TVOS
3929- [ Ignore ( "Currently fails on the farm but succeeds locally on Note 10+; needs looking into." ) ]
3930- #endif
3931- #if UNITY_STANDALONE_LINUX || UNITY_EDITOR_LINUX
3932- [ Ignore ( "Disabled to make test suite pass on Linux" ) ]
3925+ #if UNITY_2022_3 && ( UNITY_ANDROID || UNITY_IOS )
3926+ [ Ignore ( "Issue with mouse support on Android and iOS for 2022.3." ) ]
39333927#endif
39343928 [ PrebuildSetup ( typeof ( UI_CanOperateUIToolkitInterface_UsingInputSystemUIInputModule_Setup ) ) ]
3935- public IEnumerator UI_CanOperateUIToolkitInterface_UsingInputSystemUIInputModule ( UIPointerBehavior pointerBehavior )
3929+ public IEnumerator UI_UIToolkitInputModule_MouseClick_CapturesAndClicksButton ( )
39363930 {
39373931 var mouse = InputSystem . AddDevice < Mouse > ( ) ;
3938- var gamepad = InputSystem . AddDevice < Gamepad > ( ) ;
3939- var touchscreen = InputSystem . AddDevice < Touchscreen > ( ) ;
3940-
39413932 var scene = SceneManager . LoadScene ( "UITKTestScene" , new LoadSceneParameters ( LoadSceneMode . Additive ) ) ;
39423933 yield return null ;
39433934 Assert . That ( scene . isLoaded , Is . True , "UITKTestScene did not load as expected" ) ;
@@ -3946,88 +3937,158 @@ public IEnumerator UI_CanOperateUIToolkitInterface_UsingInputSystemUIInputModule
39463937 {
39473938 var objects = scene . GetRootGameObjects ( ) ;
39483939 var uiModule = objects . First ( x => x . name == "EventSystem" ) . GetComponent < InputSystemUIInputModule > ( ) ;
3949- InputSystem . settings . backgroundBehavior = InputSettings . BackgroundBehavior . IgnoreFocus ;
39503940 var uiDocument = objects . First ( x => x . name == "UIDocument" ) . GetComponent < UIDocument > ( ) ;
3951- var uiRoot = uiDocument . rootVisualElement ;
3952- var uiButton = uiRoot . Query < UnityEngine . UIElements . Button > ( "Button" ) . First ( ) ;
3953- var scrollView = uiRoot . Query < ScrollView > ( "ScrollView" ) . First ( ) ;
3954-
3955- uiModule . pointerBehavior = pointerBehavior ;
3941+ var uiButton = uiDocument . rootVisualElement . Query < UnityEngine . UIElements . Button > ( "Button" ) . First ( ) ;
39563942
39573943 var clickReceived = false ;
39583944 uiButton . clicked += ( ) => clickReceived = true ;
3959- // NOTE: We do *NOT* do the following as the gamepad submit action will *not* trigger a ClickEvent.
3960- //uiButton.RegisterCallback<ClickEvent>(_ => clickReceived = true);
39613945
39623946 yield return null ;
39633947
39643948 var buttonCenter = new Vector2 ( uiButton . worldBound . center . x , Screen . height - uiButton . worldBound . center . y ) ;
3965- var buttonOutside = new Vector2 ( uiButton . worldBound . max . x + 10 , Screen . height - uiButton . worldBound . center . y ) ;
3966- var scrollViewCenter = new Vector2 ( scrollView . worldBound . center . x , Screen . height - scrollView . worldBound . center . y ) ;
3967-
39683949 Set ( mouse . position , buttonCenter , queueEventOnly : true ) ;
39693950 Press ( mouse . leftButton , queueEventOnly : true ) ;
3970-
3971- ////TODO: look at BaseInput and whether we need to override it in order for IME to go through our codepaths
3972- ////TODO: look into or document raycasting aspect (GraphicRaycaster) when using UITK (disable raycaster?)
3973- ////TODO: fix scroll wheel bindings on virtual cursor sample
3974-
39753951 yield return null ;
3976-
39773952 Assert . That ( uiButton . HasMouseCapture ( ) , Is . True , "Expected uiButton to have mouse capture" ) ;
39783953
39793954 Release ( mouse . leftButton , queueEventOnly : true ) ;
3980-
39813955 yield return null ;
3982-
39833956 Assert . That ( uiButton . HasMouseCapture ( ) , Is . False , "Expected uiButton to no longer have mouse capture" ) ;
3984- Assert . That ( clickReceived , Is . True ) ;
3957+ Assert . That ( clickReceived , Is . True , "Expected mouse click callback on UITK button" ) ;
3958+ }
3959+ finally
3960+ {
3961+ if ( mouse . added )
3962+ InputSystem . RemoveDevice ( mouse ) ;
3963+ SceneManager . UnloadSceneAsync ( scene ) ;
3964+ }
3965+
3966+ yield return null ;
3967+ }
3968+
3969+ [ UnityTest ]
3970+ [ Category ( "UI" ) ]
3971+ [ PrebuildSetup ( typeof ( UI_CanOperateUIToolkitInterface_UsingInputSystemUIInputModule_Setup ) ) ]
3972+ public IEnumerator UI_UIToolkitInputModule_MouseScroll_MovesScrollView ( )
3973+ {
3974+ var mouse = InputSystem . AddDevice < Mouse > ( ) ;
3975+ var scene = SceneManager . LoadScene ( "UITKTestScene" , new LoadSceneParameters ( LoadSceneMode . Additive ) ) ;
3976+ yield return null ;
3977+ Assert . That ( scene . isLoaded , Is . True , "UITKTestScene did not load as expected" ) ;
39853978
3986- // Put mouse in upper right corner and scroll down.
3979+ try
3980+ {
3981+ var objects = scene . GetRootGameObjects ( ) ;
3982+ var uiModule = objects . First ( x => x . name == "EventSystem" ) . GetComponent < InputSystemUIInputModule > ( ) ;
3983+ var uiDocument = objects . First ( x => x . name == "UIDocument" ) . GetComponent < UIDocument > ( ) ;
3984+ var scrollView = uiDocument . rootVisualElement . Query < ScrollView > ( "ScrollView" ) . First ( ) ;
3985+
3986+ yield return null ;
3987+
3988+ var scrollViewCenter = new Vector2 ( scrollView . worldBound . center . x , Screen . height - scrollView . worldBound . center . y ) ;
39873989 Assert . That ( scrollView . verticalScroller . value , Is . Zero , "Expected verticalScroller to be all the way up" ) ;
39883990 Set ( mouse . position , scrollViewCenter , queueEventOnly : true ) ;
39893991 yield return null ;
39903992 Set ( mouse . scroll , new Vector2 ( 0 , - 100 ) , queueEventOnly : true ) ;
39913993 yield return null ;
3992-
3993- ////FIXME: as of a time of writing, this line is broken on trunk due to the bug in UITK
3994- // The bug is https://fogbugz.unity3d.com/f/cases/1323488/
3995- // just adding a define as a safeguard measure to reenable it when trunk goes to next version cycle
39963994 Assert . That ( scrollView . verticalScroller . value , Is . GreaterThan ( 0 ) ) ;
3995+ }
3996+ finally
3997+ {
3998+ if ( mouse . added )
3999+ InputSystem . RemoveDevice ( mouse ) ;
4000+ SceneManager . UnloadSceneAsync ( scene ) ;
4001+ }
39974002
3998- // Try a button press with the gamepad.
3999- // NOTE: The current version of UITK does not focus the button automatically. Fix for that is in the pipe.
4000- // For now focus the button manually.
4003+ yield return null ;
4004+ }
4005+
4006+ [ UnityTest ]
4007+ [ Category ( "UI" ) ]
4008+ [ PrebuildSetup ( typeof ( UI_CanOperateUIToolkitInterface_UsingInputSystemUIInputModule_Setup ) ) ]
4009+ public IEnumerator UI_UIToolkitInputModule_GamepadSubmit_ClicksFocusedButton ( )
4010+ {
4011+ var gamepad = InputSystem . AddDevice < Gamepad > ( ) ;
4012+ var scene = SceneManager . LoadScene ( "UITKTestScene" , new LoadSceneParameters ( LoadSceneMode . Additive ) ) ;
4013+ yield return null ;
4014+ Assert . That ( scene . isLoaded , Is . True , "UITKTestScene did not load as expected" ) ;
4015+
4016+ try
4017+ {
4018+ var objects = scene . GetRootGameObjects ( ) ;
4019+ var uiModule = objects . First ( x => x . name == "EventSystem" ) . GetComponent < InputSystemUIInputModule > ( ) ;
4020+ var uiDocument = objects . First ( x => x . name == "UIDocument" ) . GetComponent < UIDocument > ( ) ;
4021+ var uiButton = uiDocument . rootVisualElement . Query < UnityEngine . UIElements . Button > ( "Button" ) . First ( ) ;
4022+
4023+ yield return null ;
4024+
4025+ var clickReceived = false ;
4026+ uiButton . clicked += ( ) => clickReceived = true ;
40014027 uiButton . Focus ( ) ;
4002- clickReceived = false ;
4028+
40034029 PressAndRelease ( gamepad . buttonSouth , queueEventOnly : true ) ;
40044030 yield return null ;
4031+ Assert . That ( clickReceived , Is . True , "Expected gamepad submit to click focused UITK button" ) ;
4032+ }
4033+ finally
4034+ {
4035+ if ( gamepad . added )
4036+ InputSystem . RemoveDevice ( gamepad ) ;
4037+ SceneManager . UnloadSceneAsync ( scene ) ;
4038+ }
40054039
4006- Assert . That ( clickReceived , Is . True , "Expected to have received click" ) ;
4040+ yield return null ;
4041+ }
40074042
4008- ////TODO: tracked device support (not yet supported by UITK)
4043+ [ UnityTest ]
4044+ [ Category ( "UI" ) ]
4045+ [ TestCase ( UIPointerBehavior . AllPointersAsIs , ExpectedResult = 1 ) ]
4046+ [ TestCase ( UIPointerBehavior . SingleMouseOrPenButMultiTouchAndTrack , ExpectedResult = 1 ) ]
4047+ [ TestCase ( UIPointerBehavior . SingleUnifiedPointer , ExpectedResult = 1 ) ]
4048+ #if UNITY_2022_3 && ( UNITY_ANDROID || UNITY_IOS )
4049+ [ Ignore ( "Fails on CI for 2022.3 on Android and iOS." ) ]
4050+ #endif
4051+ [ PrebuildSetup ( typeof ( UI_CanOperateUIToolkitInterface_UsingInputSystemUIInputModule_Setup ) ) ]
4052+ public IEnumerator UI_UIToolkitInputModule_MultiTouchPointerOwnership ( UIPointerBehavior pointerBehavior )
4053+ {
4054+ var touchscreen = InputSystem . AddDevice < Touchscreen > ( ) ;
4055+ var scene = SceneManager . LoadScene ( "UITKTestScene" , new LoadSceneParameters ( LoadSceneMode . Additive ) ) ;
4056+ yield return null ;
4057+ Assert . That ( scene . isLoaded , Is . True , "UITKTestScene did not load as expected" ) ;
40094058
4010- static bool IsActive ( VisualElement ve )
4011- {
4012- return ve . Query < VisualElement > ( ) . Active ( ) . ToList ( ) . Contains ( ve ) ;
4013- }
4059+ try
4060+ {
4061+ var objects = scene . GetRootGameObjects ( ) ;
4062+ var uiModule = objects . First ( x => x . name == "EventSystem" ) . GetComponent < InputSystemUIInputModule > ( ) ;
4063+ var uiDocument = objects . First ( x => x . name == "UIDocument" ) . GetComponent < UIDocument > ( ) ;
4064+ var uiButton = uiDocument . rootVisualElement . Query < UnityEngine . UIElements . Button > ( "Button" ) . First ( ) ;
40144065
4015- // Move the mouse away from the button to check that touch inputs are also able to activate it.
4016- Set ( mouse . position , buttonOutside , queueEventOnly : true ) ;
4066+ uiModule . pointerBehavior = pointerBehavior ;
40174067 yield return null ;
4018- InputSystem . RemoveDevice ( mouse ) ;
4068+
4069+ var buttonCenter = new Vector2 ( uiButton . worldBound . center . x , Screen . height - uiButton . worldBound . center . y ) ;
4070+ var buttonOutside = new Vector2 ( uiButton . worldBound . max . x + 10 , Screen . height - uiButton . worldBound . center . y ) ;
40194071
40204072 var uiButtonDownCount = 0 ;
40214073 var uiButtonUpCount = 0 ;
4022- uiButton . RegisterCallback < PointerDownEvent > ( e => uiButtonDownCount ++ , TrickleDown . TrickleDown ) ;
4023- uiButton . RegisterCallback < PointerUpEvent > ( e => uiButtonUpCount ++ , TrickleDown . TrickleDown ) ;
4074+ var uiButtonDownPointerIds = new List < int > ( ) ;
4075+ var uiButtonUpPointerIds = new List < int > ( ) ;
4076+ uiButton . RegisterCallback < PointerDownEvent > ( eventData =>
4077+ {
4078+ uiButtonDownCount ++ ;
4079+ uiButtonDownPointerIds . Add ( eventData . pointerId ) ;
4080+ } , TrickleDown . TrickleDown ) ;
4081+ uiButton . RegisterCallback < PointerUpEvent > ( eventData =>
4082+ {
4083+ uiButtonUpCount ++ ;
4084+ uiButtonUpPointerIds . Add ( eventData . pointerId ) ;
4085+ } , TrickleDown . TrickleDown ) ;
40244086
4025- // Case 1369081: Make sure button doesn't get "stuck" in an active state when multiple fingers are used.
40264087 BeginTouch ( 1 , buttonCenter , screen : touchscreen ) ;
40274088 yield return null ;
40284089 Assert . That ( uiButtonDownCount , Is . EqualTo ( 1 ) , "Expected uiButtonDownCount to be 1" ) ;
40294090 Assert . That ( uiButtonUpCount , Is . EqualTo ( 0 ) , "Expected uiButtonUpCount to be 0" ) ;
4030- Assert . That ( IsActive ( uiButton ) , Is . True , "Expected uiButton to be active " ) ;
4091+ Assert . That ( uiButtonDownPointerIds , Has . Count . EqualTo ( 1 ) , "Expected one PointerDown pointerId " ) ;
40314092
40324093 BeginTouch ( 2 , buttonOutside , screen : touchscreen ) ;
40334094 yield return null ;
@@ -4038,31 +4099,102 @@ static bool IsActive(VisualElement ve)
40384099 if ( pointerBehavior == UIPointerBehavior . SingleUnifiedPointer )
40394100 {
40404101 Assert . That ( uiButtonUpCount , Is . EqualTo ( 1 ) , "Expected uiButtonUpCount to be 1" ) ;
4041- Assert . That ( IsActive ( uiButton ) , Is . False , "Expected uiButton to no longer be active " ) ;
4102+ Assert . That ( uiButtonUpPointerIds , Has . Count . EqualTo ( 1 ) , "Expected one PointerUp pointerId " ) ;
40424103 }
40434104 else
40444105 {
40454106 Assert . That ( uiButtonUpCount , Is . EqualTo ( 0 ) , "Expected uiButtonUpCount to be 0" ) ;
4046- Assert . That ( IsActive ( uiButton ) , Is . True , "Expected uiButton to be active " ) ;
4107+ Assert . That ( uiButtonUpPointerIds , Is . Empty , "Expected no PointerUp pointerId from outside touch " ) ;
40474108 }
40484109
40494110 EndTouch ( 1 , buttonCenter , screen : touchscreen ) ;
40504111 yield return null ;
40514112 Assert . That ( uiButtonDownCount , Is . EqualTo ( 1 ) , "Expected uiButtonDownCount to be 1" ) ;
40524113 Assert . That ( uiButtonUpCount , Is . EqualTo ( 1 ) , "Expected uiButtonUpCount to be 1" ) ;
4053- Assert . That ( IsActive ( uiButton ) , Is . False , "Expected uiButton to no longer be active" ) ;
4114+ Assert . That ( uiButtonUpPointerIds , Has . Count . EqualTo ( 1 ) , "Expected one PointerUp pointerId after releasing touch #1" ) ;
4115+ Assert . That ( uiButtonUpPointerIds [ 0 ] , Is . EqualTo ( uiButtonDownPointerIds [ 0 ] ) ,
4116+ "Expected PointerUp ownership to match the pointer that pressed the button" ) ;
4117+ Assert . That ( IsActiveVisualElement ( uiButton ) , Is . False , "Expected uiButton to no longer be active" ) ;
4118+ }
4119+ finally
4120+ {
4121+ if ( touchscreen . added )
4122+ InputSystem . RemoveDevice ( touchscreen ) ;
4123+ SceneManager . UnloadSceneAsync ( scene ) ;
4124+ }
4125+
4126+ yield return null ;
4127+ }
40544128
4055- InputSystem . RemoveDevice ( touchscreen ) ;
4129+ [ UnityTest ]
4130+ [ Category ( "UI" ) ]
4131+ #if UNITY_2022_3 && ( UNITY_ANDROID || UNITY_IOS )
4132+ [ Ignore ( "Issue with mouse support on Android and iOS for 2022.3." ) ]
4133+ #endif
4134+ [ TestCase ( UIPointerBehavior . AllPointersAsIs , ExpectedResult = 1 ) ]
4135+ [ TestCase ( UIPointerBehavior . SingleMouseOrPenButMultiTouchAndTrack , ExpectedResult = 1 ) ]
4136+ [ TestCase ( UIPointerBehavior . SingleUnifiedPointer , ExpectedResult = 1 ) ]
4137+ [ PrebuildSetup ( typeof ( UI_CanOperateUIToolkitInterface_UsingInputSystemUIInputModule_Setup ) ) ]
4138+ public IEnumerator UI_UIToolkitInputModule_MultiTouchVisualActiveState_FollowsPointerBehavior ( UIPointerBehavior pointerBehavior )
4139+ {
4140+ var touchscreen = InputSystem . AddDevice < Touchscreen > ( ) ;
4141+ var scene = SceneManager . LoadScene ( "UITKTestScene" , new LoadSceneParameters ( LoadSceneMode . Additive ) ) ;
4142+ yield return null ;
4143+ Assert . That ( scene . isLoaded , Is . True , "UITKTestScene did not load as expected" ) ;
4144+
4145+ try
4146+ {
4147+ var objects = scene . GetRootGameObjects ( ) ;
4148+ var uiModule = objects . First ( x => x . name == "EventSystem" ) . GetComponent < InputSystemUIInputModule > ( ) ;
4149+ var uiDocument = objects . First ( x => x . name == "UIDocument" ) . GetComponent < UIDocument > ( ) ;
4150+ var uiRoot = uiDocument . rootVisualElement ;
4151+ var uiButton = uiRoot . Query < UnityEngine . UIElements . Button > ( "Button" ) . First ( ) ;
4152+
4153+ uiModule . pointerBehavior = pointerBehavior ;
4154+
4155+ yield return null ;
4156+
4157+ var buttonCenter = new Vector2 ( uiButton . worldBound . center . x , Screen . height - uiButton . worldBound . center . y ) ;
4158+ var buttonOutside = new Vector2 ( uiButton . worldBound . max . x + 10 , Screen . height - uiButton . worldBound . center . y ) ;
4159+
4160+ // Finger #1 presses and holds on the button.
4161+ BeginTouch ( 1 , buttonCenter , screen : touchscreen ) ;
4162+ yield return null ;
4163+ Assert . That ( IsActiveVisualElement ( uiButton ) , Is . True , "Expected uiButton to be active while touch #1 is still pressed." ) ;
4164+
4165+ // Finger #2 taps outside of the button while finger #1 is still held.
4166+ BeginTouch ( 2 , buttonOutside , screen : touchscreen ) ;
4167+ yield return null ;
4168+ EndTouch ( 2 , buttonOutside , screen : touchscreen ) ;
4169+ yield return null ;
4170+
4171+ // Desired contract:
4172+ // - SingleUnifiedPointer: touch #2 can replace current pointer and clear active state.
4173+ // - Non-unified behaviors: touch #1 is still pressed and should keep the button visually active.
4174+ if ( pointerBehavior == UIPointerBehavior . SingleUnifiedPointer )
4175+ Assert . That ( IsActiveVisualElement ( uiButton ) , Is . False , "Expected uiButton to no longer be active in SingleUnifiedPointer mode." ) ;
4176+ else
4177+ Assert . That ( IsActiveVisualElement ( uiButton ) , Is . True , "Expected uiButton to remain active while touch #1 is still pressed." ) ;
4178+
4179+ EndTouch ( 1 , buttonCenter , screen : touchscreen ) ;
4180+ yield return null ;
4181+ Assert . That ( IsActiveVisualElement ( uiButton ) , Is . False , "Expected uiButton to no longer be active after touch #1 is released." ) ;
40564182 }
40574183 finally
40584184 {
4185+ if ( touchscreen . added )
4186+ InputSystem . RemoveDevice ( touchscreen ) ;
40594187 SceneManager . UnloadSceneAsync ( scene ) ;
40604188 }
40614189
4062- // Wait for unload to complete.
40634190 yield return null ;
40644191 }
40654192
4193+ private static bool IsActiveVisualElement ( VisualElement visualElement )
4194+ {
4195+ return visualElement . Query < VisualElement > ( ) . Active ( ) . ToList ( ) . Contains ( visualElement ) ;
4196+ }
4197+
40664198 private class UI_CanOperateUIToolkitInterface_UsingInputSystemUIInputModule_Setup : IPrebuildSetup
40674199 {
40684200 public void Setup ( )
@@ -4509,7 +4641,7 @@ public IEnumerator UI_DisplayIndexMatchesDisplayMultiplePointers()
45094641 }
45104642
45114643#endif
4512- #endregion
4644+ #endregion
45134645
45144646 public class MyButton : UnityEngine . UI . Button
45154647 {
0 commit comments