add SFMLRenderWindow
This commit is contained in:
@@ -64,10 +64,10 @@ namespace SFMLRenderer
|
|||||||
hs?.Dispose();
|
hs?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private nint HwndMessageHook(nint hwnd, int msg, nint wParam, nint lParam, ref bool handled)
|
private IntPtr HwndMessageHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
||||||
{
|
{
|
||||||
_renderWindow?.DispatchEvents();
|
_renderWindow?.DispatchEvents();
|
||||||
return nint.Zero;
|
return IntPtr.Zero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
171
SFMLRenderer/SFMLRenderWindow.cs
Normal file
171
SFMLRenderer/SFMLRenderWindow.cs
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
using SFML.Graphics;
|
||||||
|
using SFML.System;
|
||||||
|
using SFML.Window;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
|
namespace SFMLRenderer
|
||||||
|
{
|
||||||
|
public class SFMLRenderWindow : RenderWindow, ISFMLRenderer
|
||||||
|
{
|
||||||
|
private readonly DispatcherTimer _timer = new() { Interval = TimeSpan.FromMilliseconds(10) };
|
||||||
|
|
||||||
|
public SFMLRenderWindow(VideoMode mode, string title, Styles style) : base(mode, title, style)
|
||||||
|
{
|
||||||
|
SetActive(false);
|
||||||
|
_timer.Tick += (s, e) => DispatchEvents();
|
||||||
|
_timer.Start();
|
||||||
|
RendererCreated?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler? RendererCreated;
|
||||||
|
|
||||||
|
public event EventHandler? RendererDisposing
|
||||||
|
{
|
||||||
|
add => throw new NotImplementedException();
|
||||||
|
remove => throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<MouseMoveEventArgs>? CanvasMouseMove
|
||||||
|
{
|
||||||
|
add { MouseMoved += value; }
|
||||||
|
remove { MouseMoved -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<MouseButtonEventArgs>? CanvasMouseButtonPressed
|
||||||
|
{
|
||||||
|
add { MouseButtonPressed += value; }
|
||||||
|
remove { MouseButtonPressed -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<MouseButtonEventArgs>? CanvasMouseButtonReleased
|
||||||
|
{
|
||||||
|
add { MouseButtonReleased += value; }
|
||||||
|
remove { MouseButtonReleased -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<MouseWheelScrollEventArgs>? CanvasMouseWheelScrolled
|
||||||
|
{
|
||||||
|
add { MouseWheelScrolled += value; }
|
||||||
|
remove { MouseWheelScrolled -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2u Resolution
|
||||||
|
{
|
||||||
|
get => Size;
|
||||||
|
set => Size = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector2f Center
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using var view = GetView();
|
||||||
|
return view.Center;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
using var view = GetView();
|
||||||
|
view.Center = value;
|
||||||
|
SetView(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Zoom
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using var view = GetView();
|
||||||
|
return Math.Abs(Size.X / view.Size.X); // XXX: 仅使用宽度进行缩放计算
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
value = Math.Abs(value);
|
||||||
|
if (value <= 0) return;
|
||||||
|
using var view = GetView();
|
||||||
|
var signX = Math.Sign(view.Size.X);
|
||||||
|
var signY = Math.Sign(view.Size.Y);
|
||||||
|
var resolution = Size;
|
||||||
|
view.Size = new(resolution.X / value * signX, resolution.Y / value * signY);
|
||||||
|
SetView(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Rotation
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using var view = GetView();
|
||||||
|
return view.Rotation;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
using var view = GetView();
|
||||||
|
view.Rotation = value;
|
||||||
|
SetView(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool FlipX
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using var view = GetView();
|
||||||
|
return view.Size.X < 0;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
using var view = GetView();
|
||||||
|
var size = view.Size;
|
||||||
|
if (size.X > 0 && value || size.X < 0 && !value)
|
||||||
|
size.X *= -1;
|
||||||
|
view.Size = size;
|
||||||
|
SetView(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool FlipY
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
using var view = GetView();
|
||||||
|
return view.Size.Y < 0;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
using var view = GetView();
|
||||||
|
var size = view.Size;
|
||||||
|
if (size.Y > 0 && value || size.Y < 0 && !value)
|
||||||
|
size.Y *= -1;
|
||||||
|
view.Size = size;
|
||||||
|
SetView(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint MaxFps
|
||||||
|
{
|
||||||
|
get => _maxFps;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetFramerateLimit(value);
|
||||||
|
_maxFps = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private uint _maxFps = 0;
|
||||||
|
|
||||||
|
public bool VerticalSync
|
||||||
|
{
|
||||||
|
get => _verticalSync;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetVerticalSyncEnabled(value);
|
||||||
|
_verticalSync = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private bool _verticalSync = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,15 +15,15 @@ namespace SpineViewer.Natives
|
|||||||
public static class Gdi32
|
public static class Gdi32
|
||||||
{
|
{
|
||||||
[DllImport("gdi32.dll", SetLastError = true)]
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
public static extern nint CreateCompatibleDC(nint hdc);
|
public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
|
||||||
|
|
||||||
[DllImport("gdi32.dll", SetLastError = true)]
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
public static extern bool DeleteDC(nint hdc);
|
public static extern bool DeleteDC(IntPtr hdc);
|
||||||
|
|
||||||
[DllImport("gdi32.dll", SetLastError = true)]
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
public static extern nint SelectObject(nint hdc, nint hgdiobj);
|
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
|
||||||
|
|
||||||
[DllImport("gdi32.dll", SetLastError = true)]
|
[DllImport("gdi32.dll", SetLastError = true)]
|
||||||
public static extern bool DeleteObject(nint hObject);
|
public static extern bool DeleteObject(IntPtr hObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,22 +15,61 @@ namespace SpineViewer.Natives
|
|||||||
public static class User32
|
public static class User32
|
||||||
{
|
{
|
||||||
public const int GWL_STYLE = -16;
|
public const int GWL_STYLE = -16;
|
||||||
public const int WS_SIZEBOX = 0x40000;
|
public const int WS_OVERLAPPED = 0x00000000;
|
||||||
public const int WS_BORDER = 0x800000;
|
|
||||||
public const int WS_VISIBLE = 0x10000000;
|
|
||||||
public const int WS_CHILD = 0x40000000;
|
|
||||||
public const int WS_POPUP = unchecked((int)0x80000000);
|
public const int WS_POPUP = unchecked((int)0x80000000);
|
||||||
|
public const int WS_CHILD = 0x40000000;
|
||||||
|
public const int WS_MINIMIZE = 0x20000000;
|
||||||
|
public const int WS_VISIBLE = 0x10000000;
|
||||||
|
public const int WS_DISABLED = 0x08000000;
|
||||||
|
public const int WS_CLIPSIBLINGS = 0x04000000;
|
||||||
|
public const int WS_CLIPCHILDREN = 0x02000000;
|
||||||
|
public const int WS_MAXIMIZE = 0x01000000;
|
||||||
|
public const int WS_BORDER = 0x00800000;
|
||||||
|
public const int WS_DLGFRAME = 0x00400000;
|
||||||
|
public const int WS_VSCROLL = 0x00200000;
|
||||||
|
public const int WS_HSCROLL = 0x00100000;
|
||||||
|
public const int WS_SYSMENU = 0x00080000;
|
||||||
|
public const int WS_THICKFRAME = 0x00040000;
|
||||||
|
public const int WS_GROUP = 0x00020000;
|
||||||
|
public const int WS_TABSTOP = 0x00010000;
|
||||||
|
public const int WS_MINIMIZEBOX = 0x00020000;
|
||||||
|
public const int WS_MAXIMIZEBOX = 0x00010000;
|
||||||
|
public const int WS_CHILDWINDOW = WS_CHILD;
|
||||||
|
public const int WS_CAPTION = WS_BORDER | WS_DLGFRAME;
|
||||||
|
public const int WS_TILED = WS_OVERLAPPED;
|
||||||
|
public const int WS_ICONIC = WS_MINIMIZE;
|
||||||
|
public const int WS_SIZEBOX = WS_THICKFRAME;
|
||||||
|
public const int WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW;
|
||||||
|
public const int WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
|
||||||
|
public const int WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU;
|
||||||
|
|
||||||
public const int GWL_EXSTYLE = -20;
|
public const int GWL_EXSTYLE = -20;
|
||||||
public const int WS_EX_TOPMOST = 0x8;
|
public const int WS_EX_DLGMODALFRAME = 0x00000001;
|
||||||
public const int WS_EX_TRANSPARENT = 0x20;
|
public const int WS_EX_NOPARENTNOTIFY = 0x00000004;
|
||||||
public const int WS_EX_TOOLWINDOW = 0x80;
|
public const int WS_EX_TOPMOST = 0x00000008;
|
||||||
public const int WS_EX_WINDOWEDGE = 0x100;
|
public const int WS_EX_ACCEPTFILES = 0x00000010;
|
||||||
public const int WS_EX_CLIENTEDGE = 0x200;
|
public const int WS_EX_TRANSPARENT = 0x00000020;
|
||||||
public const int WS_EX_APPWINDOW = 0x40000;
|
public const int WS_EX_MDICHILD = 0x00000040;
|
||||||
public const int WS_EX_LAYERED = 0x80000;
|
public const int WS_EX_TOOLWINDOW = 0x00000080;
|
||||||
|
public const int WS_EX_WINDOWEDGE = 0x00000100;
|
||||||
|
public const int WS_EX_CLIENTEDGE = 0x00000200;
|
||||||
|
public const int WS_EX_CONTEXTHELP = 0x00000400;
|
||||||
|
public const int WS_EX_RIGHT = 0x00001000;
|
||||||
|
public const int WS_EX_LEFT = 0x00000000;
|
||||||
|
public const int WS_EX_RTLREADING = 0x00002000;
|
||||||
|
public const int WS_EX_LTRREADING = 0x00000000;
|
||||||
|
public const int WS_EX_LEFTSCROLLBAR = 0x00004000;
|
||||||
|
public const int WS_EX_RIGHTSCROLLBAR = 0x00000000;
|
||||||
|
public const int WS_EX_CONTROLPARENT = 0x00010000;
|
||||||
|
public const int WS_EX_STATICEDGE = 0x00020000;
|
||||||
|
public const int WS_EX_APPWINDOW = 0x00040000;
|
||||||
public const int WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE;
|
public const int WS_EX_OVERLAPPEDWINDOW = WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE;
|
||||||
public const int WS_EX_NOACTIVATE = 0x8000000;
|
public const int WS_EX_PALETTEWINDOW = WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
|
||||||
|
public const int WS_EX_LAYERED = 0x00080000;
|
||||||
|
public const int WS_EX_NOINHERITLAYOUT = 0x00100000;
|
||||||
|
public const int WS_EX_LAYOUTRTL = 0x00400000;
|
||||||
|
public const int WS_EX_COMPOSITED = 0x02000000;
|
||||||
|
public const int WS_EX_NOACTIVATE = 0x08000000;
|
||||||
|
|
||||||
public const uint LWA_COLORKEY = 0x1;
|
public const uint LWA_COLORKEY = 0x1;
|
||||||
public const uint LWA_ALPHA = 0x2;
|
public const uint LWA_ALPHA = 0x2;
|
||||||
@@ -42,12 +81,23 @@ namespace SpineViewer.Natives
|
|||||||
public const int ULW_ALPHA = 0x00000002;
|
public const int ULW_ALPHA = 0x00000002;
|
||||||
public const int ULW_OPAQUE = 0x00000004;
|
public const int ULW_OPAQUE = 0x00000004;
|
||||||
|
|
||||||
public const nint HWND_TOPMOST = -1;
|
public const IntPtr HWND_TOPMOST = -1;
|
||||||
|
|
||||||
public const uint SWP_NOSIZE = 0x0001;
|
public const uint SWP_ASYNCWINDOWPOS = 0x4000;
|
||||||
public const uint SWP_NOMOVE = 0x0002;
|
public const uint SWP_DEFERERASE = 0x2000;
|
||||||
public const uint SWP_NOZORDER = 0x0004;
|
public const uint SWP_NOSENDCHANGING = 0x0400;
|
||||||
|
public const uint SWP_NOOWNERZORDER = 0x0200;
|
||||||
|
public const uint SWP_NOREPOSITION = 0x0200;
|
||||||
|
public const uint SWP_NOCOPYBITS = 0x0100;
|
||||||
|
public const uint SWP_HIDEWINDOW = 0x0080;
|
||||||
|
public const uint SWP_SHOWWINDOW = 0x0040;
|
||||||
|
public const uint SWP_DRAWFRAME = 0x0020;
|
||||||
public const uint SWP_FRAMECHANGED = 0x0020;
|
public const uint SWP_FRAMECHANGED = 0x0020;
|
||||||
|
public const uint SWP_NOACTIVATE = 0x0010;
|
||||||
|
public const uint SWP_NOREDRAW = 0x0008;
|
||||||
|
public const uint SWP_NOZORDER = 0x0004;
|
||||||
|
public const uint SWP_NOMOVE = 0x0002;
|
||||||
|
public const uint SWP_NOSIZE = 0x0001;
|
||||||
|
|
||||||
public const int WM_SPAWN_WORKER = 0x052C; // 一个未公开的神秘消息
|
public const int WM_SPAWN_WORKER = 0x052C; // 一个未公开的神秘消息
|
||||||
|
|
||||||
@@ -72,6 +122,8 @@ namespace SpineViewer.Natives
|
|||||||
public const int SW_RESTORE = 9;
|
public const int SW_RESTORE = 9;
|
||||||
public const int SW_SHOWDEFAULT = 10;
|
public const int SW_SHOWDEFAULT = 10;
|
||||||
|
|
||||||
|
public const uint MONITOR_DEFAULTTONULL = 0;
|
||||||
|
public const uint MONITOR_DEFAULTTOPRIMARY = 1;
|
||||||
public const uint MONITOR_DEFAULTTONEAREST = 2;
|
public const uint MONITOR_DEFAULTTONEAREST = 2;
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
@@ -124,29 +176,25 @@ namespace SpineViewer.Natives
|
|||||||
public string szDevice;
|
public string szDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
|
||||||
public static extern nint GetDC(nint hWnd);
|
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern int ReleaseDC(nint hWnd, nint hDC);
|
public static extern IntPtr GetDC(IntPtr hWnd);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern int SetWindowLong(nint hWnd, int nIndex, int dwNewLong);
|
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern int GetWindowLong(nint hWnd, int nIndex);
|
public static extern bool GetLayeredWindowAttributes(IntPtr hWnd, ref uint crKey, ref byte bAlpha, ref uint dwFlags);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern bool GetLayeredWindowAttributes(nint hWnd, ref uint crKey, ref byte bAlpha, ref uint dwFlags);
|
public static extern bool SetLayeredWindowAttributes(IntPtr hWnd, uint pcrKey, byte pbAlpha, uint pdwFlags);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern bool SetLayeredWindowAttributes(nint hWnd, uint pcrKey, byte pbAlpha, uint pdwFlags);
|
public static extern bool UpdateLayeredWindow(IntPtr hWnd, IntPtr hdcDst, IntPtr pptDst, ref SIZE psize, IntPtr hdcSrc, ref POINT pptSrc, int crKey, ref BLENDFUNCTION pblend, int dwFlags);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern bool UpdateLayeredWindow(nint hWnd, nint hdcDst, nint pptDst, ref SIZE psize, nint hdcSrc, ref POINT pptSrc, int crKey, ref BLENDFUNCTION pblend, int dwFlags);
|
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
|
||||||
public static extern bool SetWindowPos(nint hWnd, nint hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
|
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern uint GetDoubleClickTime();
|
public static extern uint GetDoubleClickTime();
|
||||||
@@ -155,28 +203,34 @@ namespace SpineViewer.Natives
|
|||||||
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
|
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern nint FindWindow(string lpClassName, string lpWindowName);
|
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern nint SendMessageTimeout(nint hWnd, uint Msg, nint wParam, nint lParam, uint fuFlags, uint uTimeout, out nint lpdwResult);
|
public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam, uint fuFlags, uint uTimeout, out IntPtr lpdwResult);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern nint FindWindowEx(nint parentHandle, nint childAfter, string className, string windowTitle);
|
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern nint SetParent(nint hWndChild, nint hWndNewParent);
|
public static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern nint GetParent(nint hWnd);
|
public static extern IntPtr GetParent(IntPtr hWnd);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern nint GetAncestor(nint hWnd, uint gaFlags);
|
public static extern IntPtr GetAncestor(IntPtr hWnd, uint gaFlags);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern nint GetWindow(nint hWnd, uint uCmd);
|
public static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
public static extern bool ShowWindow(nint hWnd, int nCmdShow);
|
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
|
||||||
|
|
||||||
|
[DllImport("User32.dll")]
|
||||||
|
public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
public static extern bool IsIconic(IntPtr hWnd);
|
public static extern bool IsIconic(IntPtr hWnd);
|
||||||
@@ -190,6 +244,12 @@ namespace SpineViewer.Natives
|
|||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFOEX lpmi);
|
private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFOEX lpmi);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
||||||
|
|
||||||
public static TimeSpan GetLastInputElapsedTime()
|
public static TimeSpan GetLastInputElapsedTime()
|
||||||
{
|
{
|
||||||
LASTINPUTINFO lastInputInfo = new();
|
LASTINPUTINFO lastInputInfo = new();
|
||||||
@@ -205,14 +265,59 @@ namespace SpineViewer.Natives
|
|||||||
return TimeSpan.FromMilliseconds(idleTimeMillis);
|
return TimeSpan.FromMilliseconds(idleTimeMillis);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static nint GetWorkerW()
|
public static IntPtr GetWorkerW()
|
||||||
{
|
{
|
||||||
|
// NOTE: Codes borrowed from @rocksdanister/lively
|
||||||
|
|
||||||
var progman = FindWindow("Progman", null);
|
var progman = FindWindow("Progman", null);
|
||||||
if (progman == nint.Zero)
|
if (progman == IntPtr.Zero)
|
||||||
return nint.Zero;
|
return IntPtr.Zero;
|
||||||
nint hWnd = FindWindowEx(progman, 0, "WorkerW", null);
|
|
||||||
Debug.WriteLine($"HWND(Progman.WorkerW): {hWnd:x8}");
|
// Send 0x052C to Progman. This message directs Progman to spawn a
|
||||||
return hWnd;
|
// WorkerW behind the desktop icons. If it is already there, nothing
|
||||||
|
// happens.
|
||||||
|
SendMessageTimeout(progman, WM_SPAWN_WORKER, 0, 0, SMTO_NORMAL, 1000, out _);
|
||||||
|
|
||||||
|
// Spy++ output
|
||||||
|
// .....
|
||||||
|
// 0x00010190 "" WorkerW
|
||||||
|
// ...
|
||||||
|
// 0x000100EE "" SHELLDLL_DefView
|
||||||
|
// 0x000100F0 "FolderView" SysListView32
|
||||||
|
// 0x00100B8A "" WorkerW <-- This is the WorkerW instance we are after!
|
||||||
|
// 0x000100EC "Program Manager" Progman
|
||||||
|
var workerw = IntPtr.Zero;
|
||||||
|
|
||||||
|
// We enumerate all Windows, until we find one, that has the SHELLDLL_DefView
|
||||||
|
// as a child.
|
||||||
|
// If we found that window, we take its next sibling and assign it to workerw.
|
||||||
|
EnumWindows(new EnumWindowsProc((tophandle, topparamhandle) =>
|
||||||
|
{
|
||||||
|
IntPtr p = FindWindowEx(tophandle, IntPtr.Zero, "SHELLDLL_DefView", null);
|
||||||
|
|
||||||
|
if (p != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
// Gets the WorkerW Window after the current one.
|
||||||
|
workerw = FindWindowEx(IntPtr.Zero, tophandle, "WorkerW", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}), IntPtr.Zero);
|
||||||
|
|
||||||
|
// Some Windows 11 builds have a different Progman window layout.
|
||||||
|
// If the above code failed to find WorkerW, we should try this.
|
||||||
|
// Spy++ output
|
||||||
|
// 0x000100EC "Program Manager" Progman
|
||||||
|
// 0x000100EE "" SHELLDLL_DefView
|
||||||
|
// 0x000100F0 "FolderView" SysListView32
|
||||||
|
// 0x00100B8A "" WorkerW <-- This is the WorkerW instance we are after!
|
||||||
|
if (workerw == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
workerw = FindWindowEx(progman, IntPtr.Zero, "WorkerW", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.WriteLine($"HWND(WorkerW): {workerw:x8}");
|
||||||
|
return workerw;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool GetScreenResolution(IntPtr hwnd, out uint width, out uint height)
|
public static bool GetScreenResolution(IntPtr hwnd, out uint width, out uint height)
|
||||||
@@ -231,5 +336,22 @@ namespace SpineViewer.Natives
|
|||||||
width = height = 0;
|
width = height = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool GetPrimaryScreenResolution(out uint width, out uint height)
|
||||||
|
{
|
||||||
|
IntPtr hMon = MonitorFromWindow(IntPtr.Zero, MONITOR_DEFAULTTOPRIMARY);
|
||||||
|
|
||||||
|
var mi = new MONITORINFOEX { cbSize = (uint)Marshal.SizeOf<MONITORINFOEX>() };
|
||||||
|
if (GetMonitorInfo(hMon, ref mi))
|
||||||
|
{
|
||||||
|
int widthPx = mi.rcMonitor.Right - mi.rcMonitor.Left;
|
||||||
|
int heightPx = mi.rcMonitor.Bottom - mi.rcMonitor.Top;
|
||||||
|
width = (uint)widthPx;
|
||||||
|
height = (uint)heightPx;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
width = height = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,10 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
{
|
{
|
||||||
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
public MainWindowViewModel(ISFMLRenderer sfmlRenderer)
|
public MainWindowViewModel(ISFMLRenderer sfmlRenderer, ISFMLRenderer wallpaperRenderer)
|
||||||
{
|
{
|
||||||
_sfmlRenderer = sfmlRenderer;
|
_sfmlRenderer = sfmlRenderer;
|
||||||
|
_wallpaperRenderer = wallpaperRenderer;
|
||||||
_explorerListViewModel = new(this);
|
_explorerListViewModel = new(this);
|
||||||
_spineObjectListViewModel = new(this);
|
_spineObjectListViewModel = new(this);
|
||||||
_sfmlRendererViewModel = new(this);
|
_sfmlRendererViewModel = new(this);
|
||||||
@@ -34,6 +35,9 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
public ISFMLRenderer SFMLRenderer => _sfmlRenderer;
|
public ISFMLRenderer SFMLRenderer => _sfmlRenderer;
|
||||||
private readonly ISFMLRenderer _sfmlRenderer;
|
private readonly ISFMLRenderer _sfmlRenderer;
|
||||||
|
|
||||||
|
public ISFMLRenderer WallpaperRenderer => _wallpaperRenderer;
|
||||||
|
private readonly ISFMLRenderer _wallpaperRenderer;
|
||||||
|
|
||||||
public TaskbarItemProgressState ProgressState { get => _progressState; set => SetProperty(ref _progressState, value); }
|
public TaskbarItemProgressState ProgressState { get => _progressState; set => SetProperty(ref _progressState, value); }
|
||||||
private TaskbarItemProgressState _progressState = TaskbarItemProgressState.None;
|
private TaskbarItemProgressState _progressState = TaskbarItemProgressState.None;
|
||||||
|
|
||||||
@@ -133,19 +137,5 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
_spineObjectListViewModel.LoadedSpineObjects = value.LoadedSpineObjects;
|
_spineObjectListViewModel.LoadedSpineObjects = value.LoadedSpineObjects;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 调试命令
|
|
||||||
/// </summary>
|
|
||||||
public RelayCommand Cmd_Debug => _cmd_Debug ??= new(Debug_Execute);
|
|
||||||
private RelayCommand? _cmd_Debug;
|
|
||||||
|
|
||||||
private void Debug_Execute()
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
|
|
||||||
MessagePopupService.Quest("测试一下");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,6 +35,7 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
private readonly MainWindowViewModel _vmMain;
|
private readonly MainWindowViewModel _vmMain;
|
||||||
private readonly ObservableCollectionWithLock<SpineObjectModel> _models;
|
private readonly ObservableCollectionWithLock<SpineObjectModel> _models;
|
||||||
private readonly ISFMLRenderer _renderer;
|
private readonly ISFMLRenderer _renderer;
|
||||||
|
private readonly ISFMLRenderer _wallpaperRenderer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 被选中对象的背景颜色
|
/// 被选中对象的背景颜色
|
||||||
@@ -90,6 +91,7 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
_vmMain = vmMain;
|
_vmMain = vmMain;
|
||||||
_models = _vmMain.SpineObjects;
|
_models = _vmMain.SpineObjects;
|
||||||
_renderer = _vmMain.SFMLRenderer;
|
_renderer = _vmMain.SFMLRenderer;
|
||||||
|
_wallpaperRenderer = _vmMain.WallpaperRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -443,6 +445,7 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
_wallpaperRenderer.SetActive(true);
|
||||||
_renderer.SetActive(true);
|
_renderer.SetActive(true);
|
||||||
|
|
||||||
float delta;
|
float delta;
|
||||||
@@ -461,7 +464,11 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
_forwardDelta = 0;
|
_forwardDelta = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using var v = _renderer.GetView();
|
||||||
|
_wallpaperRenderer.SetView(v);
|
||||||
|
|
||||||
_renderer.Clear(_backgroundColor);
|
_renderer.Clear(_backgroundColor);
|
||||||
|
_wallpaperRenderer.Clear(_backgroundColor);
|
||||||
|
|
||||||
// 渲染背景
|
// 渲染背景
|
||||||
lock (_bgLock)
|
lock (_bgLock)
|
||||||
@@ -492,6 +499,7 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
bg.Position = view.Center;
|
bg.Position = view.Center;
|
||||||
bg.Rotation = view.Rotation;
|
bg.Rotation = view.Rotation;
|
||||||
_renderer.Draw(bg);
|
_renderer.Draw(bg);
|
||||||
|
_wallpaperRenderer.Draw(bg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -531,10 +539,12 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
sp.EnableDebug = true;
|
sp.EnableDebug = true;
|
||||||
_renderer.Draw(sp);
|
_renderer.Draw(sp);
|
||||||
sp.EnableDebug = false;
|
sp.EnableDebug = false;
|
||||||
|
_wallpaperRenderer.Draw(sp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderer.Display();
|
_renderer.Display();
|
||||||
|
_wallpaperRenderer.Display();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -546,6 +556,7 @@ namespace SpineViewer.ViewModels.MainWindow
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_renderer.SetActive(false);
|
_renderer.SetActive(false);
|
||||||
|
_wallpaperRenderer.SetActive(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
<MenuItem Header="{DynamicResource Str_Diagnostics}" Command="{Binding Cmd_ShowDiagnosticsDialog}"/>
|
<MenuItem Header="{DynamicResource Str_Diagnostics}" Command="{Binding Cmd_ShowDiagnosticsDialog}"/>
|
||||||
<Separator/>
|
<Separator/>
|
||||||
<MenuItem Header="{DynamicResource Str_Abount}" Command="{Binding Cmd_ShowAboutDialog}"/>
|
<MenuItem Header="{DynamicResource Str_Abount}" Command="{Binding Cmd_ShowAboutDialog}"/>
|
||||||
<MenuItem Header="{DynamicResource Str_Debug}" Command="{Binding Cmd_Debug}"/>
|
<MenuItem Header="{DynamicResource Str_Debug}" Click="DebugMenuItem_Click"/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<!--<MenuItem Header="{DynamicResource Str_Experiment}"/>-->
|
<!--<MenuItem Header="{DynamicResource Str_Experiment}"/>-->
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using Microsoft.Win32;
|
using NLog;
|
||||||
using NLog;
|
|
||||||
using NLog.Layouts;
|
using NLog.Layouts;
|
||||||
using NLog.Targets;
|
using NLog.Targets;
|
||||||
|
using SFMLRenderer;
|
||||||
using Spine;
|
using Spine;
|
||||||
using SpineViewer.Models;
|
using SpineViewer.Models;
|
||||||
using SpineViewer.Natives;
|
using SpineViewer.Natives;
|
||||||
@@ -35,17 +35,24 @@ public partial class MainWindow : Window
|
|||||||
public static readonly string LastStateFilePath = Path.Combine(Path.GetDirectoryName(Environment.ProcessPath), "laststate.json");
|
public static readonly string LastStateFilePath = Path.Combine(Path.GetDirectoryName(Environment.ProcessPath), "laststate.json");
|
||||||
|
|
||||||
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
private ListViewItem? _listViewDragSourceItem = null;
|
private ListViewItem? _listViewDragSourceItem = null;
|
||||||
private Point _listViewDragSourcePoint;
|
private Point _listViewDragSourcePoint;
|
||||||
|
|
||||||
|
private readonly SFMLRenderWindow _wallpaperRenderWindow;
|
||||||
private readonly MainWindowViewModel _vm;
|
private readonly MainWindowViewModel _vm;
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
InitializeLogConfiguration();
|
InitializeLogConfiguration();
|
||||||
DataContext = _vm = new(_renderPanel);
|
|
||||||
_notifyIcon.Text = _vm.Title; // XXX: hc 的 NotifyIcon 的 Text 似乎没法双向绑定
|
_wallpaperRenderWindow = new(new(500, 500), "SpineViewerWallpaper", SFML.Window.Styles.None);
|
||||||
|
_wallpaperRenderWindow.SetVisible(false);
|
||||||
|
DataContext = _vm = new(_renderPanel, _wallpaperRenderWindow);
|
||||||
|
|
||||||
|
// XXX: hc 的 NotifyIcon 的 Text 似乎没法双向绑定
|
||||||
|
_notifyIcon.Text = _vm.Title;
|
||||||
|
|
||||||
_vm.SpineObjectListViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging;
|
_vm.SpineObjectListViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging;
|
||||||
_vm.SFMLRendererViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging;
|
_vm.SFMLRendererViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging;
|
||||||
@@ -600,4 +607,33 @@ public partial class MainWindow : Window
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
private void DebugMenuItem_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
var www = _wallpaperRenderWindow;
|
||||||
|
User32.GetPrimaryScreenResolution(out var sw, out var sh);
|
||||||
|
www.Position = new(0, 0);
|
||||||
|
www.Size = new(sw, sh);
|
||||||
|
|
||||||
|
var handle = www.SystemHandle;
|
||||||
|
Debug.WriteLine($"Handle: {handle:x8}");
|
||||||
|
|
||||||
|
var style = User32.GetWindowLong(handle, User32.GWL_STYLE) | User32.WS_POPUP;
|
||||||
|
var exStyle = User32.GetWindowLong(handle, User32.GWL_EXSTYLE) | User32.WS_EX_LAYERED | User32.WS_EX_TOOLWINDOW | User32.WS_EX_TOPMOST;
|
||||||
|
User32.SetWindowLong(handle, User32.GWL_STYLE, style);
|
||||||
|
User32.SetWindowLong(handle, User32.GWL_EXSTYLE, exStyle);
|
||||||
|
User32.SetLayeredWindowAttributes(handle, 0, 200, User32.LWA_ALPHA);
|
||||||
|
|
||||||
|
var workerw = User32.GetWorkerW();
|
||||||
|
var res = User32.SetParent(handle, workerw);
|
||||||
|
Debug.WriteLine($"SetParent: {res:x8}");
|
||||||
|
|
||||||
|
User32.SetLayeredWindowAttributes(handle, 0, 255, User32.LWA_ALPHA);
|
||||||
|
var s = www.Size;
|
||||||
|
www.Size = new(s.X + 1, s.Y + 1);
|
||||||
|
www.Size = s;
|
||||||
|
www.SetVisible(true);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user