Add experimental mouse API (#126)

* Add experimental mouse API

* Add aurora::core library for aurora::ms

* Add absl::flat_hash_map library for aurora::ms

* Add comment clarifying MS is an aurora extension

* Clear MSStatus::buttons to prevent spurious values

* Minor cleanup for MSRead and MS_BUTTON_* bits

* Switch to Poll -> Read paradigm

* Clear mouse scroll state before polling for events
This commit is contained in:
Phillip Stephens
2026-04-16 12:57:10 -07:00
committed by GitHub
parent aa83f6d915
commit c21a7f75ab
7 changed files with 106 additions and 2 deletions
+1
View File
@@ -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)
+7
View File
@@ -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)
+35
View File
@@ -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
+33
View File
@@ -0,0 +1,33 @@
#include "dolphin/ms.h"
#include <SDL3/SDL_mouse.h>
#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; }
}
+18
View File
@@ -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
+3
View File
@@ -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<Uint32, GameController> g_GameControllers;
void set_mouse_scroll(float scrollX, float scrollY) noexcept;
void get_mouse_scroll(float* scrollX, float* scrollY) noexcept;
} // namespace aurora::input
+9 -2
View File
@@ -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() {