diff --git a/Runtime/Scripts/UniWindowController.cs b/Runtime/Scripts/UniWindowController.cs index 51da8fa..09c4e6d 100644 --- a/Runtime/Scripts/UniWindowController.cs +++ b/Runtime/Scripts/UniWindowController.cs @@ -1,6 +1,6 @@ /* * UniWindowController.cs - * + * * Author: Kirurobo http://twitter.com/kirurobo * License: MIT */ @@ -17,6 +17,7 @@ using UnityEngine.Events; using System.Linq; #endif + #if ENABLE_INPUT_SYSTEM using UnityEngine.InputSystem; #endif @@ -24,22 +25,23 @@ using UnityEngine.InputSystem; namespace Kirurobo { /// @cond DOXYGEN_SHOW_INTERNAL_CLASSES - /// /// 使布尔属性可编辑 /// [System.AttributeUsage(System.AttributeTargets.Field, Inherited = true, AllowMultiple = false)] - public class EditablePropertyAttribute : UnityEngine.PropertyAttribute { } + public class EditablePropertyAttribute : UnityEngine.PropertyAttribute + { + } /// /// 将属性设置为只读 /// [System.AttributeUsage(System.AttributeTargets.Field, Inherited = true, AllowMultiple = false)] - public class ReadOnlyAttribute : UnityEngine.PropertyAttribute { } + public class ReadOnlyAttribute : UnityEngine.PropertyAttribute + { + } /// @endcond - - /// /// Windows/Mac 统一窗口控制器 /// @@ -113,6 +115,7 @@ namespace Kirurobo /// 获取当前 UniWindowController 实例 /// public static UniWindowController current => _current ? _current : FindOrCreateInstance(); + private static UniWindowController _current; /// @@ -128,6 +131,7 @@ namespace Kirurobo get { return _isClickThrough; } set { SetClickThrough(value); } } + private bool _isClickThrough = false; /// @@ -138,6 +142,7 @@ namespace Kirurobo get { return _isTransparent; } set { SetTransparent(value); } } + [SerializeField, EditableProperty, Tooltip("选中后启动时设置为透明")] private bool _isTransparent = false; @@ -149,6 +154,7 @@ namespace Kirurobo get { return _alphaValue; } set { SetAlphaValue(value); } } + [SerializeField, EditableProperty, Tooltip("窗口透明度"), Range(0f, 1f)] private float _alphaValue = 1.0f; @@ -160,6 +166,7 @@ namespace Kirurobo get { return ((_uniWinCore == null) ? _isTopmost : _isTopmost = _uniWinCore.IsTopmost); } set { SetTopmost(value); } } + [SerializeField, EditableProperty, Tooltip("选中后启动时置顶")] private bool _isTopmost = false; @@ -171,6 +178,7 @@ namespace Kirurobo get { return ((_uniWinCore == null) ? _isBottommost : _isBottommost = _uniWinCore.IsBottommost); } set { SetBottommost(value); } } + [SerializeField, EditableProperty, Tooltip("选中后启动时置底")] private bool _isBottommost = false; @@ -182,6 +190,7 @@ namespace Kirurobo get { return ((_uniWinCore == null) ? _isZoomed : _isZoomed = _uniWinCore.GetZoomed()); } set { SetZoomed(value); } } + [SerializeField, EditableProperty, Tooltip("选中后启动时最大化")] private bool _isZoomed = false; @@ -193,6 +202,7 @@ namespace Kirurobo get { return _shouldFitMonitor; } set { FitToMonitor(value, _monitorToFit); } } + [SerializeField, EditableProperty, Tooltip("选中后将窗口适配到显示器")] private bool _shouldFitMonitor = false; @@ -204,6 +214,7 @@ namespace Kirurobo get { return _monitorToFit; } set { FitToMonitor(_shouldFitMonitor, value); } } + private int _monitorToFit = 0; /// @@ -214,6 +225,7 @@ namespace Kirurobo get { return _allowDropFiles; } set { SetAllowDrop(value); } } + [SerializeField, EditableProperty, Tooltip("启用文件或文件夹拖放")] private bool _allowDropFiles = false; @@ -226,8 +238,7 @@ namespace Kirurobo /// /// 点击穿透自动判定的方法 /// - [Tooltip("选择方法")] - public HitTestType hitTestType = HitTestType.Opacity; + [Tooltip("选择方法")] public HitTestType hitTestType = HitTestType.Opacity; /// /// 点击穿透判定方法为不透明度时使用的阈值 @@ -244,8 +255,7 @@ namespace Kirurobo /// /// 启用后,窗口透明时会自动将相机背景改为单色黑色透明 /// - [Header("高级设置")] - [Tooltip("窗口透明时更改相机背景")] + [Header("高级设置")] [Tooltip("窗口透明时更改相机背景")] public bool autoSwitchCameraBackground = true; /// @@ -255,54 +265,53 @@ namespace Kirurobo /// 仅在启动时生效 /// 在 Mac 上,即使强制退出全屏,似乎仍会变成另一个画面,效果不大 /// - [Tooltip("启动时强制窗口模式")] - public bool forceWindowed = false; + [Tooltip("启动时强制窗口模式")] public bool forceWindowed = false; /// /// 相机实例 /// - [Tooltip("未设置时使用主相机")] - public Camera currentCamera; + [Tooltip("未设置时使用主相机")] public Camera currentCamera; /// /// 透明方式的指定 /// - [Header("仅限 Windows")] - [Tooltip("选择透明方式。*仅 Windows 可用")] + [Header("仅限 Windows")] [Tooltip("选择透明方式。*仅 Windows 可用")] public TransparentType transparentType = TransparentType.Alpha; /// /// 当透明类型为 ColorKey 时使用的键色 /// - [Tooltip("将在窗口下次变为透明时使用")] - public Color32 keyColor = new Color32(0x01, 0x00, 0x01, 0x00); + [Tooltip("将在窗口下次变为透明时使用")] public Color32 keyColor = new Color32(0x01, 0x00, 0x01, 0x00); /// /// 在 macOS 上,是否允许将窗口放置在菜单栏上方 /// public bool isFreePositioningEnabled { - get { return ((_uniWinCore == null) ? _isFreePositioningEnabled : _isFreePositioningEnabled = _uniWinCore.IsFreePositioningEnabled); } + get + { + return ((_uniWinCore == null) + ? _isFreePositioningEnabled + : _isFreePositioningEnabled = _uniWinCore.IsFreePositioningEnabled); + } set { SetFreePositioning(value); } } - [Header("仅限 macOS")] - [Tooltip("禁用 constrainFrameRect() *仅 macOS 可用")] - [SerializeField, EditableProperty] + + [Header("仅限 macOS")] [Tooltip("禁用 constrainFrameRect() *仅 macOS 可用")] [SerializeField, EditableProperty] private bool _isFreePositioningEnabled = false; /// /// 鼠标指针是否在不透明像素或物体上 /// - [Header("状态")] - [SerializeField, ReadOnly, Tooltip("鼠标指针是否在不透明像素上?(只读)")] + [Header("状态")] [SerializeField, ReadOnly, Tooltip("鼠标指针是否在不透明像素上?(只读)")] private bool onObject = true; - + /// /// 鼠标指针下方的像素颜色。(只读) /// [SerializeField, ReadOnly, Tooltip("鼠标指针下方的像素颜色。(只读)")] public Color pickedColor; - + /// /// 获取/设置窗口坐标 /// @@ -361,11 +370,12 @@ namespace Kirurobo /// Raycast 时的图层遮罩 /// private int hitTestLayerMask; - + /// /// 窗口样式改变时发生 /// public event OnStateChangedDelegate OnStateChanged; + public delegate void OnStateChangedDelegate(WindowStateEventType type); public delegate void FilesDelegate(string[] files); @@ -379,6 +389,7 @@ namespace Kirurobo /// 显示器设置或分辨率改变时发生 /// public event OnMonitorChangedDelegate OnMonitorChanged; + public delegate void OnMonitorChangedDelegate(); @@ -421,12 +432,11 @@ namespace Kirurobo { originalCameraClearFlags = currentCamera.clearFlags; originalCameraBackground = currentCamera.backgroundColor; - } - + // 鼠标事件信息 pointerEventData = new PointerEventData(EventSystem.current); - + // 使用 Ignore Raycast 之外的图层作为有效遮罩 hitTestLayerMask = ~LayerMask.GetMask("Ignore Raycast"); @@ -451,6 +461,7 @@ namespace Kirurobo { targetMonitorIndex = 0; } + if (monitors <= targetMonitorIndex) { targetMonitorIndex = monitors - 1; @@ -468,8 +479,12 @@ namespace Kirurobo /// private static UniWindowController FindOrCreateInstance() { +#if UNITY_2022_1_OR_NEWER var instance = GameObject.FindAnyObjectByType(); - +#else + var instance = GameObject.FindObjectOfType(); +#endif + // 目前禁止自动创建 // // 场景中未找到时创建新实例 // if (!instance) @@ -480,7 +495,7 @@ namespace Kirurobo return instance; } - + void Start() { //// New Input System 存在兼容性问题,用于验证输出 @@ -535,11 +550,12 @@ namespace Kirurobo if (_uniWinCore == null || !_uniWinCore.IsActive) { UpdateTargetWindow(); - } else + } + else { _uniWinCore.Update(); } - + // 处理事件 UpdateEvents(); @@ -574,7 +590,7 @@ namespace Kirurobo // //shouldFitMonitor = false; // 禁用适配 // } if (_shouldFitMonitor) StartCoroutine("ForceZoomed"); // 延迟强制最大化 - + OnStateChanged?.Invoke((WindowStateEventType)type); } } @@ -627,7 +643,7 @@ namespace Kirurobo { // 没有自动点击测试则结束 if (!isHitTestEnabled || hitTestType == HitTestType.None) return; - + // 鼠标光标隐藏状态视为在透明像素上 bool hit = (onObject); @@ -682,6 +698,7 @@ namespace Kirurobo onObject = true; } } + yield return null; } @@ -690,7 +707,6 @@ namespace Kirurobo /// private Vector2 GetClientCursorPosition() { - // New Input System 在没有焦点时无法获取鼠标坐标,因此自行计算 Vector2 mousePos = UniWinCore.GetCursorPosition(); Vector2 winPos = windowPosition; @@ -698,7 +714,7 @@ namespace Kirurobo Vector2 unityPos = new Vector2( (mousePos.x - winPos.x - clientRect.x) * Screen.width / clientRect.width, (mousePos.y - winPos.y - clientRect.y) * Screen.height / clientRect.height - ); + ); // // 调试用 // // 与 Unity 获取的值进行比较 @@ -714,14 +730,14 @@ namespace Kirurobo // 在编辑器中始终使用 Unity 功能获取鼠标坐标 // Game 窗口可能不是唯一窗口,或 Scale 不同,无法简单计算 -#if UNITY_EDITOR - #if ENABLE_LEGACY_INPUT_MANAGER +#if UNITY_EDITOR +#if ENABLE_LEGACY_INPUT_MANAGER return Input.mousePosition; - #elif UNITY_EDITOR && ENABLE_INPUT_SYSTEM +#elif UNITY_EDITOR && ENABLE_INPUT_SYSTEM return Mouse.current.position.ReadValue(); - #else +#else return unityPos; - #endif +#endif #else return unityPos; #endif @@ -762,8 +778,8 @@ namespace Kirurobo // 在屏幕外则视为透明 if ( mousePos.x < 0 || mousePos.x >= w - || mousePos.y < 0 || mousePos.y >= h - ) + || mousePos.y < 0 || mousePos.y >= h + ) { return false; } @@ -775,14 +791,14 @@ namespace Kirurobo if (transparentType == TransparentType.ColorKey) return true; // 根据指定坐标的绘制结果进行判断 - try // 在 WaitForEndOfFrame 时机执行的话,不需要 try 应该也没问题 + try // 在 WaitForEndOfFrame 时机执行的话,不需要 try 应该也没问题 { // 参考 http://tsubakit1.hateblo.jp/entry/20131203/1386000440 colorPickerTexture.ReadPixels(new Rect(mousePos, Vector2.one), 0, 0); Color color = colorPickerTexture.GetPixels32()[0]; pickedColor = color; - return (color.a >= opacityThreshold); // alpha 达到阈值则视为不透明 + return (color.a >= opacityThreshold); // alpha 达到阈值则视为不透明 } catch (System.Exception ex) { @@ -797,7 +813,7 @@ namespace Kirurobo private void HitTestByRaycast() { Vector2 position = GetClientCursorPosition(); - + // // 判断是否在 uGUI 上 var raycastResults = new List(); pointerEventData.position = position; @@ -838,7 +854,8 @@ namespace Kirurobo onObject = true; return; } - } else + } + else { // 如果相机无效,则获取主相机 currentCamera = Camera.main; @@ -878,6 +895,7 @@ namespace Kirurobo { SetTopmost(_isTopmost); } + SetZoomed(_isZoomed); SetClickThrough(_isClickThrough); SetAllowDrop(_allowDropFiles); @@ -889,11 +907,11 @@ namespace Kirurobo } else { - #if UNITY_EDITOR +#if UNITY_EDITOR // 在编辑器中,由于 Game 视图可能被关闭或停靠,如果发生变化则更改目标窗口 // 如果活动窗口与当前目标相同,则不执行任何操作 _uniWinCore.AttachMyActiveWindow(); - #endif +#endif } } @@ -974,7 +992,8 @@ namespace Kirurobo /// public void SetTransparentType(TransparentType type) { - if (_uniWinCore != null) { + if (_uniWinCore != null) + { // 如果正在透明中,则先解除再重新透明 if (_isTransparent) { @@ -1081,6 +1100,7 @@ namespace Kirurobo { return new Rect(position, size); } + return Rect.zero; } @@ -1115,7 +1135,7 @@ namespace Kirurobo UpdateMonitorFitting(); } } - } + } else { if (_shouldFitMonitor) @@ -1147,7 +1167,7 @@ namespace Kirurobo { return UniWinCore.GetCursorPosition(); } - + /// /// 设置鼠标光标位置 /// @@ -1218,10 +1238,12 @@ namespace Kirurobo [Obsolete] public int GetDebugInfo() { - if (_uniWinCore != null) { + if (_uniWinCore != null) + { return UniWinCore.GetDebugInfo(); } + return 0; } } -} +} \ No newline at end of file diff --git a/Runtime/Scripts/UniWindowMoveHandle.cs b/Runtime/Scripts/UniWindowMoveHandle.cs index 9da36a2..bc62de4 100644 --- a/Runtime/Scripts/UniWindowMoveHandle.cs +++ b/Runtime/Scripts/UniWindowMoveHandle.cs @@ -1,6 +1,6 @@ /* * UniWindowDragMove.cs - * + * * 作者: Kirurobo http://twitter.com/kirurobo * 许可证: MIT */ @@ -10,22 +10,23 @@ using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.EventSystems; + #if ENABLE_LEGACY_INPUT_MANAGER #elif ENABLE_INPUT_SYSTEM using UnityEngine.InputSystem; #endif -namespace Kirurobo +namespace Kirurobo { - public class UniWindowMoveHandle : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler, IPointerUpHandler + public class UniWindowMoveHandle : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler, + IPointerUpHandler { private UniWindowController _uniwinc; /// /// 窗口最大化时是否禁用移动 /// - [Tooltip("窗口已最大化(缩放)时禁用拖拽移动。")] - public bool disableOnZoomed = true; + [Tooltip("窗口已最大化(缩放)时禁用拖拽移动。")] public bool disableOnZoomed = true; /// /// 拖动中则为 true @@ -34,6 +35,7 @@ namespace Kirurobo { get { return _isDragging; } } + private bool _isDragging = false; /// @@ -56,17 +58,21 @@ namespace Kirurobo /// 记录拖动前自动命中测试是否启用 /// private bool _isHitTestEnabled; - + /// /// 拖动开始时窗口内坐标[像素] /// private Vector2 _dragStartedPosition; - + // 首次帧更新前调用 Start void Start() { // 获取场景中的 UniWindowController +#if UNITY_2022_1_OR_NEWER _uniwinc = GameObject.FindAnyObjectByType(); +#else + _uniwinc = GameObject.FindObjectOfType(); +#endif if (_uniwinc) _isHitTestEnabled = _uniwinc.isHitTestEnabled; //// 下面的代码似乎不需要,所以注释掉以免擅自更改 @@ -85,7 +91,7 @@ namespace Kirurobo // 仅通过鼠标左键拖动 if (eventData.button != PointerEventData.InputButton.Left) return; - + // Mac 上行为会有所不同 // 实际上仅在 Retina 支持启用时,但 eventData.position 的坐标系与窗口坐标系的缩放会不一致 #if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX @@ -93,7 +99,7 @@ namespace Kirurobo #else _dragStartedPosition = eventData.position; #endif - + // 如果 _isDragging 为 false,则判断即将开始拖动 if (!_isDragging) { @@ -102,7 +108,7 @@ namespace Kirurobo _uniwinc.isHitTestEnabled = false; _uniwinc.isClickThrough = false; } - + _isDragging = true; } @@ -130,11 +136,12 @@ namespace Kirurobo { if (_isDragging) { - _uniwinc.isHitTestEnabled = _isHitTestEnabled; + _uniwinc.isHitTestEnabled = _isHitTestEnabled; } + _isDragging = false; } - + /// /// 非最大化时,通过鼠标拖动移动窗口 /// @@ -158,7 +165,8 @@ namespace Kirurobo // 如果鼠标按钮已松开,则结束拖动 var buttons = UniWindowController.GetMouseButtons(); - if ((buttons & UniWindowController.MouseButton.Left) == UniWindowController.MouseButton.None) { + if ((buttons & UniWindowController.MouseButton.Left) == UniWindowController.MouseButton.None) + { EndDragging(); return; } @@ -203,4 +211,4 @@ namespace Kirurobo #endif } } -} +} \ No newline at end of file