91 lines
3.2 KiB
C#
91 lines
3.2 KiB
C#
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
|
|
/// <summary>
|
|
/// OS 커서 위치를 Unity 화면 좌표로 변환한다.
|
|
///
|
|
/// 우리 창은 WS_EX_NOACTIVATE 라 포커스를 받지 않으므로 Unity 의 Mouse.position 을
|
|
/// 신뢰할 수 없다. 또 창 밖 좌표는 Unity 가 아예 모른다. 그래서 GetCursorPos 로
|
|
/// OS 커서를 직접 읽고 창 사각형 기준으로 환산한다.
|
|
///
|
|
/// 히트테스트와 시선 추적이 같은 변환을 쓰므로 여기 한 곳에만 둔다.
|
|
/// </summary>
|
|
public static class DesktopCursor
|
|
{
|
|
/// <summary>
|
|
/// 데스크톱 물리 좌표(Y 아래로) <-> Unity 화면 좌표(Y 위로) 변환에 필요한 정보.
|
|
/// 창 사각형을 매번 다시 묻지 않도록 한 번 만들어 재사용한다.
|
|
/// </summary>
|
|
public struct Mapping
|
|
{
|
|
public int Left, Top, Width, Height;
|
|
public float ScaleX, ScaleY;
|
|
|
|
public float ToScreenX(float desktopX) => (desktopX - Left) * ScaleX;
|
|
public float ToScreenY(float desktopY) => (Height - (desktopY - Top)) * ScaleY;
|
|
public Vector2 ToScreen(float desktopX, float desktopY)
|
|
=> new Vector2(ToScreenX(desktopX), ToScreenY(desktopY));
|
|
}
|
|
|
|
/// <summary>우리 창을 기준으로 한 좌표 변환 정보를 구한다.</summary>
|
|
public static bool TryGetMapping(System.IntPtr hwnd, out Mapping mapping)
|
|
{
|
|
mapping = default;
|
|
|
|
#if !UNITY_EDITOR && UNITY_STANDALONE_WIN
|
|
if (hwnd == System.IntPtr.Zero) return false;
|
|
if (!Win32.GetWindowRect(hwnd, out var rc)) return false;
|
|
if (rc.Width <= 0 || rc.Height <= 0) return false;
|
|
|
|
mapping = new Mapping
|
|
{
|
|
Left = rc.left,
|
|
Top = rc.top,
|
|
Width = rc.Width,
|
|
Height = rc.Height,
|
|
// 창 크기와 백버퍼 크기가 어긋날 경우를 대비해 비율로 환산한다.
|
|
ScaleX = Screen.width / (float)rc.Width,
|
|
ScaleY = Screen.height / (float)rc.Height,
|
|
};
|
|
return true;
|
|
#else
|
|
mapping = new Mapping
|
|
{
|
|
Left = 0, Top = 0, Width = Screen.width, Height = Screen.height,
|
|
ScaleX = 1f, ScaleY = 1f,
|
|
};
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// 커서의 Unity 화면 좌표(좌하단 원점)를 구한다. 커서가 창 밖이면 false.
|
|
/// </summary>
|
|
public static bool TryGetScreenPosition(System.IntPtr hwnd, out Vector2 screenPos)
|
|
{
|
|
screenPos = default;
|
|
|
|
#if !UNITY_EDITOR && UNITY_STANDALONE_WIN
|
|
if (!Win32.GetCursorPos(out var pt)) return false;
|
|
if (!TryGetMapping(hwnd, out Mapping map)) return false;
|
|
|
|
// 창 밖이면 무효로 본다.
|
|
if (pt.x < map.Left || pt.y < map.Top ||
|
|
pt.x >= map.Left + map.Width || pt.y >= map.Top + map.Height) return false;
|
|
|
|
screenPos = map.ToScreen(pt.x, pt.y);
|
|
return true;
|
|
#else
|
|
// 에디터에서는 일반 마우스 입력으로 대체해 미리보기가 가능하게 한다.
|
|
var mouse = Mouse.current;
|
|
if (mouse == null) return false;
|
|
|
|
Vector2 p = mouse.position.ReadValue();
|
|
if (p.x < 0f || p.y < 0f || p.x >= Screen.width || p.y >= Screen.height) return false;
|
|
|
|
screenPos = p;
|
|
return true;
|
|
#endif
|
|
}
|
|
}
|