mirror of
https://git.citron-emu.org/citron/emulator
synced 2025-12-22 20:03:42 +00:00
feat: Add mouse wheel support for game input passthrough
- Implement mouse wheel event handling in SDL2 backend (emu_window_sdl2) - Add wheel event routing from GRenderWindow to input subsystem - Add debugging logs to trace mouse wheel events through input chain - Support mouse wheel input for mods like Ultracam when games are running (WIP) Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: 2025 citron Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -732,6 +733,7 @@ void GRenderWindow::ConstrainMouse() {
|
|||||||
void GRenderWindow::wheelEvent(QWheelEvent* event) {
|
void GRenderWindow::wheelEvent(QWheelEvent* event) {
|
||||||
const int x = event->angleDelta().x();
|
const int x = event->angleDelta().x();
|
||||||
const int y = event->angleDelta().y();
|
const int y = event->angleDelta().y();
|
||||||
|
LOG_DEBUG(Frontend, "GRenderWindow wheel event: x={}, y={}", x, y);
|
||||||
input_subsystem->GetMouse()->MouseWheelChange(x, y);
|
input_subsystem->GetMouse()->MouseWheelChange(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: 2025 citron Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
@@ -77,6 +78,11 @@ void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
|
|||||||
input_subsystem->GetMouse()->TouchMove(touch_x, touch_y);
|
input_subsystem->GetMouse()->TouchMove(touch_x, touch_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmuWindow_SDL2::OnMouseWheel(s32 x, s32 y) {
|
||||||
|
input_subsystem->GetMouse()->MouseWheelChange(x, y);
|
||||||
|
LOG_DEBUG(Frontend, "SDL2 Mouse wheel event: x={}, y={}", x, y);
|
||||||
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnFingerDown(float x, float y, std::size_t id) {
|
void EmuWindow_SDL2::OnFingerDown(float x, float y, std::size_t id) {
|
||||||
input_subsystem->GetTouchScreen()->TouchPressed(x, y, id);
|
input_subsystem->GetTouchScreen()->TouchPressed(x, y, id);
|
||||||
}
|
}
|
||||||
@@ -202,6 +208,9 @@ void EmuWindow_SDL2::WaitEvent() {
|
|||||||
OnMouseButton(event.button.button, event.button.state, event.button.x, event.button.y);
|
OnMouseButton(event.button.button, event.button.state, event.button.x, event.button.y);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SDL_MOUSEWHEEL:
|
||||||
|
OnMouseWheel(event.wheel.x, event.wheel.y);
|
||||||
|
break;
|
||||||
case SDL_FINGERDOWN:
|
case SDL_FINGERDOWN:
|
||||||
OnFingerDown(event.tfinger.x, event.tfinger.y,
|
OnFingerDown(event.tfinger.x, event.tfinger.y,
|
||||||
static_cast<std::size_t>(event.tfinger.touchId));
|
static_cast<std::size_t>(event.tfinger.touchId));
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: 2025 citron Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -52,6 +53,9 @@ protected:
|
|||||||
/// Called by WaitEvent when the mouse moves.
|
/// Called by WaitEvent when the mouse moves.
|
||||||
void OnMouseMotion(s32 x, s32 y);
|
void OnMouseMotion(s32 x, s32 y);
|
||||||
|
|
||||||
|
/// Called by WaitEvent when the mouse wheel is scrolled
|
||||||
|
void OnMouseWheel(s32 x, s32 y);
|
||||||
|
|
||||||
/// Called by WaitEvent when a finger starts touching the touchscreen
|
/// Called by WaitEvent when a finger starts touching the touchscreen
|
||||||
void OnFingerDown(float x, float y, std::size_t id);
|
void OnFingerDown(float x, float y, std::size_t id);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -374,6 +375,7 @@ void EmulatedDevices::SetMouseWheel(const Common::Input::CallbackStatus& callbac
|
|||||||
const auto analog_value = TransformToAnalog(callback);
|
const auto analog_value = TransformToAnalog(callback);
|
||||||
|
|
||||||
device_status.mouse_wheel_values[index] = analog_value;
|
device_status.mouse_wheel_values[index] = analog_value;
|
||||||
|
LOG_DEBUG(Input, "EmulatedDevices::SetMouseWheel: index={}, value={}", index, analog_value.value);
|
||||||
|
|
||||||
if (is_configuring) {
|
if (is_configuring) {
|
||||||
device_status.mouse_wheel_state = {};
|
device_status.mouse_wheel_state = {};
|
||||||
@@ -455,6 +457,11 @@ AnalogStickState EmulatedDevices::GetMouseWheel() const {
|
|||||||
return device_status.mouse_wheel_state;
|
return device_status.mouse_wheel_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmulatedDevices::ResetMouseWheel() {
|
||||||
|
std::scoped_lock lock{mutex};
|
||||||
|
device_status.mouse_wheel_state = {};
|
||||||
|
}
|
||||||
|
|
||||||
void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
|
void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
|
||||||
std::scoped_lock lock{callback_mutex};
|
std::scoped_lock lock{callback_mutex};
|
||||||
for (const auto& poller_pair : callback_list) {
|
for (const auto& poller_pair : callback_list) {
|
||||||
|
|||||||
@@ -135,6 +135,9 @@ public:
|
|||||||
/// Returns the latest mouse wheel change
|
/// Returns the latest mouse wheel change
|
||||||
AnalogStickState GetMouseWheel() const;
|
AnalogStickState GetMouseWheel() const;
|
||||||
|
|
||||||
|
/// Resets the mouse wheel state (should be called each frame)
|
||||||
|
void ResetMouseWheel();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a callback to the list of events
|
* Adds a callback to the list of events
|
||||||
* @param update_callback InterfaceUpdateCallback that will be triggered
|
* @param update_callback InterfaceUpdateCallback that will be triggered
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
@@ -55,6 +56,9 @@ void DebugMouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
|||||||
next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y;
|
next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y;
|
||||||
|
|
||||||
last_mouse_wheel_state = mouse_wheel_state;
|
last_mouse_wheel_state = mouse_wheel_state;
|
||||||
|
|
||||||
|
// Reset mouse wheel state after reading to ensure delta values work correctly
|
||||||
|
emulated_devices->ResetMouseWheel();
|
||||||
next_state.button = mouse_button_state;
|
next_state.button = mouse_button_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
|
|||||||
next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y;
|
next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y;
|
||||||
|
|
||||||
last_mouse_wheel_state = mouse_wheel_state;
|
last_mouse_wheel_state = mouse_wheel_state;
|
||||||
|
|
||||||
|
// Reset mouse wheel state after reading to ensure delta values work correctly
|
||||||
|
emulated_devices->ResetMouseWheel();
|
||||||
next_state.button = mouse_button_state;
|
next_state.button = mouse_button_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@@ -235,6 +236,7 @@ void Mouse::MouseWheelChange(int x, int y) {
|
|||||||
wheel_position.x += x;
|
wheel_position.x += x;
|
||||||
wheel_position.y += y;
|
wheel_position.y += y;
|
||||||
last_motion_change.z += static_cast<f32>(y);
|
last_motion_change.z += static_cast<f32>(y);
|
||||||
|
LOG_DEBUG(Input, "Mouse wheel change: x={}, y={}, wheel_pos=({}, {})", x, y, wheel_position.x, wheel_position.y);
|
||||||
SetAxis(identifier, wheel_axis_x, static_cast<f32>(wheel_position.x));
|
SetAxis(identifier, wheel_axis_x, static_cast<f32>(wheel_position.x));
|
||||||
SetAxis(identifier, wheel_axis_y, static_cast<f32>(wheel_position.y));
|
SetAxis(identifier, wheel_axis_y, static_cast<f32>(wheel_position.y));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user