input_common: Rewrite mouse
This commit is contained in:
parent
5a785ed794
commit
00834b84dd
|
@ -1,6 +1,8 @@
|
||||||
add_library(input_common STATIC
|
add_library(input_common STATIC
|
||||||
drivers/keyboard.cpp
|
drivers/keyboard.cpp
|
||||||
drivers/keyboard.h
|
drivers/keyboard.h
|
||||||
|
drivers/mouse.cpp
|
||||||
|
drivers/mouse.h
|
||||||
helpers/stick_from_buttons.cpp
|
helpers/stick_from_buttons.cpp
|
||||||
helpers/stick_from_buttons.h
|
helpers/stick_from_buttons.h
|
||||||
helpers/touch_from_buttons.cpp
|
helpers/touch_from_buttons.cpp
|
||||||
|
@ -23,10 +25,6 @@ add_library(input_common STATIC
|
||||||
gcadapter/gc_adapter.h
|
gcadapter/gc_adapter.h
|
||||||
gcadapter/gc_poller.cpp
|
gcadapter/gc_poller.cpp
|
||||||
gcadapter/gc_poller.h
|
gcadapter/gc_poller.h
|
||||||
mouse/mouse_input.cpp
|
|
||||||
mouse/mouse_input.h
|
|
||||||
mouse/mouse_poller.cpp
|
|
||||||
mouse/mouse_poller.h
|
|
||||||
sdl/sdl.cpp
|
sdl/sdl.cpp
|
||||||
sdl/sdl.h
|
sdl/sdl.h
|
||||||
tas/tas_input.cpp
|
tas/tas_input.cpp
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
// Copyright 2021 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included
|
||||||
|
|
||||||
|
#include <stop_token>
|
||||||
|
#include <thread>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include "common/param_package.h"
|
||||||
|
#include "common/settings.h"
|
||||||
|
#include "common/thread.h"
|
||||||
|
#include "input_common/drivers/mouse.h"
|
||||||
|
|
||||||
|
namespace InputCommon {
|
||||||
|
constexpr int touch_axis_x = 10;
|
||||||
|
constexpr int touch_axis_y = 11;
|
||||||
|
|
||||||
|
Mouse::Mouse(const std::string input_engine_) : InputEngine(input_engine_) {
|
||||||
|
PreSetController(identifier);
|
||||||
|
update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse::UpdateThread(std::stop_token stop_token) {
|
||||||
|
Common::SetCurrentThreadName("yuzu:input:Mouse");
|
||||||
|
constexpr int update_time = 10;
|
||||||
|
while (!stop_token.stop_requested()) {
|
||||||
|
if (Settings::values.mouse_panning) {
|
||||||
|
// Slow movement by 4%
|
||||||
|
last_mouse_change *= 0.96f;
|
||||||
|
const float sensitivity =
|
||||||
|
Settings::values.mouse_panning_sensitivity.GetValue() * 0.022f;
|
||||||
|
SetAxis(identifier, 0, last_mouse_change.x * sensitivity);
|
||||||
|
SetAxis(identifier, 1, -last_mouse_change.y * sensitivity);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mouse_panning_timout++ > 20) {
|
||||||
|
StopPanning();
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(update_time));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse::MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int center_y) {
|
||||||
|
SetAxis(identifier, touch_axis_x, touch_x);
|
||||||
|
SetAxis(identifier, touch_axis_y, touch_y);
|
||||||
|
|
||||||
|
if (Settings::values.mouse_panning) {
|
||||||
|
auto mouse_change =
|
||||||
|
(Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>();
|
||||||
|
mouse_panning_timout = 0;
|
||||||
|
|
||||||
|
const auto move_distance = mouse_change.Length();
|
||||||
|
if (move_distance == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make slow movements at least 3 units on lenght
|
||||||
|
if (move_distance < 3.0f) {
|
||||||
|
// Normalize value
|
||||||
|
mouse_change /= move_distance;
|
||||||
|
mouse_change *= 3.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Average mouse movements
|
||||||
|
last_mouse_change = (last_mouse_change * 0.91f) + (mouse_change * 0.09f);
|
||||||
|
|
||||||
|
const auto last_move_distance = last_mouse_change.Length();
|
||||||
|
|
||||||
|
// Make fast movements clamp to 8 units on lenght
|
||||||
|
if (last_move_distance > 8.0f) {
|
||||||
|
// Normalize value
|
||||||
|
last_mouse_change /= last_move_distance;
|
||||||
|
last_mouse_change *= 8.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore average if it's less than 1 unit and use current movement value
|
||||||
|
if (last_move_distance < 1.0f) {
|
||||||
|
last_mouse_change = mouse_change / mouse_change.Length();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button_pressed) {
|
||||||
|
const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin;
|
||||||
|
const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f;
|
||||||
|
SetAxis(identifier, 0, static_cast<float>(mouse_move.x) * sensitivity);
|
||||||
|
SetAxis(identifier, 1, static_cast<float>(-mouse_move.y) * sensitivity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse::PressButton(int x, int y, f32 touch_x, f32 touch_y, MouseButton button) {
|
||||||
|
SetAxis(identifier, touch_axis_x, touch_x);
|
||||||
|
SetAxis(identifier, touch_axis_y, touch_y);
|
||||||
|
SetButton(identifier, static_cast<int>(button), true);
|
||||||
|
// Set initial analog parameters
|
||||||
|
mouse_origin = {x, y};
|
||||||
|
last_mouse_position = {x, y};
|
||||||
|
button_pressed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse::ReleaseButton(MouseButton button) {
|
||||||
|
SetButton(identifier, static_cast<int>(button), false);
|
||||||
|
|
||||||
|
if (!Settings::values.mouse_panning) {
|
||||||
|
SetAxis(identifier, 0, 0);
|
||||||
|
SetAxis(identifier, 1, 0);
|
||||||
|
}
|
||||||
|
button_pressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse::ReleaseAllButtons() {
|
||||||
|
ResetButtonState();
|
||||||
|
button_pressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mouse::StopPanning() {
|
||||||
|
last_mouse_change = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Common::ParamPackage> Mouse::GetInputDevices() const {
|
||||||
|
std::vector<Common::ParamPackage> devices;
|
||||||
|
devices.emplace_back(Common::ParamPackage{
|
||||||
|
{"engine", "keyboard"},
|
||||||
|
{"display", "Keyboard/Mouse"},
|
||||||
|
});
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Mouse::GetUIName(const Common::ParamPackage& params) const {
|
||||||
|
if (params.Has("button")) {
|
||||||
|
return fmt::format("Mouse {}", params.Get("button", 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Bad Mouse";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace InputCommon
|
|
@ -0,0 +1,77 @@
|
||||||
|
// Copyright 2021 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stop_token>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "common/vector_math.h"
|
||||||
|
#include "input_common/input_engine.h"
|
||||||
|
|
||||||
|
namespace InputCommon {
|
||||||
|
|
||||||
|
enum class MouseButton {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Wheel,
|
||||||
|
Backward,
|
||||||
|
Forward,
|
||||||
|
Task,
|
||||||
|
Extra,
|
||||||
|
Undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A button device factory representing a keyboard. It receives keyboard events and forward them
|
||||||
|
* to all button devices it created.
|
||||||
|
*/
|
||||||
|
class Mouse final : public InputCommon::InputEngine {
|
||||||
|
public:
|
||||||
|
explicit Mouse(const std::string input_engine_);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals that mouse has moved.
|
||||||
|
* @param x the x-coordinate of the cursor
|
||||||
|
* @param y the y-coordinate of the cursor
|
||||||
|
* @param center_x the x-coordinate of the middle of the screen
|
||||||
|
* @param center_y the y-coordinate of the middle of the screen
|
||||||
|
*/
|
||||||
|
void MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int center_y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the status of all buttons bound with the key to pressed
|
||||||
|
* @param key_code the code of the key to press
|
||||||
|
*/
|
||||||
|
void PressButton(int x, int y, f32 touch_x, f32 touch_y, MouseButton button);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the status of all buttons bound with the key to released
|
||||||
|
* @param key_code the code of the key to release
|
||||||
|
*/
|
||||||
|
void ReleaseButton(MouseButton button);
|
||||||
|
|
||||||
|
void ReleaseAllButtons();
|
||||||
|
|
||||||
|
std::vector<Common::ParamPackage> GetInputDevices() const override;
|
||||||
|
std::string GetUIName(const Common::ParamPackage& params) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void UpdateThread(std::stop_token stop_token);
|
||||||
|
void StopPanning();
|
||||||
|
|
||||||
|
const PadIdentifier identifier = {
|
||||||
|
.guid = Common::UUID{""},
|
||||||
|
.port = 0,
|
||||||
|
.pad = 0,
|
||||||
|
};
|
||||||
|
Common::Vec2<int> mouse_origin;
|
||||||
|
Common::Vec2<int> last_mouse_position;
|
||||||
|
Common::Vec2<float> last_mouse_change;
|
||||||
|
bool button_pressed;
|
||||||
|
int mouse_panning_timout{};
|
||||||
|
std::jthread update_thread;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace InputCommon
|
|
@ -1,223 +0,0 @@
|
||||||
// Copyright 2020 yuzu Emulator Project
|
|
||||||
// Licensed under GPLv2+
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include <stop_token>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "input_common/mouse/mouse_input.h"
|
|
||||||
|
|
||||||
namespace MouseInput {
|
|
||||||
|
|
||||||
Mouse::Mouse() {
|
|
||||||
update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); });
|
|
||||||
}
|
|
||||||
|
|
||||||
Mouse::~Mouse() = default;
|
|
||||||
|
|
||||||
void Mouse::UpdateThread(std::stop_token stop_token) {
|
|
||||||
constexpr int update_time = 10;
|
|
||||||
while (!stop_token.stop_requested()) {
|
|
||||||
for (MouseInfo& info : mouse_info) {
|
|
||||||
const Common::Vec3f angular_direction{
|
|
||||||
-info.tilt_direction.y,
|
|
||||||
0.0f,
|
|
||||||
-info.tilt_direction.x,
|
|
||||||
};
|
|
||||||
|
|
||||||
info.motion.SetGyroscope(angular_direction * info.tilt_speed);
|
|
||||||
info.motion.UpdateRotation(update_time * 1000);
|
|
||||||
info.motion.UpdateOrientation(update_time * 1000);
|
|
||||||
info.tilt_speed = 0;
|
|
||||||
info.data.motion = info.motion.GetMotion();
|
|
||||||
if (Settings::values.mouse_panning) {
|
|
||||||
info.last_mouse_change *= 0.96f;
|
|
||||||
info.data.axis = {static_cast<int>(16 * info.last_mouse_change.x),
|
|
||||||
static_cast<int>(16 * -info.last_mouse_change.y)};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (configuring) {
|
|
||||||
UpdateYuzuSettings();
|
|
||||||
}
|
|
||||||
if (mouse_panning_timout++ > 20) {
|
|
||||||
StopPanning();
|
|
||||||
}
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(update_time));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mouse::UpdateYuzuSettings() {
|
|
||||||
if (buttons == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mouse_queue.Push(MouseStatus{
|
|
||||||
.button = last_button,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mouse::PressButton(int x, int y, MouseButton button_) {
|
|
||||||
const auto button_index = static_cast<std::size_t>(button_);
|
|
||||||
if (button_index >= mouse_info.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto button = 1U << button_index;
|
|
||||||
buttons |= static_cast<u16>(button);
|
|
||||||
last_button = button_;
|
|
||||||
|
|
||||||
mouse_info[button_index].mouse_origin = Common::MakeVec(x, y);
|
|
||||||
mouse_info[button_index].last_mouse_position = Common::MakeVec(x, y);
|
|
||||||
mouse_info[button_index].data.pressed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mouse::StopPanning() {
|
|
||||||
for (MouseInfo& info : mouse_info) {
|
|
||||||
if (Settings::values.mouse_panning) {
|
|
||||||
info.data.axis = {};
|
|
||||||
info.tilt_speed = 0;
|
|
||||||
info.last_mouse_change = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mouse::MouseMove(int x, int y, int center_x, int center_y) {
|
|
||||||
for (MouseInfo& info : mouse_info) {
|
|
||||||
if (Settings::values.mouse_panning) {
|
|
||||||
auto mouse_change =
|
|
||||||
(Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>();
|
|
||||||
mouse_panning_timout = 0;
|
|
||||||
|
|
||||||
if (mouse_change.y == 0 && mouse_change.x == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto mouse_change_length = mouse_change.Length();
|
|
||||||
if (mouse_change_length < 3.0f) {
|
|
||||||
mouse_change /= mouse_change_length / 3.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
info.last_mouse_change = (info.last_mouse_change * 0.91f) + (mouse_change * 0.09f);
|
|
||||||
|
|
||||||
const auto last_mouse_change_length = info.last_mouse_change.Length();
|
|
||||||
if (last_mouse_change_length > 8.0f) {
|
|
||||||
info.last_mouse_change /= last_mouse_change_length / 8.0f;
|
|
||||||
} else if (last_mouse_change_length < 1.0f) {
|
|
||||||
info.last_mouse_change = mouse_change / mouse_change.Length();
|
|
||||||
}
|
|
||||||
|
|
||||||
info.tilt_direction = info.last_mouse_change;
|
|
||||||
info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.data.pressed) {
|
|
||||||
const auto mouse_move = Common::MakeVec(x, y) - info.mouse_origin;
|
|
||||||
const auto mouse_change = Common::MakeVec(x, y) - info.last_mouse_position;
|
|
||||||
info.last_mouse_position = Common::MakeVec(x, y);
|
|
||||||
info.data.axis = {mouse_move.x, -mouse_move.y};
|
|
||||||
|
|
||||||
if (mouse_change.x == 0 && mouse_change.y == 0) {
|
|
||||||
info.tilt_speed = 0;
|
|
||||||
} else {
|
|
||||||
info.tilt_direction = mouse_change.Cast<float>();
|
|
||||||
info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mouse::ReleaseButton(MouseButton button_) {
|
|
||||||
const auto button_index = static_cast<std::size_t>(button_);
|
|
||||||
if (button_index >= mouse_info.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto button = 1U << button_index;
|
|
||||||
buttons &= static_cast<u16>(0xFF - button);
|
|
||||||
|
|
||||||
mouse_info[button_index].tilt_speed = 0;
|
|
||||||
mouse_info[button_index].data.pressed = false;
|
|
||||||
mouse_info[button_index].data.axis = {0, 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mouse::ReleaseAllButtons() {
|
|
||||||
buttons = 0;
|
|
||||||
for (auto& info : mouse_info) {
|
|
||||||
info.tilt_speed = 0;
|
|
||||||
info.data.pressed = false;
|
|
||||||
info.data.axis = {0, 0};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mouse::BeginConfiguration() {
|
|
||||||
buttons = 0;
|
|
||||||
last_button = MouseButton::Undefined;
|
|
||||||
mouse_queue.Clear();
|
|
||||||
configuring = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mouse::EndConfiguration() {
|
|
||||||
buttons = 0;
|
|
||||||
for (MouseInfo& info : mouse_info) {
|
|
||||||
info.tilt_speed = 0;
|
|
||||||
info.data.pressed = false;
|
|
||||||
info.data.axis = {0, 0};
|
|
||||||
}
|
|
||||||
last_button = MouseButton::Undefined;
|
|
||||||
mouse_queue.Clear();
|
|
||||||
configuring = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Mouse::ToggleButton(std::size_t button_) {
|
|
||||||
if (button_ >= mouse_info.size()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto button = 1U << button_;
|
|
||||||
const bool button_state = (toggle_buttons & button) != 0;
|
|
||||||
const bool button_lock = (lock_buttons & button) != 0;
|
|
||||||
|
|
||||||
if (button_lock) {
|
|
||||||
return button_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock_buttons |= static_cast<u16>(button);
|
|
||||||
|
|
||||||
if (button_state) {
|
|
||||||
toggle_buttons &= static_cast<u16>(0xFF - button);
|
|
||||||
} else {
|
|
||||||
toggle_buttons |= static_cast<u16>(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
return !button_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Mouse::UnlockButton(std::size_t button_) {
|
|
||||||
if (button_ >= mouse_info.size()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto button = 1U << button_;
|
|
||||||
const bool button_state = (toggle_buttons & button) != 0;
|
|
||||||
|
|
||||||
lock_buttons &= static_cast<u16>(0xFF - button);
|
|
||||||
|
|
||||||
return button_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() {
|
|
||||||
return mouse_queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() const {
|
|
||||||
return mouse_queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseData& Mouse::GetMouseState(std::size_t button) {
|
|
||||||
return mouse_info[button].data;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MouseData& Mouse::GetMouseState(std::size_t button) const {
|
|
||||||
return mouse_info[button].data;
|
|
||||||
}
|
|
||||||
} // namespace MouseInput
|
|
|
@ -1,116 +0,0 @@
|
||||||
// Copyright 2020 yuzu Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <mutex>
|
|
||||||
#include <stop_token>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "common/threadsafe_queue.h"
|
|
||||||
#include "common/vector_math.h"
|
|
||||||
#include "core/frontend/input.h"
|
|
||||||
#include "input_common/motion_input.h"
|
|
||||||
|
|
||||||
namespace MouseInput {
|
|
||||||
|
|
||||||
enum class MouseButton {
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Wheel,
|
|
||||||
Backward,
|
|
||||||
Forward,
|
|
||||||
Task,
|
|
||||||
Extra,
|
|
||||||
Undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MouseStatus {
|
|
||||||
MouseButton button{MouseButton::Undefined};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MouseData {
|
|
||||||
bool pressed{};
|
|
||||||
std::array<int, 2> axis{};
|
|
||||||
Input::MotionStatus motion{};
|
|
||||||
Input::TouchStatus touch{};
|
|
||||||
};
|
|
||||||
|
|
||||||
class Mouse {
|
|
||||||
public:
|
|
||||||
Mouse();
|
|
||||||
~Mouse();
|
|
||||||
|
|
||||||
/// Used for polling
|
|
||||||
void BeginConfiguration();
|
|
||||||
void EndConfiguration();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals that a button is pressed.
|
|
||||||
* @param x the x-coordinate of the cursor
|
|
||||||
* @param y the y-coordinate of the cursor
|
|
||||||
* @param button_ the button pressed
|
|
||||||
*/
|
|
||||||
void PressButton(int x, int y, MouseButton button_);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals that mouse has moved.
|
|
||||||
* @param x the x-coordinate of the cursor
|
|
||||||
* @param y the y-coordinate of the cursor
|
|
||||||
* @param center_x the x-coordinate of the middle of the screen
|
|
||||||
* @param center_y the y-coordinate of the middle of the screen
|
|
||||||
*/
|
|
||||||
void MouseMove(int x, int y, int center_x, int center_y);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals that a button is released.
|
|
||||||
* @param button_ the button pressed
|
|
||||||
*/
|
|
||||||
void ReleaseButton(MouseButton button_);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals that all buttons are released
|
|
||||||
*/
|
|
||||||
void ReleaseAllButtons();
|
|
||||||
|
|
||||||
[[nodiscard]] bool ToggleButton(std::size_t button_);
|
|
||||||
[[nodiscard]] bool UnlockButton(std::size_t button_);
|
|
||||||
|
|
||||||
[[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue();
|
|
||||||
[[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const;
|
|
||||||
|
|
||||||
[[nodiscard]] MouseData& GetMouseState(std::size_t button);
|
|
||||||
[[nodiscard]] const MouseData& GetMouseState(std::size_t button) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void UpdateThread(std::stop_token stop_token);
|
|
||||||
void UpdateYuzuSettings();
|
|
||||||
void StopPanning();
|
|
||||||
|
|
||||||
struct MouseInfo {
|
|
||||||
InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f};
|
|
||||||
Common::Vec2<int> mouse_origin;
|
|
||||||
Common::Vec2<int> last_mouse_position;
|
|
||||||
Common::Vec2<float> last_mouse_change;
|
|
||||||
bool is_tilting = false;
|
|
||||||
float sensitivity{0.120f};
|
|
||||||
|
|
||||||
float tilt_speed = 0;
|
|
||||||
Common::Vec2<float> tilt_direction;
|
|
||||||
MouseData data;
|
|
||||||
};
|
|
||||||
|
|
||||||
u16 buttons{};
|
|
||||||
u16 toggle_buttons{};
|
|
||||||
u16 lock_buttons{};
|
|
||||||
std::jthread update_thread;
|
|
||||||
MouseButton last_button{MouseButton::Undefined};
|
|
||||||
std::array<MouseInfo, 7> mouse_info;
|
|
||||||
Common::SPSCQueue<MouseStatus> mouse_queue;
|
|
||||||
bool configuring{false};
|
|
||||||
int mouse_panning_timout{};
|
|
||||||
};
|
|
||||||
} // namespace MouseInput
|
|
|
@ -1,299 +0,0 @@
|
||||||
// Copyright 2020 yuzu Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "common/threadsafe_queue.h"
|
|
||||||
#include "input_common/mouse/mouse_input.h"
|
|
||||||
#include "input_common/mouse/mouse_poller.h"
|
|
||||||
|
|
||||||
namespace InputCommon {
|
|
||||||
|
|
||||||
class MouseButton final : public Input::ButtonDevice {
|
|
||||||
public:
|
|
||||||
explicit MouseButton(u32 button_, bool toggle_, MouseInput::Mouse* mouse_input_)
|
|
||||||
: button(button_), toggle(toggle_), mouse_input(mouse_input_) {}
|
|
||||||
|
|
||||||
bool GetStatus() const override {
|
|
||||||
const bool button_state = mouse_input->GetMouseState(button).pressed;
|
|
||||||
if (!toggle) {
|
|
||||||
return button_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (button_state) {
|
|
||||||
return mouse_input->ToggleButton(button);
|
|
||||||
}
|
|
||||||
return mouse_input->UnlockButton(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const u32 button;
|
|
||||||
const bool toggle;
|
|
||||||
MouseInput::Mouse* mouse_input;
|
|
||||||
};
|
|
||||||
|
|
||||||
MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_)
|
|
||||||
: mouse_input(std::move(mouse_input_)) {}
|
|
||||||
|
|
||||||
std::unique_ptr<Input::ButtonDevice> MouseButtonFactory::Create(
|
|
||||||
const Common::ParamPackage& params) {
|
|
||||||
const auto button_id = params.Get("button", 0);
|
|
||||||
const auto toggle = params.Get("toggle", false);
|
|
||||||
|
|
||||||
return std::make_unique<MouseButton>(button_id, toggle, mouse_input.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
Common::ParamPackage MouseButtonFactory::GetNextInput() const {
|
|
||||||
MouseInput::MouseStatus pad;
|
|
||||||
Common::ParamPackage params;
|
|
||||||
auto& queue = mouse_input->GetMouseQueue();
|
|
||||||
while (queue.Pop(pad)) {
|
|
||||||
// This while loop will break on the earliest detected button
|
|
||||||
if (pad.button != MouseInput::MouseButton::Undefined) {
|
|
||||||
params.Set("engine", "mouse");
|
|
||||||
params.Set("button", static_cast<u16>(pad.button));
|
|
||||||
params.Set("toggle", false);
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MouseButtonFactory::BeginConfiguration() {
|
|
||||||
polling = true;
|
|
||||||
mouse_input->BeginConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MouseButtonFactory::EndConfiguration() {
|
|
||||||
polling = false;
|
|
||||||
mouse_input->EndConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
class MouseAnalog final : public Input::AnalogDevice {
|
|
||||||
public:
|
|
||||||
explicit MouseAnalog(u32 port_, u32 axis_x_, u32 axis_y_, bool invert_x_, bool invert_y_,
|
|
||||||
float deadzone_, float range_, const MouseInput::Mouse* mouse_input_)
|
|
||||||
: button(port_), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), invert_y(invert_y_),
|
|
||||||
deadzone(deadzone_), range(range_), mouse_input(mouse_input_) {}
|
|
||||||
|
|
||||||
float GetAxis(u32 axis) const {
|
|
||||||
std::lock_guard lock{mutex};
|
|
||||||
const auto axis_value =
|
|
||||||
static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis));
|
|
||||||
const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.10f;
|
|
||||||
return axis_value * sensitivity / (100.0f * range);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const {
|
|
||||||
float x = GetAxis(analog_axis_x);
|
|
||||||
float y = GetAxis(analog_axis_y);
|
|
||||||
if (invert_x) {
|
|
||||||
x = -x;
|
|
||||||
}
|
|
||||||
if (invert_y) {
|
|
||||||
y = -y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the coordinates are in the unit circle,
|
|
||||||
// otherwise normalize it.
|
|
||||||
float r = x * x + y * y;
|
|
||||||
if (r > 1.0f) {
|
|
||||||
r = std::sqrt(r);
|
|
||||||
x /= r;
|
|
||||||
y /= r;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {x, y};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<float, float> GetStatus() const override {
|
|
||||||
const auto [x, y] = GetAnalog(axis_x, axis_y);
|
|
||||||
const float r = std::sqrt((x * x) + (y * y));
|
|
||||||
if (r > deadzone) {
|
|
||||||
return {x / r * (r - deadzone) / (1 - deadzone),
|
|
||||||
y / r * (r - deadzone) / (1 - deadzone)};
|
|
||||||
}
|
|
||||||
return {0.0f, 0.0f};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<float, float> GetRawStatus() const override {
|
|
||||||
const float x = GetAxis(axis_x);
|
|
||||||
const float y = GetAxis(axis_y);
|
|
||||||
return {x, y};
|
|
||||||
}
|
|
||||||
|
|
||||||
Input::AnalogProperties GetAnalogProperties() const override {
|
|
||||||
return {deadzone, range, 0.5f};
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const u32 button;
|
|
||||||
const u32 axis_x;
|
|
||||||
const u32 axis_y;
|
|
||||||
const bool invert_x;
|
|
||||||
const bool invert_y;
|
|
||||||
const float deadzone;
|
|
||||||
const float range;
|
|
||||||
const MouseInput::Mouse* mouse_input;
|
|
||||||
mutable std::mutex mutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// An analog device factory that creates analog devices from GC Adapter
|
|
||||||
MouseAnalogFactory::MouseAnalogFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_)
|
|
||||||
: mouse_input(std::move(mouse_input_)) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates analog device from joystick axes
|
|
||||||
* @param params contains parameters for creating the device:
|
|
||||||
* - "port": the nth gcpad on the adapter
|
|
||||||
* - "axis_x": the index of the axis to be bind as x-axis
|
|
||||||
* - "axis_y": the index of the axis to be bind as y-axis
|
|
||||||
*/
|
|
||||||
std::unique_ptr<Input::AnalogDevice> MouseAnalogFactory::Create(
|
|
||||||
const Common::ParamPackage& params) {
|
|
||||||
const auto port = static_cast<u32>(params.Get("port", 0));
|
|
||||||
const auto axis_x = static_cast<u32>(params.Get("axis_x", 0));
|
|
||||||
const auto axis_y = static_cast<u32>(params.Get("axis_y", 1));
|
|
||||||
const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
|
|
||||||
const auto range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
|
|
||||||
const std::string invert_x_value = params.Get("invert_x", "+");
|
|
||||||
const std::string invert_y_value = params.Get("invert_y", "+");
|
|
||||||
const bool invert_x = invert_x_value == "-";
|
|
||||||
const bool invert_y = invert_y_value == "-";
|
|
||||||
|
|
||||||
return std::make_unique<MouseAnalog>(port, axis_x, axis_y, invert_x, invert_y, deadzone, range,
|
|
||||||
mouse_input.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MouseAnalogFactory::BeginConfiguration() {
|
|
||||||
polling = true;
|
|
||||||
mouse_input->BeginConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MouseAnalogFactory::EndConfiguration() {
|
|
||||||
polling = false;
|
|
||||||
mouse_input->EndConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
Common::ParamPackage MouseAnalogFactory::GetNextInput() const {
|
|
||||||
MouseInput::MouseStatus pad;
|
|
||||||
Common::ParamPackage params;
|
|
||||||
auto& queue = mouse_input->GetMouseQueue();
|
|
||||||
while (queue.Pop(pad)) {
|
|
||||||
// This while loop will break on the earliest detected button
|
|
||||||
if (pad.button != MouseInput::MouseButton::Undefined) {
|
|
||||||
params.Set("engine", "mouse");
|
|
||||||
params.Set("port", static_cast<u16>(pad.button));
|
|
||||||
params.Set("axis_x", 0);
|
|
||||||
params.Set("axis_y", 1);
|
|
||||||
params.Set("invert_x", "+");
|
|
||||||
params.Set("invert_y", "+");
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MouseMotion final : public Input::MotionDevice {
|
|
||||||
public:
|
|
||||||
explicit MouseMotion(u32 button_, const MouseInput::Mouse* mouse_input_)
|
|
||||||
: button(button_), mouse_input(mouse_input_) {}
|
|
||||||
|
|
||||||
Input::MotionStatus GetStatus() const override {
|
|
||||||
return mouse_input->GetMouseState(button).motion;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const u32 button;
|
|
||||||
const MouseInput::Mouse* mouse_input;
|
|
||||||
};
|
|
||||||
|
|
||||||
MouseMotionFactory::MouseMotionFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_)
|
|
||||||
: mouse_input(std::move(mouse_input_)) {}
|
|
||||||
|
|
||||||
std::unique_ptr<Input::MotionDevice> MouseMotionFactory::Create(
|
|
||||||
const Common::ParamPackage& params) {
|
|
||||||
const auto button_id = params.Get("button", 0);
|
|
||||||
|
|
||||||
return std::make_unique<MouseMotion>(button_id, mouse_input.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
Common::ParamPackage MouseMotionFactory::GetNextInput() const {
|
|
||||||
MouseInput::MouseStatus pad;
|
|
||||||
Common::ParamPackage params;
|
|
||||||
auto& queue = mouse_input->GetMouseQueue();
|
|
||||||
while (queue.Pop(pad)) {
|
|
||||||
// This while loop will break on the earliest detected button
|
|
||||||
if (pad.button != MouseInput::MouseButton::Undefined) {
|
|
||||||
params.Set("engine", "mouse");
|
|
||||||
params.Set("button", static_cast<u16>(pad.button));
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MouseMotionFactory::BeginConfiguration() {
|
|
||||||
polling = true;
|
|
||||||
mouse_input->BeginConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MouseMotionFactory::EndConfiguration() {
|
|
||||||
polling = false;
|
|
||||||
mouse_input->EndConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
class MouseTouch final : public Input::TouchDevice {
|
|
||||||
public:
|
|
||||||
explicit MouseTouch(u32 button_, const MouseInput::Mouse* mouse_input_)
|
|
||||||
: button(button_), mouse_input(mouse_input_) {}
|
|
||||||
|
|
||||||
Input::TouchStatus GetStatus() const override {
|
|
||||||
return mouse_input->GetMouseState(button).touch;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const u32 button;
|
|
||||||
const MouseInput::Mouse* mouse_input;
|
|
||||||
};
|
|
||||||
|
|
||||||
MouseTouchFactory::MouseTouchFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_)
|
|
||||||
: mouse_input(std::move(mouse_input_)) {}
|
|
||||||
|
|
||||||
std::unique_ptr<Input::TouchDevice> MouseTouchFactory::Create(const Common::ParamPackage& params) {
|
|
||||||
const auto button_id = params.Get("button", 0);
|
|
||||||
|
|
||||||
return std::make_unique<MouseTouch>(button_id, mouse_input.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
Common::ParamPackage MouseTouchFactory::GetNextInput() const {
|
|
||||||
MouseInput::MouseStatus pad;
|
|
||||||
Common::ParamPackage params;
|
|
||||||
auto& queue = mouse_input->GetMouseQueue();
|
|
||||||
while (queue.Pop(pad)) {
|
|
||||||
// This while loop will break on the earliest detected button
|
|
||||||
if (pad.button != MouseInput::MouseButton::Undefined) {
|
|
||||||
params.Set("engine", "mouse");
|
|
||||||
params.Set("button", static_cast<u16>(pad.button));
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MouseTouchFactory::BeginConfiguration() {
|
|
||||||
polling = true;
|
|
||||||
mouse_input->BeginConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MouseTouchFactory::EndConfiguration() {
|
|
||||||
polling = false;
|
|
||||||
mouse_input->EndConfiguration();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace InputCommon
|
|
|
@ -1,109 +0,0 @@
|
||||||
// Copyright 2020 yuzu Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include "core/frontend/input.h"
|
|
||||||
#include "input_common/mouse/mouse_input.h"
|
|
||||||
|
|
||||||
namespace InputCommon {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A button device factory representing a mouse. It receives mouse events and forward them
|
|
||||||
* to all button devices it created.
|
|
||||||
*/
|
|
||||||
class MouseButtonFactory final : public Input::Factory<Input::ButtonDevice> {
|
|
||||||
public:
|
|
||||||
explicit MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a button device from a button press
|
|
||||||
* @param params contains parameters for creating the device:
|
|
||||||
* - "code": the code of the key to bind with the button
|
|
||||||
*/
|
|
||||||
std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override;
|
|
||||||
|
|
||||||
Common::ParamPackage GetNextInput() const;
|
|
||||||
|
|
||||||
/// For device input configuration/polling
|
|
||||||
void BeginConfiguration();
|
|
||||||
void EndConfiguration();
|
|
||||||
|
|
||||||
bool IsPolling() const {
|
|
||||||
return polling;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<MouseInput::Mouse> mouse_input;
|
|
||||||
bool polling = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// An analog device factory that creates analog devices from mouse
|
|
||||||
class MouseAnalogFactory final : public Input::Factory<Input::AnalogDevice> {
|
|
||||||
public:
|
|
||||||
explicit MouseAnalogFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_);
|
|
||||||
|
|
||||||
std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override;
|
|
||||||
|
|
||||||
Common::ParamPackage GetNextInput() const;
|
|
||||||
|
|
||||||
/// For device input configuration/polling
|
|
||||||
void BeginConfiguration();
|
|
||||||
void EndConfiguration();
|
|
||||||
|
|
||||||
bool IsPolling() const {
|
|
||||||
return polling;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<MouseInput::Mouse> mouse_input;
|
|
||||||
bool polling = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A motion device factory that creates motion devices from mouse
|
|
||||||
class MouseMotionFactory final : public Input::Factory<Input::MotionDevice> {
|
|
||||||
public:
|
|
||||||
explicit MouseMotionFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_);
|
|
||||||
|
|
||||||
std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override;
|
|
||||||
|
|
||||||
Common::ParamPackage GetNextInput() const;
|
|
||||||
|
|
||||||
/// For device input configuration/polling
|
|
||||||
void BeginConfiguration();
|
|
||||||
void EndConfiguration();
|
|
||||||
|
|
||||||
bool IsPolling() const {
|
|
||||||
return polling;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<MouseInput::Mouse> mouse_input;
|
|
||||||
bool polling = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// An touch device factory that creates touch devices from mouse
|
|
||||||
class MouseTouchFactory final : public Input::Factory<Input::TouchDevice> {
|
|
||||||
public:
|
|
||||||
explicit MouseTouchFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_);
|
|
||||||
|
|
||||||
std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override;
|
|
||||||
|
|
||||||
Common::ParamPackage GetNextInput() const;
|
|
||||||
|
|
||||||
/// For device input configuration/polling
|
|
||||||
void BeginConfiguration();
|
|
||||||
void EndConfiguration();
|
|
||||||
|
|
||||||
bool IsPolling() const {
|
|
||||||
return polling;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::shared_ptr<MouseInput::Mouse> mouse_input;
|
|
||||||
bool polling = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace InputCommon
|
|
Loading…
Reference in New Issue