committed by
Narr the Reg
7 changed files with 217 additions and 751 deletions
-
6src/input_common/CMakeLists.txt
-
138src/input_common/drivers/mouse.cpp
-
77src/input_common/drivers/mouse.h
-
223src/input_common/mouse/mouse_input.cpp
-
116src/input_common/mouse/mouse_input.h
-
299src/input_common/mouse/mouse_poller.cpp
-
109src/input_common/mouse/mouse_poller.h
@ -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 |
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue