1+ using System ;
2+ using System . Collections ;
3+ using NUnit . Framework ;
4+ using UnityEngine ;
5+ using UnityEngine . EventSystems ;
6+ using UnityEngine . InputSystem ;
7+ using UnityEngine . InputSystem . UI ;
8+ using UnityEngine . TestTools ;
9+ using UnityEngine . UI ;
10+
11+ [ Description ( "Check https://jira.unity3d.com/browse/ISXB-1561 for more details." ) ]
12+ public class MockKeyboardWithUITests : InputTestFixture
13+ {
14+ private Keyboard m_Keyboard ;
15+ private GameObject m_CanvasGo ;
16+ private GameObject m_EventSystemGo ;
17+ private GameObject m_ButtonGo ;
18+ private InputActionAsset m_InputActionAsset ;
19+
20+ public class CancellationHandler : MonoBehaviour , ICancelHandler
21+ {
22+ public Action trigger ;
23+ public void OnCancel ( BaseEventData eventData ) => trigger ( ) ;
24+ }
25+
26+ public override void Setup ( )
27+ {
28+ base . Setup ( ) ;
29+
30+ // Add a mock keyboard
31+ m_Keyboard = InputSystem . AddDevice < Keyboard > ( ) ;
32+
33+ // first creating the UI stuff
34+ m_CanvasGo = new GameObject ( "canvas" ) ;
35+ m_ButtonGo = new GameObject ( "button" , typeof ( Button ) , typeof ( CancellationHandler ) ) ;
36+ m_ButtonGo . transform . SetParent ( m_CanvasGo . transform , false ) ;
37+
38+ // Now creating the Input layer
39+ m_EventSystemGo = new GameObject ( "eventSystem" , typeof ( EventSystem ) ) ;
40+ EventSystem . current . SetSelectedGameObject ( m_ButtonGo ) ;
41+
42+ var inputModule = m_EventSystemGo . AddComponent < InputSystemUIInputModule > ( ) ;
43+
44+ m_InputActionAsset = ScriptableObject . CreateInstance < InputActionAsset > ( ) ;
45+ var actionMap = new InputActionMap ( "UI" ) ;
46+ var submitAction = actionMap . AddAction ( "Submit" , binding : "Keyboard/enter" , type : InputActionType . Button ) ;
47+ var cancelAction = actionMap . AddAction ( "Cancel" , binding : "Keyboard/escape" , type : InputActionType . Button ) ;
48+ m_InputActionAsset . AddActionMap ( actionMap ) ;
49+ actionMap . Enable ( ) ;
50+ inputModule . actionsAsset = m_InputActionAsset ;
51+ inputModule . submit = InputActionReference . Create ( submitAction ) ;
52+ inputModule . cancel = InputActionReference . Create ( cancelAction ) ;
53+ }
54+
55+ public override void TearDown ( )
56+ {
57+ GameObject . Destroy ( m_EventSystemGo ) ;
58+ GameObject . Destroy ( m_CanvasGo ) ;
59+
60+ InputSystem . RemoveDevice ( m_Keyboard ) ;
61+
62+ base . TearDown ( ) ;
63+ }
64+
65+ private static bool [ ] FrameWaitingOptions = { true , false } ;
66+
67+ [ UnityTest ]
68+ public IEnumerator MockKeyboard_PressEnter_TriggersButtonOnClick ( [ ValueSource ( nameof ( FrameWaitingOptions ) ) ] bool waitFrame )
69+ {
70+ bool invokedListener = false ;
71+
72+ m_ButtonGo . GetComponent < Button > ( ) . onClick . AddListener ( ( ) => invokedListener = true ) ;
73+
74+ Press ( m_Keyboard . enterKey ) ;
75+
76+ // We'd like to test both options to be safe with rapid actions that happened within a single frame
77+ if ( waitFrame )
78+ yield return null ;
79+
80+ Release ( m_Keyboard . enterKey ) ;
81+
82+ yield return null ;
83+
84+ Assert . IsTrue ( invokedListener , "The button should have been clicked here." ) ;
85+ }
86+
87+ [ UnityTest ]
88+ public IEnumerator MockKeyboard_PressEscape_TriggersCancelHandler ( [ ValueSource ( nameof ( FrameWaitingOptions ) ) ] bool waitFrame )
89+ {
90+ bool invokedListener = false ;
91+ m_ButtonGo . GetComponent < CancellationHandler > ( ) . trigger = ( ) => invokedListener = true ;
92+
93+ Press ( m_Keyboard . escapeKey ) ;
94+
95+ // We'd like to test both options to be safe with rapid actions that happened within a single frame
96+ if ( waitFrame )
97+ yield return null ;
98+
99+ Release ( m_Keyboard . escapeKey ) ;
100+
101+ yield return null ;
102+
103+ Assert . IsTrue ( invokedListener , "The cancel event should have been raised here." ) ;
104+ }
105+ }
0 commit comments