using System; using System.Collections.Generic; using Unity.Collections; using Unity.Profiling; using UnityEngine.InputSystem; using UnityEngine.InputSystem.LowLevel; using UnityEngine.InputSystem.Users; using UnityEngine.Profiling; using UnityEngine.InputSystem.EnhancedTouch; #if UNITY_EDITOR using UnityEditor; using UnityEngine.InputSystem.Editor; #endif namespace UnityEngine.InputSystem { /// /// Provides functions for saving and restore the InputSystem state across tests and domain reloads. /// internal class InputTestStateManager { static readonly ProfilerMarker k_InputResetMarker = new ProfilerMarker("InputSystem.Reset"); #if UNITY_EDITOR public InputSystemState GetSavedState() { return m_SavedStateStack.Peek(); } #endif /// /// Push the current state of the input system onto a stack and /// reset the system to its default state. /// /// /// The save stack is not able to survive domain reloads. It is intended solely /// for use in tests. /// public void SaveAndReset(bool enableRemoting, IInputRuntime runtime) { ////FIXME: does not preserve global state in InputActionState ////TODO: preserve InputUser state ////TODO: preserve EnhancedTouchSupport state m_SavedStateStack.Push(new InputSystemState { manager = InputSystem.manager, remote = InputSystem.remoting, remoteConnection = InputSystem.remoteConnection, managerState = InputSystem.manager.SaveState(), remotingState = InputSystem.remoting?.SaveState() ?? new InputRemoting.SerializedState(), #if UNITY_EDITOR userSettings = InputEditorUserSettings.s_Settings, systemObject = JsonUtility.ToJson(InputSystemEditorInitializer.domainStateManager), #endif inputActionState = InputActionState.SaveAndResetState(), touchState = EnhancedTouch.Touch.SaveAndResetState(), inputUserState = InputUser.SaveAndResetState() }); Reset(enableRemoting, runtime ?? InputRuntime.s_Instance); // Keep current runtime. } /// /// Return the input system to its default state. /// public void Reset(bool enableRemoting, IInputRuntime runtime) { k_InputResetMarker.Begin(); InputSystem.TestHook_DisableActions(); // Some devices keep globals. Get rid of them by pretending the devices // are removed. if (InputSystem.manager != null) { foreach (var device in InputSystem.manager.devices) device.NotifyRemoved(); InputSystem.manager.UninstallGlobals(); } #if UNITY_EDITOR // Perform special initialization for running Editor tests InputSystemTestHooks.TestHook_InitializeForPlayModeTests(enableRemoting, runtime); #else // For Player tests we can use the normal initialization InputSystem.InitializeInPlayer(runtime, false); #endif // UNITY_EDITOR Mouse.s_PlatformMouseDevice = null; InputEventListener.s_ObserverState = default; InputUser.ResetGlobals(); EnhancedTouchSupport.Reset(); InputSystem.TestHook_EnableActions(); k_InputResetMarker.End(); } ////FIXME: this method doesn't restore things like InputDeviceDebuggerWindow.onToolbarGUI /// /// Restore the state of the system from the last state pushed with . /// public void Restore() { Debug.Assert(m_SavedStateStack.Count > 0); // Load back previous state. var state = m_SavedStateStack.Pop(); state.inputUserState.StaticDisposeCurrentState(); state.touchState.StaticDisposeCurrentState(); state.inputActionState.StaticDisposeCurrentState(); InputSystemTestHooks.TestHook_DestroyAndReset(); state.inputUserState.RestoreSavedState(); state.touchState.RestoreSavedState(); state.inputActionState.RestoreSavedState(); InputSystemTestHooks.TestHook_RestoreFromSavedState(state.manager, state.remote, state.remoteConnection); InputUpdate.Restore(state.managerState.updateState); InputSystem.manager.InstallRuntime(InputSystem.manager.runtime); InputSystem.manager.InstallGlobals(); // IMPORTANT // If InputManager was using the "temporary" settings object, then it'll have been deleted during Reset() // and the saved Manager settings state will also be null, since it's a ScriptableObject. // In this case we manually create and set new temp settings object. if (InputSystem.manager.settings == null) { var tmpSettings = ScriptableObject.CreateInstance(); tmpSettings.hideFlags = HideFlags.HideAndDontSave; InputSystem.manager.settings = tmpSettings; } else InputSystem.manager.ApplySettings(); #if UNITY_EDITOR InputEditorUserSettings.s_Settings = state.userSettings; JsonUtility.FromJsonOverwrite(state.systemObject, InputSystemEditorInitializer.domainStateManager); #endif // Get devices that keep global lists (like Gamepad) to re-initialize them // by pretending the devices have been added. foreach (var device in InputSystem.devices) { device.NotifyAdded(); device.MakeCurrent(); } } private Stack m_SavedStateStack = new Stack(); } }