Files
2026-07-10 12:20:54 +08:00

926 lines
32 KiB
C#

/*
* UniWinCore.cs
*
* Author: Kirurobo http://twitter.com/kirurobo
* License: MIT 许可证
*/
using System;
using System.Runtime.InteropServices;
using AOT;
using UnityEngine;
using System.Text;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Kirurobo
{
/// <summary>
/// LibUniWinC 的原生插件包装
/// </summary>
internal class UniWinCore : IDisposable
{
/// <summary>
/// 仅 Windows 下的透明方法类型
/// </summary>
public enum TransparentType : int
{
None = 0,
Alpha = 1,
ColorKey = 2,
}
/// <summary>
/// 状态变更事件类型(实验性)
/// </summary>
[Flags]
public enum WindowStateEventType : int
{
None = 0,
StyleChanged = 1,
Resized = 2,
// 后续规格可能会有变更
TopMostEnabled = 16 + 1 + 8,
TopMostDisabled = 16 + 1,
BottomMostEnabled = 32 + 1 + 8,
BottomMostDisabled = 32 + 1,
WallpaperModeEnabled = 64 + 1 + 8,
WallpaperModeDisabled = 64 + 1,
};
#region Native functions
protected class LibUniWinC
{
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate void StringCallback([MarshalAs(UnmanagedType.LPWStr)] string returnString);
[UnmanagedFunctionPointer((CallingConvention.Winapi))]
public delegate void IntCallback([MarshalAs(UnmanagedType.I4)] int value);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsActive();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsTransparent();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsBorderless();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsTopmost();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsBottommost();
[DllImport("LibUniWinC", CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsMaximized();
[DllImport("LibUniWinC", CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsFreePositioningEnabled();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AttachMyWindow();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AttachMyOwnerWindow();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AttachMyActiveWindow();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DetachWindow();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern void Update();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern void SetTransparent([MarshalAs(UnmanagedType.U1)] bool bEnabled);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern void SetBorderless([MarshalAs(UnmanagedType.U1)] bool bEnabled);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern void SetAlphaValue(float alpha);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern void SetClickThrough([MarshalAs(UnmanagedType.U1)] bool bEnabled);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern void SetTopmost([MarshalAs(UnmanagedType.U1)] bool bEnabled);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern void SetBottommost([MarshalAs(UnmanagedType.U1)] bool bEnabled);
[DllImport("LibUniWinC", CallingConvention = CallingConvention.Winapi)]
public static extern void SetMaximized([MarshalAs(UnmanagedType.U1)] bool bZoomed);
[DllImport("LibUniWinC", CallingConvention = CallingConvention.Winapi)]
public static extern void EnableFreePositioning([MarshalAs(UnmanagedType.U1)] bool bEnabled);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern void SetPosition(float x, float y);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetPosition(out float x, out float y);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern void SetSize(float x, float y);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetSize(out float x, out float y);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetClientSize(out float width, out float height);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetClientRectangle(out float x, out float y, out float width, out float height);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool RegisterDropFilesCallback([MarshalAs(UnmanagedType.FunctionPtr)] StringCallback callback);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnregisterDropFilesCallback();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool RegisterMonitorChangedCallback([MarshalAs(UnmanagedType.FunctionPtr)] IntCallback callback);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnregisterMonitorChangedCallback();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool RegisterWindowStyleChangedCallback([MarshalAs(UnmanagedType.FunctionPtr)] IntCallback callback);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnregisterWindowStyleChangedCallback();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetAllowDrop([MarshalAs(UnmanagedType.U1)] bool enabled);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern int GetCurrentMonitor();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern int GetMonitorCount();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMonitorRectangle(int index, out float x, out float y, out float width, out float height);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern void SetCursorPosition(float x, float y);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetCursorPosition(out float x, out float y);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern int GetMouseButtons();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern int GetModifierKeys();
#region 仅适用于 Windows
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern void SetTransparentType(int type);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern void SetKeyColor(uint colorref);
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
public static extern int GetDebugInfo();
[DllImport("LibUniWinC",CallingConvention=CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AttachWindowHandle(IntPtr hWnd);
#endregion
}
#endregion
static string[] lastDroppedFiles;
static bool wasDropped = false;
static bool wasMonitorChanged = false;
static bool wasWindowStyleChanged = false;
static WindowStateEventType windowStateEventType = WindowStateEventType.None;
#if UNITY_EDITOR
/// <summary>
/// 获取 Unity 编辑器窗口
/// </summary>
/// <returns></returns>
/// <seealso href="http://baba-s.hatenablog.com/entry/2017/09/17/135018"/>
public static EditorWindow GetGameView()
{
var assembly = typeof(EditorWindow).Assembly;
var type = assembly.GetType("UnityEditor.GameView");
var gameView = EditorWindow.GetWindow(type);
return gameView;
}
#endif
/// <summary>
/// 判断窗口是否已附加且可用
/// </summary>
/// <value><c>true</c> 如果此实例处于活动状态;否则为 <c>false</c>。</value>
public bool IsActive { get; private set; } = false;
/// <summary>
/// 判断附加窗口是否始终置顶
/// </summary>
public bool IsTopmost { get { return (IsActive && _isTopmost); } }
private bool _isTopmost = false;
/// <summary>
/// 判断附加窗口是否始终置底
/// </summary>
public bool IsBottommost { get { return (IsActive && _isBottommost); } }
private bool _isBottommost = false;
/// <summary>
/// 判断附加窗口是否透明
/// </summary>
public bool IsTransparent { get { return (IsActive && _isTransparent); } }
private bool _isTransparent = false;
/// <summary>
/// 判断附加窗口是否点击穿透(即不接收任何鼠标操作)
/// </summary>
public bool IsClickThrough { get { return (IsActive && _isClickThrough); } }
private bool _isClickThrough = false;
/// <summary>
/// 判断附加窗口是否无边框(无标题栏和边框)
/// </summary>
public bool IsBorderless { get { return (IsActive && _isBorderless); } }
private bool _isBorderless = false;
/// <summary>
/// 判断附加窗口是否可以自由定位(仅 macOS)
/// </summary>
public bool IsFreePositioningEnabled { get { return (IsActive && _isFreePositioningEnabled); } }
private bool _isFreePositioningEnabled = false;
/// <summary>
/// Windows 下的透明方法类型
/// </summary>
private TransparentType transparentType = TransparentType.Alpha;
/// <summary>
/// 当 transparentType 为 ColorKey 时用于透明的颜色
/// </summary>
private Color32 keyColor = new Color32(1, 0, 1, 0);
#region Constructor or destructor
/// <summary>
/// 窗口控制构造函数
/// </summary>
public UniWinCore()
{
IsActive = false;
}
/// <summary>
/// 析构函数
/// </summary>
~UniWinCore()
{
Dispose();
}
/// <summary>
/// 结束时的处理
/// </summary>
public void Dispose()
{
// 由于最后恢复窗口状态会引起注意,所以特意不恢复,因此注释掉
//DetachWindow();
// 替代 DetachWindow()
LibUniWinC.UnregisterDropFilesCallback();
LibUniWinC.UnregisterMonitorChangedCallback();
LibUniWinC.UnregisterWindowStyleChangedCallback();
}
#endregion
#region Callbacks
/// <summary>
/// 显示器或分辨率变化时的回调
/// 此处的处理保持最低限度,仅设置标志
/// </summary>
/// <param name="monitorCount"></param>
[MonoPInvokeCallback(typeof(LibUniWinC.IntCallback))]
private static void _monitorChangedCallback([MarshalAs(UnmanagedType.I4)] int monitorCount)
{
wasMonitorChanged = true;
}
/// <summary>
/// 窗口样式、最大化、最小化等调用的回调
/// 此处的处理保持最低限度,仅设置标志
/// </summary>
/// <param name="e"></param>
[MonoPInvokeCallback(typeof(LibUniWinC.IntCallback))]
private static void _windowStyleChangedCallback([MarshalAs(UnmanagedType.I4)] int e)
{
wasWindowStyleChanged = true;
windowStateEventType = (WindowStateEventType)e;
}
/// <summary>
/// 文件或文件夹被拖放时调用的回调
/// 将字符串转换为数组,并设置标志位
/// </summary>
/// <param name="paths"></param>
[MonoPInvokeCallback(typeof(LibUniWinC.StringCallback))]
private static void _dropFilesCallback([MarshalAs(UnmanagedType.LPWStr)] string paths)
{
// 将以 LF 分隔的字符串分割为路径数组
//char[] delimiters = { '\n', '\0' };
//string[] files = paths.Split(delimiters).Where(s => s != "").ToArray();
string[] files = parsePaths(paths);
if (files.Length > 0)
{
lastDroppedFiles = new string[files.Length];
files.CopyTo(lastDroppedFiles, 0);
wasDropped = true;
}
}
/// <summary>
/// 将双引号包围、LF(或null)分隔的字符串转换为数组并返回
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
internal static string[] parsePaths(string text)
{
System.Collections.Generic.List<string> list = new System.Collections.Generic.List<string>();
bool inEscaped = false;
int len = text.Length;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < len; i++)
{
char c = text[i];
if (c == '"')
{
if (inEscaped)
{
if (((i + 1) < len) && text[i + 1] == '"')
{
i++;
sb.Append(c); // 连续双引号视为一个双引号
continue;
}
}
inEscaped = !inEscaped; // 非连续则切换是否在引号内
}
else if (c == '\n')
{
if (inEscaped)
{
// 如果在引号内,则作为路径的一部分
sb.Append(c);
}
else
{
// 如果不在引号内,则作为分隔符,移到下一个路径
if (sb.Length > 0)
{
list.Add(sb.ToString());
//sb.Clear(); // for .NET 4 or later
sb.Length = 0; // for .NET 2
}
}
}
else if (c == '\0')
{
// 空字符始终作为分隔符,移到下一个路径
if (sb.Length > 0)
{
list.Add(sb.ToString());
//sb.Clear(); // for .NET 4 or later
sb.Length = 0; // for .NET 2
}
}
else
{
sb.Append(c);
}
}
if (sb.Length > 0)
{
list.Add(sb.ToString());
}
// 移除空字符串元素
list.RemoveAll(v => v.Length == 0);
return list.ToArray();
}
#endregion
#region Find, attach or detach
/// <summary>
/// 将窗口状态恢复至最初并从操作对象中解除
/// </summary>
public void DetachWindow()
{
#if UNITY_EDITOR
// 在编辑器中,窗口样式可能无法正确获取置顶状态,
// 因此默认视为非置顶,在分离时强制取消置顶
EnableTopmost(false);
#endif
LibUniWinC.DetachWindow();
}
/// <summary>
/// 查找自己的窗口(如果游戏视图是独立窗口则查找它)并作为操作对象
/// </summary>
/// <returns></returns>
public bool AttachMyWindow()
{
#if UNITY_EDITOR_WIN
// 似乎没有可靠的方法获取游戏视图,因此给予焦点后立即获取活动窗口
var gameView = GetGameView();
if (gameView)
{
gameView.Focus();
LibUniWinC.AttachMyActiveWindow();
}
#else
LibUniWinC.AttachMyWindow();
#endif
// 添加事件处理程序
LibUniWinC.RegisterDropFilesCallback(_dropFilesCallback);
LibUniWinC.RegisterMonitorChangedCallback(_monitorChangedCallback);
LibUniWinC.RegisterWindowStyleChangedCallback(_windowStyleChangedCallback);
IsActive = LibUniWinC.IsActive();
return IsActive;
}
public bool AttachWindowHandle(IntPtr hWnd)
{
LibUniWinC.AttachWindowHandle(hWnd);
IsActive = LibUniWinC.IsActive();
return IsActive;
}
/// <summary>
/// 选择自己进程中当前活动的窗口
/// 编辑器情况下,窗口会关闭或停靠,因此在聚焦时调用
/// </summary>
/// <returns></returns>
public bool AttachMyActiveWindow()
{
LibUniWinC.AttachMyActiveWindow();
IsActive = LibUniWinC.IsActive();
return IsActive;
}
#endregion
#region About window status
/// <summary>
/// 定期调用以维持窗口样式
/// </summary>
public void Update()
{
LibUniWinC.Update();
}
string GetDebubgWindowSizeInfo()
{
float x, y, cx, cy;
LibUniWinC.GetSize(out x, out y);
LibUniWinC.GetClientSize(out cx, out cy);
return $"W:{x},H:{y} CW:{cx},CH:{cy}";
}
/// <summary>
/// 设置/取消透明
/// </summary>
/// <param name="isTransparent"></param>
public void EnableTransparent(bool isTransparent)
{
// 编辑器无法透明或边框与正常不同,因此跳过
#if !UNITY_EDITOR
LibUniWinC.SetTransparent(isTransparent);
LibUniWinC.SetBorderless(isTransparent);
#endif
this._isTransparent = isTransparent;
}
/// <summary>
/// 设置窗口透明度
/// </summary>
/// <param name="alpha">0.0 - 1.0</param>
public void SetAlphaValue(float alpha)
{
// Windows 编辑器下,一旦半透明化后显示不会更新,因此禁用。Mac 则没问题
#if !UNITY_EDITOR_WIN
LibUniWinC.SetAlphaValue(alpha);
#endif
}
/// <summary>
/// 设置窗口 Z 顺序(是否置顶)。
/// </summary>
/// <param name="isTopmost">如果设为 <c>true</c> 则置顶。</param>
public void EnableTopmost(bool isTopmost)
{
LibUniWinC.SetTopmost(isTopmost);
this._isTopmost = isTopmost;
this._isBottommost = false; // 互斥
}
/// <summary>
/// 设置窗口 Z 顺序(是否置底)。
/// </summary>
/// <param name="isBottommost">如果设为 <c>true</c> 则置底。</param>
public void EnableBottommost(bool isBottommost)
{
LibUniWinC.SetBottommost(isBottommost);
this._isBottommost = isBottommost;
this._isTopmost = false; // 互斥
}
/// <summary>
/// 设置/取消点击穿透
/// </summary>
/// <param name="isThrough"></param>
public void EnableClickThrough(bool isThrough)
{
// 编辑器下点击穿透可能导致无法操作,因此跳过
#if !UNITY_EDITOR
LibUniWinC.SetClickThrough(isThrough);
#endif
this._isClickThrough = isThrough;
}
/// <summary>
/// 最大化窗口(Mac 上为缩放)
/// 最大化后可能还会调整大小,目前可能无法可靠工作
/// </summary>
public void SetZoomed(bool isZoomed)
{
LibUniWinC.SetMaximized(isZoomed);
}
/// <summary>
/// 获取窗口是否已最大化(Mac 上为缩放)
/// 最大化后可能还会调整大小,目前可能无法可靠工作
/// </summary>
public bool GetZoomed()
{
return LibUniWinC.IsMaximized();
}
/// <summary>
/// 设置窗口位置。
/// </summary>
/// <param name="position">位置。</param>
public void SetWindowPosition(Vector2 position)
{
LibUniWinC.SetPosition(position.x, position.y);
}
/// <summary>
/// 获取窗口位置。
/// </summary>
/// <returns>位置。</returns>
public Vector2 GetWindowPosition()
{
Vector2 pos = Vector2.zero;
LibUniWinC.GetPosition(out pos.x, out pos.y);
return pos;
}
/// <summary>
/// 设置窗口大小。
/// </summary>
/// <param name="size">x 为宽度,y 为高度</param>
public void SetWindowSize(Vector2 size)
{
LibUniWinC.SetSize(size.x, size.y);
}
/// <summary>
/// 获取窗口大小。
/// </summary>
/// <returns>x 为宽度,y 为高度</returns>
public Vector2 GetWindowSize()
{
Vector2 size = Vector2.zero;
LibUniWinC.GetSize(out size.x, out size.y);
return size;
}
/// <summary>
/// 获取客户区大小。
/// </summary>
/// <returns>x 为宽度,y 为高度</returns>
public Vector2 GetClientSize()
{
Vector2 size = Vector2.zero;
LibUniWinC.GetClientSize(out size.x, out size.y);
return size;
}
/// <summary>
/// 获取客户区矩形。
/// </summary>
/// <returns>x 为宽度,y 为高度</returns>
public Rect GetClientRectangle()
{
Vector2 pos = Vector2.zero;
Vector2 size = Vector2.zero;
LibUniWinC.GetClientRectangle(out pos.x, out pos.y, out size.x, out size.y);
return new Rect(pos.x, pos.y, size.x, size.y);
}
#endregion
#region File opening
public void SetAllowDrop(bool enabled)
{
LibUniWinC.SetAllowDrop(enabled);
}
#endregion
#region Event observers
/// <summary>
/// 检查文件拖放并取消拖放标志
/// </summary>
/// <param name="files"></param>
/// <returns>如果文件被拖放则返回 true</returns>
public bool ObserveDroppedFiles(out string[] files)
{
files = lastDroppedFiles;
if (!wasDropped || files == null) return false;
wasDropped = false;
return true;
}
/// <summary>
/// 检查显示器数量或分辨率变化,并取消标志
/// </summary>
/// <returns>如果已变化则返回 true</returns>
public bool ObserveMonitorChanged()
{
if (!wasMonitorChanged) return false;
wasMonitorChanged = false;
return true;
}
/// <summary>
/// 检查窗口样式是否已变更,并取消标志
/// </summary>
/// <returns>如果窗口样式已变更则返回 true</returns>
public bool ObserveWindowStyleChanged()
{
if (!wasWindowStyleChanged) return false;
windowStateEventType = WindowStateEventType.None;
wasWindowStyleChanged = false;
return true;
}
/// <summary>
/// 检查窗口样式是否已变更,并取消标志
/// </summary>
/// <returns>如果窗口样式已变更则返回 true</returns>
public bool ObserveWindowStyleChanged(out WindowStateEventType type)
{
if (!wasWindowStyleChanged)
{
type = WindowStateEventType.None;
return false;
}
type = windowStateEventType;
windowStateEventType = WindowStateEventType.None;
wasWindowStyleChanged = false;
return true;
}
#endregion
#region About mouse cursor
/// <summary>
/// 设置鼠标指针位置。
/// </summary>
/// <param name="position">位置。</param>
public static void SetCursorPosition(Vector2 position)
{
LibUniWinC.SetCursorPosition(position.x, position.y);
}
/// <summary>
/// 获取鼠标指针位置。
/// </summary>
/// <returns>位置。</returns>
public static Vector2 GetCursorPosition()
{
Vector2 pos = Vector2.zero;
LibUniWinC.GetCursorPosition(out pos.x, out pos.y);
return pos;
}
/// <summary>
/// Get pressed mouse buttons.
/// </summary>
/// <returns>Bit flags of pressed buttons</returns>
public static int GetMouseButtons()
{
return LibUniWinC.GetMouseButtons();
}
/// <summary>
/// 获取按下的修饰键。
/// </summary>
/// <returns>按下键的位标志</returns>
public static int GetModifierKeys()
{
return LibUniWinC.GetModifierKeys();
}
// 未实现
public static bool GetCursorVisible()
{
return true;
}
#endregion
#region for Windows only
/// <summary>
/// 指定透明方法(仅 Windows 支持)
/// </summary>
/// <param name="type"></param>
public void SetTransparentType(TransparentType type)
{
LibUniWinC.SetTransparentType((Int32)type);
transparentType = type;
}
/// <summary>
/// 单色透明时指定透明色(仅 Windows 支持)
/// </summary>
/// <param name="color"></param>
public void SetKeyColor(Color32 color)
{
LibUniWinC.SetKeyColor((UInt32)(color.b * 0x10000 + color.g * 0x100 + color.r));
keyColor = color;
}
#endregion
#region for macOS only
/// <summary>
/// 设置/取消窗口的自由配置(仅 macOS 支持)
/// </summary>
/// <param name="enabled"></param>
public void EnableFreePositioning(bool enabled)
{
LibUniWinC.EnableFreePositioning(enabled);
_isFreePositioningEnabled = LibUniWinC.IsFreePositioningEnabled();
}
#endregion
#region About monitors
/// <summary>
/// 获取窗口所在显示器的索引
/// </summary>
/// <returns>显示器索引</returns>
public int GetCurrentMonitor()
{
return LibUniWinC.GetCurrentMonitor();
}
/// <summary>
/// 获取已连接显示器的数量
/// </summary>
/// <returns>数量</returns>
public static int GetMonitorCount()
{
return LibUniWinC.GetMonitorCount();
}
/// <summary>
/// 获取显示器的位置和大小
/// </summary>
/// <param name="index"></param>
/// <param name="position"></param>
/// <param name="size"></param>
/// <returns></returns>
public static bool GetMonitorRectangle(int index, out Vector2 position, out Vector2 size)
{
return LibUniWinC.GetMonitorRectangle(index, out position.x, out position.y, out size.x, out size.y);
}
/// <summary>
/// 将窗口适配到指定显示器
/// </summary>
/// <param name="monitorIndex"></param>
/// <returns></returns>
public bool FitToMonitor(int monitorIndex)
{
float dx, dy, dw, dh;
if (LibUniWinC.GetMonitorRectangle(monitorIndex, out dx, out dy, out dw, out dh))
{
// 如果处于最大化状态则先恢复
if (LibUniWinC.IsMaximized()) LibUniWinC.SetMaximized(false);
// 指定显示器的中心坐标
float cx = dx + (dw / 2);
float cy = dy + (dh / 2);
// 将窗口中心移动到指定显示器中心
float ww, wh;
LibUniWinC.GetSize(out ww, out wh);
float wx = cx - (ww / 2);
float wy = cy - (wh / 2);
LibUniWinC.SetPosition(wx, wy);
// 最大化
LibUniWinC.SetMaximized(true);
//Debug.Log(String.Format("显示器 {4} : {0},{1} - {2},{3}", dx, dy, dw, dh, monitorIndex));
return true;
}
return false;
}
/// <summary>
/// 打印显示器列表
/// </summary>
[Obsolete]
public static void DebugMonitorInfo()
{
int monitors = LibUniWinC.GetMonitorCount();
int currentMonitorIndex = LibUniWinC.GetCurrentMonitor();
string message = "当前显示器: " + currentMonitorIndex + "\r\n";
for (int i = 0; i < monitors; i++)
{
float x, y, w, h;
bool result = LibUniWinC.GetMonitorRectangle(i, out x, out y, out w, out h);
message += String.Format(
"显示器 {0}: X:{1}, Y:{2} - W:{3}, H:{4}\r\n",
i, x, y, w, h
);
}
Debug.Log(message);
}
/// <summary>
/// 获取用于调试的信息
/// </summary>
/// <returns></returns>
[Obsolete]
public static int GetDebugInfo()
{
return LibUniWinC.GetDebugInfo();
}
#endregion
}
}