mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Better WindowClass handling, Added Clipboard
This commit is contained in:
@@ -4,7 +4,6 @@ namespace GlitchyEngine.Events
|
||||
{
|
||||
public class MouseMovedEvent : Event, IEvent
|
||||
{
|
||||
private Window _window;
|
||||
private int32 _mouseX, _mouseY;
|
||||
|
||||
public override EventType EventType => .MouseMoved;
|
||||
@@ -15,14 +14,11 @@ namespace GlitchyEngine.Events
|
||||
|
||||
public static EventType StaticType => .MouseMoved;
|
||||
|
||||
public Window Window => _window;
|
||||
|
||||
public int32 PositionX => _mouseX;
|
||||
public int32 PositionY => _mouseY;
|
||||
|
||||
public this(Window window, int32 x, int32 y)
|
||||
public this(int32 x, int32 y)
|
||||
{
|
||||
_window = window;
|
||||
_mouseX = x;
|
||||
_mouseY = y;
|
||||
}
|
||||
@@ -99,18 +95,14 @@ namespace GlitchyEngine.Events
|
||||
|
||||
public abstract class MouseButtonEvent : Event
|
||||
{
|
||||
protected Window _window;
|
||||
protected MouseButton _mouseButton;
|
||||
|
||||
public override EventCategory Category => .Input | .Mouse;
|
||||
|
||||
public Window Window => _window;
|
||||
|
||||
public MouseButton MouseButton => _mouseButton;
|
||||
|
||||
protected this(Window window, MouseButton mouseButton)
|
||||
protected this(MouseButton mouseButton)
|
||||
{
|
||||
_window = window;
|
||||
_mouseButton = mouseButton;
|
||||
}
|
||||
}
|
||||
@@ -123,7 +115,7 @@ namespace GlitchyEngine.Events
|
||||
|
||||
public static EventType StaticType => .MouseButtonPressed;
|
||||
|
||||
public this(Window window, MouseButton mouseButton) : base(window, mouseButton) { }
|
||||
public this(MouseButton mouseButton) : base(mouseButton) { }
|
||||
|
||||
public override void ToString(String strBuffer)
|
||||
{
|
||||
@@ -140,7 +132,7 @@ namespace GlitchyEngine.Events
|
||||
|
||||
public static EventType StaticType => .MouseButtonReleased;
|
||||
|
||||
public this(Window window, MouseButton mouseButton) : base(window, mouseButton) { }
|
||||
public this(MouseButton mouseButton) : base(mouseButton) { }
|
||||
|
||||
public override void ToString(String strBuffer)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
#if BF_PLATFORM_WINDOWS
|
||||
using System;
|
||||
using DirectX.Common;
|
||||
using System.Text;
|
||||
|
||||
using static System.Windows;
|
||||
|
||||
namespace GlitchyEngine.System;
|
||||
|
||||
extension Clipboard
|
||||
{
|
||||
[CLink, CallingConvention(.Stdcall)]
|
||||
private static extern IntBool OpenClipboard(HWnd hWndNewOwner);
|
||||
[CLink, CallingConvention(.Stdcall)]
|
||||
private static extern IntBool CloseClipboard();
|
||||
[CLink, CallingConvention(.Stdcall)]
|
||||
private static extern IntBool EmptyClipboard();
|
||||
|
||||
[AllowDuplicates]
|
||||
private enum ClipboardFormat : uint32
|
||||
{
|
||||
Bitmap = 2,
|
||||
Dib = 8,
|
||||
DibV5 = 17,
|
||||
Dif = 5,
|
||||
DspBitmap = 0,
|
||||
Dspenhmetafile = 0,
|
||||
DspMetaFilepict = 0,
|
||||
DspText = 0,
|
||||
Enhmetafile = 14,
|
||||
Gdiobjfirst = 0,
|
||||
Gdiobjlast = 0,
|
||||
Hdrop = 15,
|
||||
Locale = 16,
|
||||
Metafilepict = 3,
|
||||
Oemtext = 7,
|
||||
Ownerdisplay = 0,
|
||||
Palette = 9,
|
||||
Pendata = 10,
|
||||
Privatefirst = 0,
|
||||
Privatelast = 0,
|
||||
Riff = 11,
|
||||
Sylk = 4,
|
||||
Text = 1,
|
||||
Tiff = 6,
|
||||
UnicodeText = 13,
|
||||
Wave = 12
|
||||
}
|
||||
|
||||
[CLink, CallingConvention(.Stdcall)]
|
||||
private static extern Handle GetClipboardData(ClipboardFormat format);
|
||||
[CLink, CallingConvention(.Stdcall)]
|
||||
private static extern Handle SetClipboardData(ClipboardFormat format, Handle memory);
|
||||
|
||||
[CLink, CallingConvention(.Stdcall)]
|
||||
private static extern void* GlobalLock(Handle memory);
|
||||
[CLink, CallingConvention(.Stdcall)]
|
||||
private static extern IntBool GlobalUnlock(Handle memory);
|
||||
|
||||
[AllowDuplicates]
|
||||
private enum GlobalMemoryFlags : uint32
|
||||
{
|
||||
Fixed = 0x0000,
|
||||
Moveable = 0x0002,
|
||||
ZeroInit = 0x0040,
|
||||
/// Combines Fixed and ZeroInit
|
||||
GPTR = 0x0040,
|
||||
/// Combines Moveable and ZeroInit
|
||||
GHND = 0x0042
|
||||
}
|
||||
|
||||
[CLink, CallingConvention(.Stdcall)]
|
||||
private static extern Handle GlobalAlloc(GlobalMemoryFlags uFlags, int dwBytes);
|
||||
[CLink, CallingConvention(.Stdcall)]
|
||||
private static extern Handle GlobalFree(Handle memory);
|
||||
|
||||
public static mixin TryLogging(IntBool result)
|
||||
{
|
||||
if (!result)
|
||||
{
|
||||
HResult hresult = HResult.FromWin32((uint32)GetLastError());
|
||||
Log.EngineLogger.Error($"{hresult.Underlying}: {hresult}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public static mixin TryLoggingSilent(IntBool result)
|
||||
{
|
||||
if (!result)
|
||||
{
|
||||
HResult hresult = HResult.FromWin32((uint32)GetLastError());
|
||||
Log.EngineLogger.Error($"{hresult.Underlying}: {hresult}");
|
||||
}
|
||||
}
|
||||
|
||||
public override static void Clear()
|
||||
{
|
||||
TryLogging!(OpenClipboard(0));
|
||||
TryLogging!(EmptyClipboard());
|
||||
TryLogging!(CloseClipboard());
|
||||
}
|
||||
|
||||
public override static void Read(String outBuffer)
|
||||
{
|
||||
TryLogging!(OpenClipboard(0));
|
||||
|
||||
do
|
||||
{
|
||||
Handle handle = GetClipboardData(.UnicodeText);
|
||||
|
||||
if (handle == 0)
|
||||
break;
|
||||
|
||||
char16* clipboardData = (char16*)GlobalLock(handle);
|
||||
|
||||
if (clipboardData != null)
|
||||
{
|
||||
outBuffer.Append(clipboardData);
|
||||
|
||||
TryLoggingSilent!(GlobalUnlock(handle));
|
||||
}
|
||||
else
|
||||
{
|
||||
HResult hresult = HResult.FromWin32((uint32)GetLastError());
|
||||
Log.EngineLogger.Error($"{hresult.Underlying}: {hresult}");
|
||||
}
|
||||
}
|
||||
|
||||
TryLogging!(CloseClipboard());
|
||||
}
|
||||
|
||||
public override static void Set(StringView text)
|
||||
{
|
||||
TryLogging!(OpenClipboard(0));
|
||||
|
||||
do
|
||||
{
|
||||
char16* nativeTextPtr = text.ToScopedNativeWChar!();
|
||||
Span<char16> nativeText = .(nativeTextPtr, UTF16.CStrLen(nativeTextPtr) + 1);
|
||||
|
||||
Handle handle = GlobalAlloc(.Moveable, sizeof(char16) * nativeText.Length);
|
||||
|
||||
if (handle == 0)
|
||||
break;
|
||||
|
||||
char16* clipboardDataPtr = (char16*)GlobalLock(handle);
|
||||
Span<char16> clipboardData = .(clipboardDataPtr, nativeText.Length);
|
||||
|
||||
if (clipboardDataPtr == null)
|
||||
{
|
||||
HResult hresult = HResult.FromWin32((uint32)GetLastError());
|
||||
Log.EngineLogger.Error($"{hresult.Underlying}: {hresult}");
|
||||
break;
|
||||
}
|
||||
|
||||
nativeText.CopyTo(clipboardData);
|
||||
TryLoggingSilent!(GlobalUnlock(handle));
|
||||
|
||||
TryLoggingSilent!(EmptyClipboard());
|
||||
|
||||
if (SetClipboardData(.UnicodeText, handle) == 0)
|
||||
{
|
||||
HResult hresult = HResult.FromWin32((uint32)GetLastError());
|
||||
Log.EngineLogger.Error($"{hresult.Underlying}: {hresult}");
|
||||
|
||||
GlobalFree(handle);
|
||||
}
|
||||
}
|
||||
|
||||
TryLogging!(CloseClipboard());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -21,12 +21,13 @@ namespace GlitchyEngine
|
||||
public extension Window
|
||||
{
|
||||
const String WindowClassName = "GlitchyEngineWindow";
|
||||
static readonly char16[?] WindowClassNameW = WindowClassName.ToConstNativeW();
|
||||
|
||||
private Windows.HInstance _instanceHandle;
|
||||
private static WindowClassExW WindowClass;
|
||||
|
||||
private static Windows.HInstance _instanceHandle;
|
||||
internal Windows.HWnd _windowHandle;
|
||||
|
||||
private WindowClassExW _windowClass;
|
||||
|
||||
private WindowRectangle _clientRect;
|
||||
|
||||
private MinMaxInfo _minMaxInfo;
|
||||
@@ -183,52 +184,65 @@ namespace GlitchyEngine
|
||||
Log.EngineLogger.Error($"Failed to destroy window: Message ({(int)res}): {res}");
|
||||
}
|
||||
|
||||
// TODO manage window classes somehow
|
||||
UnregisterClass(WindowClassName.ToScopedNativeWChar!(), _instanceHandle);
|
||||
|
||||
Application.Instance.Windows.Remove(this);
|
||||
}
|
||||
|
||||
static ~this()
|
||||
{
|
||||
#unwarn
|
||||
UnregisterClass(WindowClass.ClassName, _instanceHandle);
|
||||
}
|
||||
|
||||
[LinkName(.C)]
|
||||
static extern HWnd GetActiveWindow();
|
||||
|
||||
private void CreateWindowClass(StringView iconPath)
|
||||
{
|
||||
_instanceHandle = (.)GetModuleHandleW(null);
|
||||
|
||||
WindowClass = .();
|
||||
WindowClass.Style = .HorizontalRedrawOnChange | .VerticalRedrawOnChange;
|
||||
WindowClass.WindowProcedure = => MessageHandler;
|
||||
WindowClass.HInstance = (.)_instanceHandle;
|
||||
|
||||
if (iconPath.Ptr != null)
|
||||
{
|
||||
Debug.Profiler.ProfileScope!("LoadIcon");
|
||||
|
||||
WindowClass.Icon = LoadImageW(0, iconPath.ToScopedNativeWChar!(), .Icon, 0, 0, .LoadFromFile);
|
||||
}
|
||||
else
|
||||
WindowClass.Icon = 0;
|
||||
|
||||
WindowClass.Cursor = LoadCursorW(0, IDC_ARROW);
|
||||
WindowClass.BackgroundBrush = (HBRUSH)SystemColor.WindowFrame;
|
||||
|
||||
#unwarn
|
||||
WindowClass.ClassName = &WindowClassNameW;
|
||||
|
||||
if (RegisterClassExW(ref WindowClass) == 0)
|
||||
{
|
||||
uint32 lastError = GetLastError();
|
||||
Log.EngineLogger.Error($"Failed to register window class. Message({(int)lastError}): {(HResult)lastError}");
|
||||
Runtime.FatalError("Failed to register window class");
|
||||
}
|
||||
}
|
||||
|
||||
private void Init(WindowDescription desc)
|
||||
{
|
||||
Debug.Profiler.ProfileFunction!();
|
||||
|
||||
Log.EngineLogger.Trace($"Creating window \"{desc.Title}\" ({desc.Width}, {desc.Height})...");
|
||||
|
||||
_instanceHandle = (.)GetModuleHandleW(null);
|
||||
|
||||
_windowClass = .();
|
||||
_windowClass.Style = .HorizontalRedrawOnChange | .VerticalRedrawOnChange;
|
||||
_windowClass.WindowProcedure = => MessageHandler;
|
||||
_windowClass.HInstance = (.)_instanceHandle;
|
||||
|
||||
if (desc.Icon.Ptr != null)
|
||||
if (WindowClass == default)
|
||||
{
|
||||
Debug.Profiler.ProfileScope!("LoadIcon");
|
||||
|
||||
_windowClass.Icon = LoadImageW(0, desc.Icon.ToScopedNativeWChar!(), .Icon, 0, 0, .LoadFromFile);
|
||||
}
|
||||
else
|
||||
_windowClass.Icon = 0;
|
||||
|
||||
_windowClass.Cursor = LoadCursorW(0, IDC_ARROW);
|
||||
_windowClass.BackgroundBrush = (HBRUSH)SystemColor.WindowFrame;
|
||||
_windowClass.ClassName = WindowClassName.ToScopedNativeWChar!();
|
||||
|
||||
if (RegisterClassExW(ref _windowClass) == 0)
|
||||
{
|
||||
uint32 lastError = GetLastError();
|
||||
Log.EngineLogger.Error($"Failed to register window class. Message({(int)lastError}): {(HResult)lastError}");
|
||||
//Runtime.FatalError("Failed to register window class");
|
||||
CreateWindowClass(desc.Icon);
|
||||
}
|
||||
|
||||
{
|
||||
Debug.Profiler.ProfileScope!("CreateWindow");
|
||||
|
||||
_windowHandle = CreateWindowExW(.None, _windowClass.ClassName, desc.Title.ToScopedNativeWChar!(), .WS_OVERLAPPEDWINDOW | .WS_VISIBLE,
|
||||
_windowHandle = CreateWindowExW(.None, WindowClass.ClassName, desc.Title.ToScopedNativeWChar!(), .WS_OVERLAPPEDWINDOW | .WS_VISIBLE,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, desc.Width, desc.Height, 0, 0, (.)_instanceHandle, null);
|
||||
}
|
||||
|
||||
@@ -244,6 +258,8 @@ namespace GlitchyEngine
|
||||
|
||||
// Determine whether or not the window is currently active
|
||||
_isActive = GetActiveWindow() == _windowHandle;
|
||||
|
||||
SetIcon(desc.Icon);
|
||||
}
|
||||
|
||||
private bool _isResizingOrMoving;
|
||||
@@ -252,7 +268,7 @@ namespace GlitchyEngine
|
||||
[CLink]
|
||||
static extern IntBool IsWindowUnicode(HWND whnd);
|
||||
|
||||
public Result<void> SetIcon(StringView filePath)
|
||||
public override Result<void> SetIcon(StringView filePath)
|
||||
{
|
||||
HICON hIcon = LoadImageW(0, filePath.ToScopedNativeWChar!(), .Icon, 0, 0, .LoadFromFile);
|
||||
if (hIcon == 0)
|
||||
@@ -386,34 +402,34 @@ namespace GlitchyEngine
|
||||
// Left mouse button
|
||||
case WM_LBUTTONDOWN:
|
||||
{
|
||||
var event = scope MouseButtonPressedEvent(window, .LeftButton);
|
||||
var event = scope MouseButtonPressedEvent(.LeftButton);
|
||||
window._eventCallback(event);
|
||||
}
|
||||
case WM_LBUTTONUP:
|
||||
{
|
||||
var event = scope MouseButtonReleasedEvent(window, .LeftButton);
|
||||
var event = scope MouseButtonReleasedEvent(.LeftButton);
|
||||
window._eventCallback(event);
|
||||
}
|
||||
// Right mouse button
|
||||
case WM_RBUTTONDOWN:
|
||||
{
|
||||
var event = scope MouseButtonPressedEvent(window, .RightButton);
|
||||
var event = scope MouseButtonPressedEvent(.RightButton);
|
||||
window._eventCallback(event);
|
||||
}
|
||||
case WM_RBUTTONUP:
|
||||
{
|
||||
var event = scope MouseButtonReleasedEvent(window, .RightButton);
|
||||
var event = scope MouseButtonReleasedEvent(.RightButton);
|
||||
window._eventCallback(event);
|
||||
}
|
||||
// Middle mouse button
|
||||
case WM_MBUTTONDOWN:
|
||||
{
|
||||
var event = scope MouseButtonPressedEvent(window, .MiddleButton);
|
||||
var event = scope MouseButtonPressedEvent(.MiddleButton);
|
||||
window._eventCallback(event);
|
||||
}
|
||||
case WM_MBUTTONUP:
|
||||
{
|
||||
var event = scope MouseButtonReleasedEvent(window, .MiddleButton);
|
||||
var event = scope MouseButtonReleasedEvent(.MiddleButton);
|
||||
window._eventCallback(event);
|
||||
}
|
||||
// X button
|
||||
@@ -425,7 +441,7 @@ namespace GlitchyEngine
|
||||
else
|
||||
button = .XButton2;
|
||||
|
||||
var event = scope MouseButtonPressedEvent(window, button);
|
||||
var event = scope MouseButtonPressedEvent(button);
|
||||
window._eventCallback(event);
|
||||
}
|
||||
case WM_XBUTTONUP:
|
||||
@@ -436,7 +452,7 @@ namespace GlitchyEngine
|
||||
else
|
||||
button = .XButton2;
|
||||
|
||||
var event = scope MouseButtonReleasedEvent(window, button);
|
||||
var event = scope MouseButtonReleasedEvent(button);
|
||||
window._eventCallback(event);
|
||||
}
|
||||
// Vertical scrolling
|
||||
@@ -459,10 +475,10 @@ namespace GlitchyEngine
|
||||
{
|
||||
SplitHighAndLowOrder!(lParam, let x, let y);
|
||||
|
||||
var event = scope MouseMovedEvent(window, x, y);
|
||||
var event = scope MouseMovedEvent(x, y);
|
||||
window._eventCallback(event);
|
||||
}
|
||||
case WM_INPUT:
|
||||
/*case WM_INPUT:
|
||||
{
|
||||
uint32 dataSize = ?;
|
||||
GetRawInputData((.)lParam, RID_INPUT, null, &dataSize, sizeof(RAWINPUTHEADER));
|
||||
@@ -483,7 +499,7 @@ namespace GlitchyEngine
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// Todo: DirectInput
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace GlitchyEngine.System;
|
||||
|
||||
class Clipboard
|
||||
{
|
||||
/// Clears the clipboard.
|
||||
public static extern void Clear();
|
||||
|
||||
/// Reads a unicode text from the clipboard.
|
||||
public static extern void Read(String outBuffer);
|
||||
|
||||
/// Sets the content of the clipboard to the given unicode text.
|
||||
public static extern void Set(StringView text);
|
||||
}
|
||||
Reference in New Issue
Block a user