창 올라타기

This commit is contained in:
2026-08-26 11:01:56 +09:00
parent 65024110df
commit cab0d772b1
18 changed files with 1335 additions and 31 deletions

View File

@@ -14,9 +14,24 @@
[RequireComponent(typeof(Camera))]
public class TransparentWindow : MonoBehaviour
{
public enum CoverageMode
{
/// <summary>플레이어 설정의 기본 해상도를 그대로 쓴다. 디버깅용.</summary>
FixedSize,
/// <summary>주 모니터를 꽉 채운다. 해상도가 달라도 자동으로 맞춘다.</summary>
PrimaryMonitor,
/// <summary>모든 모니터를 합친 가상 데스크톱 전체를 덮는다.</summary>
VirtualDesktop,
}
[Header("창 동작")]
[Tooltip("창을 가상 데스크톱 전체로 확장. 클릭 통과가 동작하는 것을 확인한 뒤 켤 것")]
[SerializeField] bool spanVirtualDesktop = false;
[Tooltip("창이 덮을 범위. 해상도가 바뀌면 자동으로 다시 맞춘다")]
[SerializeField] CoverageMode coverage = CoverageMode.PrimaryMonitor;
[Tooltip("해상도/모니터 변경을 확인하는 주기(초). 0 이면 확인하지 않는다")]
[SerializeField] float boundsCheckInterval = 2f;
[Tooltip("작업표시줄 / Alt+Tab 에서 숨김 (WS_EX_TOOLWINDOW)")]
[SerializeField] bool hideFromTaskbar = true;
@@ -70,19 +85,74 @@ void Update()
var kb = Keyboard.current;
if (kb != null && kb.escapeKey.wasPressedThisFrame) Application.Quit();
}
#if !UNITY_EDITOR && UNITY_STANDALONE_WIN
CheckBoundsChanged();
#endif
}
#if !UNITY_EDITOR && UNITY_STANDALONE_WIN
/// <summary>설정한 범위에 해당하는 화면 사각형을 구한다.</summary>
void GetTargetBounds(out int x, out int y, out int w, out int h)
{
switch (coverage)
{
case CoverageMode.PrimaryMonitor:
x = 0;
y = 0;
w = Win32.GetSystemMetrics(Win32.SM_CXSCREEN);
h = Win32.GetSystemMetrics(Win32.SM_CYSCREEN);
break;
case CoverageMode.VirtualDesktop:
x = Win32.GetSystemMetrics(Win32.SM_XVIRTUALSCREEN);
y = Win32.GetSystemMetrics(Win32.SM_YVIRTUALSCREEN);
w = Win32.GetSystemMetrics(Win32.SM_CXVIRTUALSCREEN);
h = Win32.GetSystemMetrics(Win32.SM_CYVIRTUALSCREEN);
break;
default:
x = 0;
y = 0;
w = Screen.width;
h = Screen.height;
break;
}
}
bool applying;
Vector4 appliedBounds = new Vector4(-1f, -1f, -1f, -1f);
float nextBoundsCheck;
/// <summary>
/// 해상도 변경, 모니터 연결/해제, 배율 변경에 대응한다.
/// 이걸 안 하면 모니터를 바꿔 꽂았을 때 창이 예전 크기로 남아 화면 일부만 덮는다.
/// </summary>
void CheckBoundsChanged()
{
if (!IsReady || applying) return;
if (boundsCheckInterval <= 0f) return;
if (Time.unscaledTime < nextBoundsCheck) return;
nextBoundsCheck = Time.unscaledTime + boundsCheckInterval;
GetTargetBounds(out int x, out int y, out int w, out int h);
var now = new Vector4(x, y, w, h);
if (now == appliedBounds) return;
Debug.Log($"[TransparentWindow] 화면 구성 변경 감지: {appliedBounds} -> {now}. 다시 적용합니다.");
StartCoroutine(ApplyWindowStyle());
}
IEnumerator ApplyWindowStyle()
{
int x = 0, y = 0, w = Screen.width, h = Screen.height;
applying = true;
if (spanVirtualDesktop)
GetTargetBounds(out int x, out int y, out int w, out int h);
appliedBounds = new Vector4(x, y, w, h);
if (coverage != CoverageMode.FixedSize && (w != Screen.width || h != Screen.height))
{
x = Win32.GetSystemMetrics(Win32.SM_XVIRTUALSCREEN);
y = Win32.GetSystemMetrics(Win32.SM_YVIRTUALSCREEN);
w = Win32.GetSystemMetrics(Win32.SM_CXVIRTUALSCREEN);
h = Win32.GetSystemMetrics(Win32.SM_CYVIRTUALSCREEN);
Screen.SetResolution(w, h, FullScreenMode.Windowed);
}
@@ -123,7 +193,8 @@ IEnumerator ApplyWindowStyle()
Hwnd = hwnd;
IsReady = true;
Debug.Log($"[TransparentWindow] 적용 완료: {x},{y} {w}x{h}");
applying = false;
Debug.Log($"[TransparentWindow] 적용 완료: {coverage} {x},{y} {w}x{h}");
}
#endif
}