Fix Mouse Button errors, implement MouseWheel events
All checks were successful
Run ReCI Build Test / Explore-Gitea-Actions (push) Successful in 1m42s

This commit is contained in:
2024-12-03 21:24:50 -05:00
parent b75f44f1ee
commit a3adbb6266
9 changed files with 169 additions and 60 deletions

View File

@@ -57,9 +57,9 @@ namespace ReWindow {
class MouseWheelEvent : public MouseEvent
{
public:
int wheel_dt;
int WheelMovement;
MouseWheelEvent() = default;
MouseWheelEvent(int wheel) : MouseEvent(), wheel_dt(wheel) {}
MouseWheelEvent(int wheel) : MouseEvent(), WheelMovement(wheel) {}
};
class MouseButtonDownEvent : public MouseEvent {
@@ -67,14 +67,14 @@ namespace ReWindow {
MouseButton Button;
MouseButtonDownEvent() = default;
MouseButtonDownEvent(MouseButton Button) : MouseEvent() {}
MouseButtonDownEvent(MouseButton button) : MouseEvent(), Button(button) {}
};
class MouseButtonUpEvent : public MouseEvent {
public:
MouseButton Button;
MouseButtonUpEvent() = default;
MouseButtonUpEvent(MouseButton Button) : MouseEvent() {}
MouseButtonUpEvent(MouseButton button) : MouseEvent(), Button(button) {}
};
class WindowResizeRequestEvent : public RWindowEvent

View File

@@ -19,9 +19,9 @@ private:
public:
static std::vector<Key> GetKeyboard();
Key();
Key() = default;
Key(const char* charcode, X11Scancode scancode, WindowsScancode wSc);
const char* CharCode;
std::string Mnemonic;
X11Scancode x11ScanCode;
WindowsScancode winScanCode;
bool operator==(const Key& rhs) const;

View File

@@ -10,13 +10,16 @@
#pragma once
#include <string>
class MouseButton {
public:
MouseButton();
explicit MouseButton(const char* charcode, unsigned int index);
const char* CharCode;
std::string Mnemonic;
unsigned int ButtonIndex;
MouseButton() = default;
explicit MouseButton(const std::string& charcode, unsigned int index);
bool operator == (const MouseButton& mb) const;
bool operator<(const MouseButton& rhs) const;
MouseButton(const MouseButton&) = default;
@@ -25,14 +28,17 @@ public:
namespace MouseButtons
{
static const MouseButton Left {"l", 1};
static const MouseButton Right {"r", 2};
static const MouseButton Middle {"m", 3};
static const MouseButton MWheelUp {"1", 4};
static const MouseButton MWheelDown {"2", 5};
static const MouseButton Mouse4 {"4", 8};
static const MouseButton Mouse5 {"5", 9};
static const MouseButton Unimplemented {"u", 0};
static const MouseButton Left ("L", 1);
static const MouseButton Right ("R", 2);
static const MouseButton Middle ("M", 3);
static const MouseButton Mouse4 ("4", 8);
static const MouseButton Mouse5 ("5", 9);
static const MouseButton Unimplemented ("?", 0);
/// NOTE: IsMouseButtonDown will not return correctly for the mouse-wheel-buttons, because the action is effectively instantaneous.
static const MouseButton MWheelUp ("U", 4);
/// NOTE: IsMouseButtonDown will not return correctly for the mouse-wheel-buttons, because the action is effectively instantaneous.
static const MouseButton MWheelDown ("D", 5);
}
MouseButton GetMouseButtonFromXButton(unsigned int button);

View File

@@ -10,6 +10,7 @@
#include <rewindow/types/gamepadbutton.h>
#include <J3ML/LinearAlgebra.hpp>
#include <rewindow/types/WindowEvents.hpp>
#include <format>
enum class RWindowFlags: uint8_t {
@@ -29,8 +30,6 @@ enum class RenderingAPI: uint8_t {
VULKAN = 1,
};
namespace ReWindow
{
using J3ML::LinearAlgebra::Vector2;
@@ -47,8 +46,57 @@ namespace ReWindow
class MouseState {
public:
std::map<MouseButton, bool> PressedBtns;
Vector2 Pos;
struct
{
bool LMB = false;
bool RMB = false;
bool MMB = false;
bool SideButton1 = false;
bool SideButton2 = false;
bool MWheelUp = false;
bool MWheelDown = false;
} Buttons;
Vector2 Position;
int Wheel = 0;
[[nodiscard]] bool IsDown(const MouseButton& btn) const
{
if (btn == MouseButtons::Left) return Buttons.LMB;
if (btn == MouseButtons::Right) return Buttons.RMB;
if (btn == MouseButtons::Middle) return Buttons.MMB;
if (btn == MouseButtons::Mouse4) return Buttons.SideButton1;
if (btn == MouseButtons::Mouse5) return Buttons.SideButton2;
//if (btn == MouseButtons::MWheelUp) return Buttons.MWheelUp;
//if (btn == MouseButtons::MWheelDown) return Buttons.MWheelDown;
return false; // Unknown button?
}
void Set(const MouseButton& btn, bool state)
{
if (btn == MouseButtons::Left) Buttons.LMB = state;
if (btn == MouseButtons::Right) Buttons.RMB = state;
if (btn == MouseButtons::Middle) Buttons.MMB = state;
if (btn == MouseButtons::Mouse4) Buttons.SideButton1 = state;
if (btn == MouseButtons::Mouse5) Buttons.SideButton2 = state;
//if (btn == MouseButtons::MWheelUp) Buttons.MWheelUp = state;
//if (btn == MouseButtons::MWheelDown) Buttons.MWheelDown = state;
}
bool& operator[](const MouseButton& btn)
{
if (btn == MouseButtons::Left) return Buttons.LMB;
if (btn == MouseButtons::Right) return Buttons.RMB;
if (btn == MouseButtons::Middle) return Buttons.MMB;
if (btn == MouseButtons::Mouse4) return Buttons.SideButton1;
if (btn == MouseButtons::Mouse5) return Buttons.SideButton2;
//if (btn == MouseButtons::MWheelUp) return Buttons.MWheelUp;
//if (btn == MouseButtons::MWheelDown) return Buttons.MWheelDown;
throw std::runtime_error("Attempted to handle unmapped mouse button");
}
};
/// RWindow is a class implementation of a platform-independent window abstraction.
@@ -111,6 +159,8 @@ namespace ReWindow
/// @see GetAccurateMouseCoordinates().
Vector2 GetMouseCoordinates() const;
int GetMouseWheelPersistent() const { return currentMouse.Wheel;}
/// Sets which rendering API is to be used with this window.
void SetRenderer(RenderingAPI api);
@@ -149,7 +199,7 @@ namespace ReWindow
[[nodiscard]] bool IsKeyDown(Key key) const;
/// Returns whether the given mouse button is currently being pressed.
[[nodiscard]] bool IsMouseButtonDown(MouseButton button) const;
[[nodiscard]] bool IsMouseButtonDown(const MouseButton &button) const;
/// Sets whether or not to make the window fullscreen.
/// @note This is implemented per-OS, and as such, it simply requests the OS to do what we want. No guarantee about follow-through can be given.
@@ -301,6 +351,7 @@ namespace ReWindow
MouseState previousMouse;
RenderingAPI renderer = RenderingAPI::OPENGL;
//Vector2 mouse_coords = {0, 0};
@@ -340,9 +391,9 @@ namespace ReWindow
/// @note This will be invoked **after** the window-open procedure completes.
void processOnOpen();
/// Executes event handlers for mouse press events.
void processMousePress(MouseButton btn);
void processMousePress(const MouseButton& btn);
/// Executes event handlers for mouse release events.
void processMouseRelease(MouseButton btn);
void processMouseRelease(const MouseButton& btn);
/// Executes event handlers for window focus events.
void processFocusIn();
/// Executes event handlers for window unfocus events.

View File

@@ -32,6 +32,28 @@ class MyWindow : public ReWindow::RWindow {
auto pos = GetMouseCoordinates();
//std::cout << pos.x << ", " << pos.y << std::endl;
//if (IsMouseButtonDown(MouseButtons::MWheelUp))
//std::cout << "WheelUp Mouse Button" << std::endl;
//if (IsMouseButtonDown(MouseButtons::MWheelDown))
//std::cout << "WheelDown Mouse Button" << std::endl;
if (IsMouseButtonDown(MouseButtons::Left))
std::cout << "Left Mouse Button" << std::endl;
if (IsMouseButtonDown(MouseButtons::Right))
std::cout << "Right Mouse Button" << std::endl;
if (IsMouseButtonDown(MouseButtons::Middle))
std::cout << "Middle Mouse Button" << std::endl;
if (IsMouseButtonDown(MouseButtons::Mouse4))
std::cout << "Mouse4 Mouse Button" << std::endl;
if (IsMouseButtonDown(MouseButtons::Mouse5))
std::cout << "Mouse5 Mouse Button" << std::endl;
RWindow::OnRefresh(elapsed);
}
@@ -39,6 +61,18 @@ class MyWindow : public ReWindow::RWindow {
std::cout << "resized to " << e.Size.x << ", " << e.Size.y << std::endl;
return true;
}
void OnMouseButtonDown(const ReWindow::MouseButtonDownEvent &e) override
{
std::cout << "Overload Down: " << e.Button.Mnemonic << std::endl;
RWindow::OnMouseButtonDown(e);
}
void OnMouseButtonUp(const ReWindow::MouseButtonUpEvent &e) override
{
std::cout << "Overload Up: " << e.Button.Mnemonic << std::endl;
RWindow::OnMouseButtonUp(e);
}
};
int main() {
@@ -95,14 +129,19 @@ int main() {
window->OnKeyDownEvent += [&] (ReWindow::KeyDownEvent e) {
jlog::Debug(e.key.CharCode);
jlog::Debug(e.key.Mnemonic);
};
window->OnMouseButtonDownEvent += [&] (ReWindow::MouseButtonDownEvent e) {
jlog::Debug(e.Button.CharCode);
jlog::Debug(e.Button.Mnemonic + std::to_string(e.Button.ButtonIndex));
};
window->OnMouseWheelEvent += [&, window] (ReWindow::MouseWheelEvent e)
{
std::cout << window->GetMouseWheelPersistent() << std::endl;
};
while (window->IsAlive()) {
window->PollEvents();
window->ManagedRefresh();

View File

@@ -166,18 +166,34 @@ void RWindow::PollEvents() {
}
if (xev.type == ButtonRelease) {
Logger::Debug(std::format("Recieved event '{}'", "ButtonRelease"));
MouseButton button = GetMouseButtonFromXButton(xev.xbutton.button);
processMouseRelease(button);
// Mouse Wheel fires both the ButtonPress and ButtonRelease instantaneously.
// Therefore, we handle it as a specific MouseWheel event rather than a MouseButton event,
// and only call on ButtonPress, otherwise it will appear to duplicate the mouse wheel scroll.
if (xev.xbutton.button != 4 && xev.xbutton.button != 5) {
MouseButton button = GetMouseButtonFromXButton(xev.xbutton.button);
Logger::Debug(std::format("Recieved event '{}'", "ButtonRelease"));
processMouseRelease(button);
}
}
if (xev.type == ButtonPress) {
MouseButton button = GetMouseButtonFromXButton(xev.xbutton.button);
Logger::Debug(std::format("Window event: MouseButtonPress {}", button.CharCode));
// Mouse Wheel fires both the ButtonPress and ButtonRelease instantaneously.
// Therefore, we handle it as a specific MouseWheel event rather than a MouseButton event,
// and only call on ButtonPress, otherwise it will appear to duplicate the mouse wheel scroll.
if (xev.xbutton.button == 4) {
processMouseWheel(-1);
} else if (xev.xbutton.button == 5) {
processMouseWheel(1);
} else
{
MouseButton button = GetMouseButtonFromXButton(xev.xbutton.button);
processMousePress(button);
Logger::Debug(std::format("Window event: MouseButtonPress {}", button.Mnemonic));
processMousePress(button);
}
}
if (xev.type == Expose)
@@ -213,7 +229,7 @@ void RWindow::PollEvents() {
}
previousKeyboard = currentKeyboard;
previousMouse.PressedBtns = currentMouse.PressedBtns;
previousMouse.Buttons = currentMouse.Buttons;
}

View File

@@ -33,7 +33,7 @@ RWindow::RWindow(const std::string& title, int width, int height, RenderingAPI r
title(title), width(width), height(height), renderer(renderer) {}
Vector2 RWindow::GetMouseCoordinates() const {
return currentMouse.Pos;
return currentMouse.Position;
}
bool RWindow::GetFlag(RWindowFlags flag) const {
@@ -66,9 +66,9 @@ void RWindow::processFocusOut()
OnFocusLostEvent(event);
}
void RWindow::processMousePress(MouseButton btn)
void RWindow::processMousePress(const MouseButton& btn)
{
currentMouse.PressedBtns[btn] = true;
currentMouse.Set(btn, true);
auto eventData = MouseButtonDownEvent(btn);
OnMouseButtonDown(eventData);
OnMouseButtonDownEvent(eventData);
@@ -77,15 +77,15 @@ void RWindow::processMousePress(MouseButton btn)
void RWindow::processMouseMove(Vector2 last_pos, Vector2 new_pos)
{
currentMouse.Pos = new_pos;
currentMouse.Position = new_pos;
auto eventData = MouseMoveEvent(new_pos);
OnMouseMove(eventData);
OnMouseMoveEvent(eventData);
}
void RWindow::processMouseRelease(MouseButton btn)
void RWindow::processMouseRelease(const MouseButton& btn)
{
currentMouse.PressedBtns[btn] = false;
currentMouse.Set(btn, false);
auto eventData = MouseButtonUpEvent(btn);
OnMouseButtonUp(eventData);
OnMouseButtonUpEvent(eventData);
@@ -147,10 +147,9 @@ bool RWindow::IsKeyDown(Key key) const {
return false;
}
bool RWindow::IsMouseButtonDown(MouseButton button) const {
bool RWindow::IsMouseButtonDown(const MouseButton &button) const {
// TODO: Implement MouseButton map
for (const auto& pair : currentMouse.PressedBtns)
return pair.first == button && pair.second;
return currentMouse.IsDown(button);
}
void RWindow::processKeyPress(Key key) {
@@ -188,12 +187,12 @@ void RWindow::Refresh() {
OnRefresh(delta_time);
// Only call once and cache the result.
currentMouse.Pos = GetAccurateMouseCoordinates();
currentMouse.Position = GetAccurateMouseCoordinates();
/// TODO: Implement optional minimum epsilon to trigger a Mouse Update.
if (currentMouse.Pos != previousMouse.Pos) {
processMouseMove(previousMouse.Pos, currentMouse.Pos);
previousMouse.Pos = currentMouse.Pos;
if (currentMouse.Position != previousMouse.Position) {
processMouseMove(previousMouse.Position, currentMouse.Position);
previousMouse.Position = currentMouse.Position;
}
}
@@ -224,9 +223,12 @@ void RWindow::UpdateFrameTiming(float frame_time) {
void RWindow::processMouseWheel(int scrolls)
{
currentMouse.Wheel += scrolls;
auto ev = MouseWheelEvent(scrolls);
OnMouseWheel(ev);
OnMouseWheelEvent(ev);
previousMouse.Wheel = currentMouse.Wheel;
}

View File

@@ -4,26 +4,22 @@
std::vector<Key> Key::GetKeyboard() { return keyboard; }
Key::Key() {
keyboard.push_back(*this);
}
Key::Key(const char* charcode, X11Scancode scancode, WindowsScancode sc)
: CharCode(charcode), x11ScanCode(scancode), winScanCode(sc)
: Mnemonic(charcode), x11ScanCode(scancode), winScanCode(sc)
{
//TODO doing this is what crashes the program.
keyboard.push_back(*this);
}
bool Key::operator==(const Key &rhs) const {
//This is not a good workaround.
return (this->x11ScanCode == rhs.x11ScanCode);
}
bool Key::operator<(const Key &rhs) const {
return (this->CharCode < rhs.CharCode);
return (this->Mnemonic < rhs.Mnemonic);
}

View File

@@ -1,12 +1,11 @@
#include <rewindow/types/mousebutton.h>
#include <string>
#include <X11/X.h>
#include "rewindow/logger/logger.h"
MouseButton::MouseButton() {
}
MouseButton::MouseButton(const char* charcode, unsigned int index) {
this->CharCode = charcode;
MouseButton::MouseButton(const std::string& charcode, unsigned int index) {
this->Mnemonic = charcode;
this->ButtonIndex = index;
}
@@ -15,7 +14,7 @@ bool MouseButton::operator==(const MouseButton &mb) const {
}
bool MouseButton::operator<(const MouseButton &rhs) const {
return (this->CharCode < rhs.CharCode);
return (this->ButtonIndex < rhs.ButtonIndex);
}
@@ -24,8 +23,8 @@ MouseButton GetMouseButtonFromXButton(unsigned int button) {
case 1: return MouseButtons::Left;
case 2: return MouseButtons::Middle;
case 3: return MouseButtons::Right;
case 4: return MouseButtons::MWheelUp;
case 5: return MouseButtons::MWheelDown;
//case 4: return MouseButtons::MWheelUp;
//case 5: return MouseButtons::MWheelDown;
//For *whatever* reason. These aren't in X.h
case 8: return MouseButtons::Mouse4;
case 9: return MouseButtons::Mouse5;