using System; using System.Threading; using UnityEngine; using UnityEngine.Events; namespace SkyHook { /// /// Manages SkyHook activity. /// A "ed" instance will be created automatically upon use. /// public class SkyHookManager : MonoBehaviour { private static SkyHookManager _instance; private ManualResetEvent _mre; /// /// Whether this process is focused. /// public static bool IsFocused; /// /// Whether or the event will be received only if the game window is focused. /// Note that only down key events will be ignored. /// // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once FieldCanBeMadeReadOnly.Global public bool requireFocus = true; /// /// Whether the hook is active now. /// public bool isHookActive; /// /// Your callback for each key updated events. /// Use to register your callback. /// // ReSharper disable once MemberCanBePrivate.Global public static readonly UnityEvent KeyUpdated = new(); private SkyHookNative.Callback _callback; /// /// The instance of . /// A new instance will be created if it does not exist. ///
/// This will return null if is false. ///
// ReSharper disable once MemberCanBePrivate.Global public static SkyHookManager Instance { get { if (!Application.isPlaying) return null; if (_instance) return _instance; var obj = new GameObject("SkyHook Manager"); _instance = obj.AddComponent(); DontDestroyOnLoad(_instance); return _instance; } } private void HookCallback(SkyHookEvent ev) { if (requireFocus && !IsFocused && ev.Type == EventType.KeyPressed) { return; } KeyUpdated.Invoke(ev); } private void _StartHook() { var started = false; Exception exception = null; _mre = new(false); new Thread(() => { try { _callback = HookCallback; var result = SkyHookNative.StartHook(_callback); if (result != null) { exception = new SkyHookException(result); } isHookActive = true; started = true; _mre.WaitOne(); Debug.Log("Thread ended"); } catch (Exception e) { exception = e; Debug.LogError(e); throw; } }).Start(); while (!started && exception == null) { } if (exception != null) { throw exception; } } private void _StopHook() { var result = SkyHookNative.StopHook(); if (result != null) { throw new SkyHookException(result); } if (_mre != null) { _mre.Set(); } isHookActive = false; } /// /// Starts the native hook. ///
/// This will only work if is true. ///
public static void StartHook() { if (!Application.isPlaying) { Debug.LogWarning("You may not call StartHook() if the application is not playing."); return; } Instance._StartHook(); } /// /// Stops the native hook. ///
/// This will only work if is true. ///
public static void StopHook() { if (!Application.isPlaying) { Debug.LogWarning("You may not call StopHook() if the application is not playing."); return; } Instance._StopHook(); } private void OnDestroy() { if (isHookActive) { _StopHook(); } } private void Update() { if (requireFocus) { IsFocused = Application.isFocused; } } } }