Implement mouse capture and cursor

This commit is contained in:
Magnus Norddahl 2024-01-03 03:41:41 +01:00 committed by Christoph Oelckers
parent b463c8e656
commit 9381813eb5
7 changed files with 98 additions and 1 deletions

View file

@ -177,6 +177,8 @@ private:
Widget* CaptureWidget = nullptr;
Widget* HoverWidget = nullptr;
StandardCursor CurrentCursor = StandardCursor::arrow;
Widget(const Widget&) = delete;
Widget& operator=(const Widget&) = delete;

View file

@ -162,9 +162,13 @@ public:
virtual void ShowCursor(bool enable) = 0;
virtual void LockCursor() = 0;
virtual void UnlockCursor() = 0;
virtual void CaptureMouse() = 0;
virtual void ReleaseMouseCapture() = 0;
virtual void Update() = 0;
virtual bool GetKeyState(EInputKey key) = 0;
virtual void SetCursor(StandardCursor cursor) = 0;
virtual Rect GetWindowFrame() const = 0;
virtual Size GetClientSize() const = 0;
virtual int GetPixelWidth() const = 0;

View file

@ -367,14 +367,38 @@ void Widget::UnlockCursor()
void Widget::SetCursor(StandardCursor cursor)
{
if (CurrentCursor != cursor)
{
CurrentCursor = cursor;
if (HoverWidget == this || CaptureWidget == this)
{
Widget* w = Window();
if (w)
{
w->DispWindow->SetCursor(CurrentCursor);
}
}
}
}
void Widget::CaptureMouse()
{
Widget* w = Window();
if (w && w->CaptureWidget != this)
{
w->CaptureWidget = this;
w->DispWindow->CaptureMouse();
}
}
void Widget::ReleaseMouseCapture()
{
Widget* w = Window();
if (w && w->CaptureWidget != nullptr)
{
w->CaptureWidget = nullptr;
w->DispWindow->ReleaseMouseCapture();
}
}
std::string Widget::GetClipboardText()
@ -487,6 +511,7 @@ void Widget::OnWindowMouseMove(const Point& pos)
{
if (CaptureWidget)
{
DispWindow->SetCursor(CaptureWidget->CurrentCursor);
CaptureWidget->OnMouseMove(CaptureWidget->MapFrom(this, pos));
}
else
@ -502,6 +527,7 @@ void Widget::OnWindowMouseMove(const Point& pos)
HoverWidget = widget;
}
DispWindow->SetCursor(widget->CurrentCursor);
widget->OnMouseMove(widget->MapFrom(this, pos));
}
}

View file

@ -132,6 +132,18 @@ void SDL2DisplayWindow::UnlockCursor()
SDL_ShowCursor(1);
}
void SDL2DisplayWindow::CaptureMouse()
{
}
void SDL2DisplayWindow::ReleaseMouseCapture()
{
}
void SDL2DisplayWindow::SetCursor(StandardCursor cursor)
{
}
void SDL2DisplayWindow::Update()
{
SDL_Event event = {};

View file

@ -24,8 +24,11 @@ public:
void ShowCursor(bool enable) override;
void LockCursor() override;
void UnlockCursor() override;
void CaptureMouse() override;
void ReleaseMouseCapture() override;
void Update() override;
bool GetKeyState(EInputKey key) override;
void SetCursor(StandardCursor cursor) override;
Rect GetWindowFrame() const override;
Size GetClientSize() const override;

View file

@ -209,6 +209,16 @@ void Win32Window::UnlockCursor()
}
}
void Win32Window::CaptureMouse()
{
SetCapture(WindowHandle);
}
void Win32Window::ReleaseMouseCapture()
{
ReleaseCapture();
}
void Win32Window::Update()
{
InvalidateRect(WindowHandle, nullptr, FALSE);
@ -219,6 +229,15 @@ bool Win32Window::GetKeyState(EInputKey key)
return ::GetKeyState((int)key) & 0x8000; // High bit (0x8000) means key is down, Low bit (0x0001) means key is sticky on (like Caps Lock, Num Lock, etc.)
}
void Win32Window::SetCursor(StandardCursor cursor)
{
if (cursor != CurrentCursor)
{
CurrentCursor = cursor;
UpdateCursor();
}
}
Rect Win32Window::GetWindowFrame() const
{
RECT box = {};
@ -411,7 +430,7 @@ LRESULT Win32Window::OnWindowMessage(UINT msg, WPARAM wparam, LPARAM lparam)
}
else
{
SetCursor((HCURSOR)LoadImage(0, IDC_ARROW, IMAGE_CURSOR, LR_DEFAULTSIZE, LR_DEFAULTSIZE, LR_SHARED));
UpdateCursor();
}
WindowHost->OnWindowMouseMove(GetLParamPos(lparam));
@ -511,6 +530,30 @@ LRESULT Win32Window::OnWindowMessage(UINT msg, WPARAM wparam, LPARAM lparam)
return DefWindowProc(WindowHandle, msg, wparam, lparam);
}
void Win32Window::UpdateCursor()
{
LPCWSTR cursor = IDC_ARROW;
switch (CurrentCursor)
{
case StandardCursor::arrow: cursor = IDC_ARROW; break;
case StandardCursor::appstarting: cursor = IDC_APPSTARTING; break;
case StandardCursor::cross: cursor = IDC_CROSS; break;
case StandardCursor::hand: cursor = IDC_HAND; break;
case StandardCursor::ibeam: cursor = IDC_IBEAM; break;
case StandardCursor::no: cursor = IDC_NO; break;
case StandardCursor::size_all: cursor = IDC_SIZEALL; break;
case StandardCursor::size_nesw: cursor = IDC_SIZENESW; break;
case StandardCursor::size_ns: cursor = IDC_SIZENS; break;
case StandardCursor::size_nwse: cursor = IDC_SIZENWSE; break;
case StandardCursor::size_we: cursor = IDC_SIZEWE; break;
case StandardCursor::uparrow: cursor = IDC_UPARROW; break;
case StandardCursor::wait: cursor = IDC_WAIT; break;
default: break;
}
::SetCursor((HCURSOR)LoadImage(0, cursor, IMAGE_CURSOR, LR_DEFAULTSIZE, LR_DEFAULTSIZE, LR_SHARED));
}
Point Win32Window::GetLParamPos(LPARAM lparam) const
{
double dpiscale = GetDpiScale();

View file

@ -30,9 +30,14 @@ public:
void ShowCursor(bool enable) override;
void LockCursor() override;
void UnlockCursor() override;
void CaptureMouse() override;
void ReleaseMouseCapture() override;
void Update() override;
bool GetKeyState(EInputKey key) override;
void SetCursor(StandardCursor cursor) override;
void UpdateCursor();
Rect GetWindowFrame() const override;
Size GetClientSize() const override;
int GetPixelWidth() const override;
@ -76,4 +81,6 @@ public:
POINT MouseLockPos = {};
HDC PaintDC = 0;
StandardCursor CurrentCursor = StandardCursor::arrow;
};