diff --git a/CMakeLists.txt b/CMakeLists.txt index d77ff84..4a48ec3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,7 @@ if (AURORA_ENABLE_GX) include(cmake/aurora_gd.cmake) endif () include(cmake/aurora_pad.cmake) +include(cmake/aurora_ms.cmake) include(cmake/aurora_si.cmake) include(cmake/aurora_main.cmake) include(cmake/aurora_mtx.cmake) diff --git a/cmake/aurora_ms.cmake b/cmake/aurora_ms.cmake new file mode 100644 index 0000000..26fa2f1 --- /dev/null +++ b/cmake/aurora_ms.cmake @@ -0,0 +1,7 @@ +add_library(aurora_ms STATIC lib/dolphin/ms/mouse.cpp) + +add_library(aurora::ms ALIAS aurora_ms) + +target_include_directories(aurora_ms PUBLIC include) +target_link_libraries(aurora_ms PUBLIC aurora::core) +target_link_libraries(aurora_ms PRIVATE absl::flat_hash_map) diff --git a/include/dolphin/ms.h b/include/dolphin/ms.h new file mode 100644 index 0000000..0cd4c55 --- /dev/null +++ b/include/dolphin/ms.h @@ -0,0 +1,35 @@ +// Aurora exclusive API extension +// While the GC and Wii could both technically support mice, they never received official libraries +// This library is a theoretical implementation based loosely on PAD +#ifndef DOLPHIN_MS_H +#define DOLPHIN_MS_H +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MSStatus { + f32 x; + f32 y; + f32 xrel; + f32 yrel; + u32 buttons; + f32 scrollX; + f32 scrollY; +} MSStatus; + +#define MS_BUTTON_LEFT (1 << 0) +#define MS_BUTTON_MIDDLE (1 << 1) +#define MS_BUTTON_RIGHT (1 << 2) +#define MS_BUTTON_X1 (1 << 3) +#define MS_BUTTON_X2 (1 << 4) + +void MSPoll(); +void MSRead(MSStatus* status); + +#ifdef __cplusplus +} +#endif + +#endif // DUSK_MS_H diff --git a/lib/dolphin/ms/mouse.cpp b/lib/dolphin/ms/mouse.cpp new file mode 100644 index 0000000..a5b95f7 --- /dev/null +++ b/lib/dolphin/ms/mouse.cpp @@ -0,0 +1,33 @@ +#include "dolphin/ms.h" +#include + +#include "../../input.hpp" + +extern "C" { +static MSStatus gStatus{}; + +void MSPoll() { + const uint32_t buttons = SDL_GetGlobalMouseState(&gStatus.x, &gStatus.y); + SDL_GetRelativeMouseState(&gStatus.xrel, &gStatus.yrel); + aurora::input::get_mouse_scroll(&gStatus.scrollX, &gStatus.scrollY); + + gStatus.buttons = 0; + if (buttons & SDL_BUTTON_LEFT) { + gStatus.buttons |= MS_BUTTON_LEFT; + } + if (buttons & SDL_BUTTON_MIDDLE) { + gStatus.buttons |= MS_BUTTON_MIDDLE; + } + if (buttons & SDL_BUTTON_RIGHT) { + gStatus.buttons |= MS_BUTTON_RIGHT; + } + if (buttons & SDL_BUTTON_X1) { + gStatus.buttons |= MS_BUTTON_X1; + } + if (buttons & SDL_BUTTON_X2) { + gStatus.buttons |= MS_BUTTON_X2; + } +} + +void MSRead(MSStatus* status) { *status = gStatus; } +} \ No newline at end of file diff --git a/lib/input.cpp b/lib/input.cpp index ae57268..9e46a0a 100644 --- a/lib/input.cpp +++ b/lib/input.cpp @@ -138,4 +138,22 @@ void initialize() noexcept { ASSERT(SDL_Init(SDL_INIT_HAPTIC | SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD), "Failed to initialize SDL subsystems: {}", SDL_GetError()); } + +struct MouseScrollStatus { + float scrollX; + float scrollY; +}; + +static MouseScrollStatus g_MouseStatus; + +void set_mouse_scroll(const float scrollX, const float scrollY) noexcept { + g_MouseStatus.scrollX = scrollX; + g_MouseStatus.scrollY = scrollY; +} + +void get_mouse_scroll(float* scrollX, float* scrollY) noexcept { + *scrollX = g_MouseStatus.scrollX; + *scrollY = g_MouseStatus.scrollY; +} + } // namespace aurora::input diff --git a/lib/input.hpp b/lib/input.hpp index 8af4886..2305262 100644 --- a/lib/input.hpp +++ b/lib/input.hpp @@ -53,4 +53,7 @@ void controller_rumble(uint32_t instance, uint16_t low_freq_intensity, uint16_t uint32_t controller_count() noexcept; void initialize() noexcept; extern absl::flat_hash_map g_GameControllers; + +void set_mouse_scroll(float scrollX, float scrollY) noexcept; +void get_mouse_scroll(float* scrollX, float* scrollY) noexcept; } // namespace aurora::input diff --git a/lib/window.cpp b/lib/window.cpp index 6c92fd2..66bf8a2 100644 --- a/lib/window.cpp +++ b/lib/window.cpp @@ -74,6 +74,8 @@ const AuroraEvent* poll_events() { g_events.clear(); SDL_Event event; + // Clear out the previous scroll values to prevent ghost input + input::set_mouse_scroll(0, 0); while (SDL_PollEvent(&event)) { #ifdef AURORA_ENABLE_GX imgui::process_event(event); @@ -154,6 +156,9 @@ const AuroraEvent* poll_events() { }); break; } + case SDL_EVENT_MOUSE_WHEEL: + input::set_mouse_scroll(event.wheel.x, event.wheel.y); + break; case SDL_EVENT_QUIT: g_events.push_back(AuroraEvent{ .type = AURORA_EXIT, @@ -334,7 +339,8 @@ AuroraWindowSize get_window_size() { int native_fb_w = 0; int native_fb_h = 0; ASSERT(SDL_GetWindowSize(g_window, &width, &height), "Failed to get window size: {}", SDL_GetError()); - ASSERT(SDL_GetWindowSizeInPixels(g_window, &native_fb_w, &native_fb_h), "Failed to get window size in pixels: {}", SDL_GetError()); + ASSERT(SDL_GetWindowSizeInPixels(g_window, &native_fb_w, &native_fb_h), "Failed to get window size in pixels: {}", + SDL_GetError()); int fb_w = native_fb_w; int fb_h = native_fb_h; @@ -385,7 +391,8 @@ void set_window_position(uint32_t x, uint32_t y) { } void center_window() { - TRY_WARN(SDL_SetWindowPosition(g_window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED), "Failed to center window: {}", SDL_GetError()); + TRY_WARN(SDL_SetWindowPosition(g_window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED), + "Failed to center window: {}", SDL_GetError()); } static void push_future_resize_event() {