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