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();
}
}