Merge pull request #5990 from german77/mousePanningV2
InputCommon: Mouse fixes
This commit is contained in:
commit
9c4c9f1e7d
@ -59,7 +59,7 @@ void Mouse::UpdateYuzuSettings() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mouse::PressButton(int x, int y, int button_) {
|
void Mouse::PressButton(int x, int y, MouseButton button_) {
|
||||||
const auto button_index = static_cast<std::size_t>(button_);
|
const auto button_index = static_cast<std::size_t>(button_);
|
||||||
if (button_index >= mouse_info.size()) {
|
if (button_index >= mouse_info.size()) {
|
||||||
return;
|
return;
|
||||||
@ -67,7 +67,7 @@ void Mouse::PressButton(int x, int y, int button_) {
|
|||||||
|
|
||||||
const auto button = 1U << button_index;
|
const auto button = 1U << button_index;
|
||||||
buttons |= static_cast<u16>(button);
|
buttons |= static_cast<u16>(button);
|
||||||
last_button = static_cast<MouseButton>(button_index);
|
last_button = button_;
|
||||||
|
|
||||||
mouse_info[button_index].mouse_origin = Common::MakeVec(x, y);
|
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].last_mouse_position = Common::MakeVec(x, y);
|
||||||
@ -129,7 +129,7 @@ void Mouse::MouseMove(int x, int y, int center_x, int center_y) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mouse::ReleaseButton(int button_) {
|
void Mouse::ReleaseButton(MouseButton button_) {
|
||||||
const auto button_index = static_cast<std::size_t>(button_);
|
const auto button_index = static_cast<std::size_t>(button_);
|
||||||
if (button_index >= mouse_info.size()) {
|
if (button_index >= mouse_info.size()) {
|
||||||
return;
|
return;
|
||||||
@ -152,6 +152,11 @@ void Mouse::BeginConfiguration() {
|
|||||||
|
|
||||||
void Mouse::EndConfiguration() {
|
void Mouse::EndConfiguration() {
|
||||||
buttons = 0;
|
buttons = 0;
|
||||||
|
for (MouseInfo& info : mouse_info) {
|
||||||
|
info.tilt_speed = 0;
|
||||||
|
info.data.pressed = false;
|
||||||
|
info.data.axis = {0, 0};
|
||||||
|
}
|
||||||
last_button = MouseButton::Undefined;
|
last_button = MouseButton::Undefined;
|
||||||
mouse_queue.Clear();
|
mouse_queue.Clear();
|
||||||
configuring = false;
|
configuring = false;
|
||||||
|
@ -18,10 +18,12 @@ namespace MouseInput {
|
|||||||
|
|
||||||
enum class MouseButton {
|
enum class MouseButton {
|
||||||
Left,
|
Left,
|
||||||
Wheel,
|
|
||||||
Right,
|
Right,
|
||||||
Forward,
|
Wheel,
|
||||||
Backward,
|
Backward,
|
||||||
|
Forward,
|
||||||
|
Task,
|
||||||
|
Extra,
|
||||||
Undefined,
|
Undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -51,7 +53,7 @@ public:
|
|||||||
* @param y the y-coordinate of the cursor
|
* @param y the y-coordinate of the cursor
|
||||||
* @param button_ the button pressed
|
* @param button_ the button pressed
|
||||||
*/
|
*/
|
||||||
void PressButton(int x, int y, int button_);
|
void PressButton(int x, int y, MouseButton button_);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signals that mouse has moved.
|
* Signals that mouse has moved.
|
||||||
@ -65,7 +67,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Signals that a motion sensor tilt has ended.
|
* Signals that a motion sensor tilt has ended.
|
||||||
*/
|
*/
|
||||||
void ReleaseButton(int button_);
|
void ReleaseButton(MouseButton button_);
|
||||||
|
|
||||||
[[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue();
|
[[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue();
|
||||||
[[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const;
|
[[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const;
|
||||||
@ -94,7 +96,7 @@ private:
|
|||||||
u16 buttons{};
|
u16 buttons{};
|
||||||
std::thread update_thread;
|
std::thread update_thread;
|
||||||
MouseButton last_button{MouseButton::Undefined};
|
MouseButton last_button{MouseButton::Undefined};
|
||||||
std::array<MouseInfo, 5> mouse_info;
|
std::array<MouseInfo, 7> mouse_info;
|
||||||
Common::SPSCQueue<MouseStatus> mouse_queue;
|
Common::SPSCQueue<MouseStatus> mouse_queue;
|
||||||
bool configuring{false};
|
bool configuring{false};
|
||||||
bool update_thread_running{true};
|
bool update_thread_running{true};
|
||||||
|
@ -383,6 +383,25 @@ void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
|
|||||||
input_subsystem->GetKeyboard()->ReleaseKey(event->key());
|
input_subsystem->GetKeyboard()->ReleaseKey(event->key());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MouseInput::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) {
|
||||||
|
switch (button) {
|
||||||
|
case Qt::LeftButton:
|
||||||
|
return MouseInput::MouseButton::Left;
|
||||||
|
case Qt::RightButton:
|
||||||
|
return MouseInput::MouseButton::Right;
|
||||||
|
case Qt::MiddleButton:
|
||||||
|
return MouseInput::MouseButton::Wheel;
|
||||||
|
case Qt::BackButton:
|
||||||
|
return MouseInput::MouseButton::Backward;
|
||||||
|
case Qt::ForwardButton:
|
||||||
|
return MouseInput::MouseButton::Forward;
|
||||||
|
case Qt::TaskButton:
|
||||||
|
return MouseInput::MouseButton::Task;
|
||||||
|
default:
|
||||||
|
return MouseInput::MouseButton::Extra;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GRenderWindow::mousePressEvent(QMouseEvent* event) {
|
void GRenderWindow::mousePressEvent(QMouseEvent* event) {
|
||||||
// Touch input is handled in TouchBeginEvent
|
// Touch input is handled in TouchBeginEvent
|
||||||
if (event->source() == Qt::MouseEventSynthesizedBySystem) {
|
if (event->source() == Qt::MouseEventSynthesizedBySystem) {
|
||||||
@ -391,7 +410,8 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) {
|
|||||||
|
|
||||||
auto pos = event->pos();
|
auto pos = event->pos();
|
||||||
const auto [x, y] = ScaleTouch(pos);
|
const auto [x, y] = ScaleTouch(pos);
|
||||||
input_subsystem->GetMouse()->PressButton(x, y, event->button());
|
const auto button = QtButtonToMouseButton(event->button());
|
||||||
|
input_subsystem->GetMouse()->PressButton(x, y, button);
|
||||||
|
|
||||||
if (event->button() == Qt::LeftButton) {
|
if (event->button() == Qt::LeftButton) {
|
||||||
this->TouchPressed(x, y, 0);
|
this->TouchPressed(x, y, 0);
|
||||||
@ -425,7 +445,8 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
input_subsystem->GetMouse()->ReleaseButton(event->button());
|
const auto button = QtButtonToMouseButton(event->button());
|
||||||
|
input_subsystem->GetMouse()->ReleaseButton(button);
|
||||||
|
|
||||||
if (event->button() == Qt::LeftButton) {
|
if (event->button() == Qt::LeftButton) {
|
||||||
this->TouchReleased(0);
|
this->TouchReleased(0);
|
||||||
|
@ -28,6 +28,10 @@ namespace InputCommon {
|
|||||||
class InputSubsystem;
|
class InputSubsystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace MouseInput {
|
||||||
|
enum class MouseButton;
|
||||||
|
}
|
||||||
|
|
||||||
namespace VideoCore {
|
namespace VideoCore {
|
||||||
enum class LoadCallbackStage;
|
enum class LoadCallbackStage;
|
||||||
}
|
}
|
||||||
@ -149,6 +153,9 @@ public:
|
|||||||
void keyPressEvent(QKeyEvent* event) override;
|
void keyPressEvent(QKeyEvent* event) override;
|
||||||
void keyReleaseEvent(QKeyEvent* event) override;
|
void keyReleaseEvent(QKeyEvent* event) override;
|
||||||
|
|
||||||
|
/// Converts a Qt mouse button into MouseInput mouse button
|
||||||
|
static MouseInput::MouseButton QtButtonToMouseButton(Qt::MouseButton button);
|
||||||
|
|
||||||
void mousePressEvent(QMouseEvent* event) override;
|
void mousePressEvent(QMouseEvent* event) override;
|
||||||
void mouseMoveEvent(QMouseEvent* event) override;
|
void mouseMoveEvent(QMouseEvent* event) override;
|
||||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||||
|
@ -235,7 +235,7 @@ const std::array<UISettings::Shortcut, 17> Config::default_hotkeys{{
|
|||||||
{QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}},
|
{QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), Qt::WindowShortcut}},
|
||||||
{QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), Qt::WindowShortcut}},
|
{QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), Qt::WindowShortcut}},
|
||||||
{QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), Qt::WindowShortcut}},
|
{QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), Qt::WindowShortcut}},
|
||||||
{QStringLiteral("Toggle Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("F9"), Qt::ApplicationShortcut}},
|
{QStringLiteral("Toggle Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F9"), Qt::ApplicationShortcut}},
|
||||||
{QStringLiteral("Toggle Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Z"), Qt::ApplicationShortcut}},
|
{QStringLiteral("Toggle Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Z"), Qt::ApplicationShortcut}},
|
||||||
{QStringLiteral("Toggle Status Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+S"), Qt::WindowShortcut}},
|
{QStringLiteral("Toggle Status Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+S"), Qt::WindowShortcut}},
|
||||||
}};
|
}};
|
||||||
@ -508,7 +508,7 @@ void Config::ReadControlValues() {
|
|||||||
|
|
||||||
Settings::values.emulate_analog_keyboard =
|
Settings::values.emulate_analog_keyboard =
|
||||||
ReadSetting(QStringLiteral("emulate_analog_keyboard"), false).toBool();
|
ReadSetting(QStringLiteral("emulate_analog_keyboard"), false).toBool();
|
||||||
Settings::values.mouse_panning = ReadSetting(QStringLiteral("mouse_panning"), false).toBool();
|
Settings::values.mouse_panning = false;
|
||||||
Settings::values.mouse_panning_sensitivity =
|
Settings::values.mouse_panning_sensitivity =
|
||||||
ReadSetting(QStringLiteral("mouse_panning_sensitivity"), 1).toFloat();
|
ReadSetting(QStringLiteral("mouse_panning_sensitivity"), 1).toFloat();
|
||||||
|
|
||||||
@ -1182,7 +1182,6 @@ void Config::SaveControlValues() {
|
|||||||
WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false);
|
WriteSetting(QStringLiteral("keyboard_enabled"), Settings::values.keyboard_enabled, false);
|
||||||
WriteSetting(QStringLiteral("emulate_analog_keyboard"),
|
WriteSetting(QStringLiteral("emulate_analog_keyboard"),
|
||||||
Settings::values.emulate_analog_keyboard, false);
|
Settings::values.emulate_analog_keyboard, false);
|
||||||
WriteSetting(QStringLiteral("mouse_panning"), Settings::values.mouse_panning, false);
|
|
||||||
WriteSetting(QStringLiteral("mouse_panning_sensitivity"),
|
WriteSetting(QStringLiteral("mouse_panning_sensitivity"),
|
||||||
Settings::values.mouse_panning_sensitivity, 1.0f);
|
Settings::values.mouse_panning_sensitivity, 1.0f);
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "input_common/mouse/mouse_poller.h"
|
#include "input_common/mouse/mouse_poller.h"
|
||||||
#include "input_common/udp/udp.h"
|
#include "input_common/udp/udp.h"
|
||||||
#include "ui_configure_input_player.h"
|
#include "ui_configure_input_player.h"
|
||||||
|
#include "yuzu/bootmanager.h"
|
||||||
#include "yuzu/configuration/config.h"
|
#include "yuzu/configuration/config.h"
|
||||||
#include "yuzu/configuration/configure_input_player.h"
|
#include "yuzu/configuration/configure_input_player.h"
|
||||||
#include "yuzu/configuration/configure_input_player_widget.h"
|
#include "yuzu/configuration/configure_input_player_widget.h"
|
||||||
@ -1345,7 +1346,8 @@ void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
input_subsystem->GetMouse()->PressButton(0, 0, event->button());
|
const auto button = GRenderWindow::QtButtonToMouseButton(event->button());
|
||||||
|
input_subsystem->GetMouse()->PressButton(0, 0, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
|
void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) {
|
||||||
|
@ -854,8 +854,7 @@ void GMainWindow::InitializeHotkeys() {
|
|||||||
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this),
|
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Mouse Panning"), this),
|
||||||
&QShortcut::activated, this, [&] {
|
&QShortcut::activated, this, [&] {
|
||||||
Settings::values.mouse_panning = !Settings::values.mouse_panning;
|
Settings::values.mouse_panning = !Settings::values.mouse_panning;
|
||||||
if (UISettings::values.hide_mouse || Settings::values.mouse_panning) {
|
if (Settings::values.mouse_panning) {
|
||||||
mouse_hide_timer.start();
|
|
||||||
render_window->installEventFilter(render_window);
|
render_window->installEventFilter(render_window);
|
||||||
render_window->setAttribute(Qt::WA_Hover, true);
|
render_window->setAttribute(Qt::WA_Hover, true);
|
||||||
}
|
}
|
||||||
@ -1208,11 +1207,14 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) {
|
|||||||
renderer_status_button->setDisabled(true);
|
renderer_status_button->setDisabled(true);
|
||||||
|
|
||||||
if (UISettings::values.hide_mouse || Settings::values.mouse_panning) {
|
if (UISettings::values.hide_mouse || Settings::values.mouse_panning) {
|
||||||
mouse_hide_timer.start();
|
|
||||||
render_window->installEventFilter(render_window);
|
render_window->installEventFilter(render_window);
|
||||||
render_window->setAttribute(Qt::WA_Hover, true);
|
render_window->setAttribute(Qt::WA_Hover, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (UISettings::values.hide_mouse) {
|
||||||
|
mouse_hide_timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
std::string title_name;
|
std::string title_name;
|
||||||
std::string title_version;
|
std::string title_version;
|
||||||
const auto res = system.GetGameName(title_name);
|
const auto res = system.GetGameName(title_name);
|
||||||
@ -2372,12 +2374,15 @@ void GMainWindow::OnConfigure() {
|
|||||||
if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) {
|
if ((UISettings::values.hide_mouse || Settings::values.mouse_panning) && emulation_running) {
|
||||||
render_window->installEventFilter(render_window);
|
render_window->installEventFilter(render_window);
|
||||||
render_window->setAttribute(Qt::WA_Hover, true);
|
render_window->setAttribute(Qt::WA_Hover, true);
|
||||||
mouse_hide_timer.start();
|
|
||||||
} else {
|
} else {
|
||||||
render_window->removeEventFilter(render_window);
|
render_window->removeEventFilter(render_window);
|
||||||
render_window->setAttribute(Qt::WA_Hover, false);
|
render_window->setAttribute(Qt::WA_Hover, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (UISettings::values.hide_mouse) {
|
||||||
|
mouse_hide_timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
UpdateStatusButtons();
|
UpdateStatusButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2615,8 +2620,7 @@ void GMainWindow::UpdateUISettings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::HideMouseCursor() {
|
void GMainWindow::HideMouseCursor() {
|
||||||
if (emu_thread == nullptr ||
|
if (emu_thread == nullptr && UISettings::values.hide_mouse) {
|
||||||
(!UISettings::values.hide_mouse && !Settings::values.mouse_panning)) {
|
|
||||||
mouse_hide_timer.stop();
|
mouse_hide_timer.stop();
|
||||||
ShowMouseCursor();
|
ShowMouseCursor();
|
||||||
return;
|
return;
|
||||||
@ -2626,8 +2630,7 @@ void GMainWindow::HideMouseCursor() {
|
|||||||
|
|
||||||
void GMainWindow::ShowMouseCursor() {
|
void GMainWindow::ShowMouseCursor() {
|
||||||
render_window->unsetCursor();
|
render_window->unsetCursor();
|
||||||
if (emu_thread != nullptr &&
|
if (emu_thread != nullptr && UISettings::values.hide_mouse) {
|
||||||
(UISettings::values.hide_mouse || Settings::values.mouse_panning)) {
|
|
||||||
mouse_hide_timer.start();
|
mouse_hide_timer.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,18 +35,36 @@ void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
|
|||||||
input_subsystem->GetMouse()->MouseMove(x, y, 0, 0);
|
input_subsystem->GetMouse()->MouseMove(x, y, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MouseInput::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) const {
|
||||||
|
switch (button) {
|
||||||
|
case SDL_BUTTON_LEFT:
|
||||||
|
return MouseInput::MouseButton::Left;
|
||||||
|
case SDL_BUTTON_RIGHT:
|
||||||
|
return MouseInput::MouseButton::Right;
|
||||||
|
case SDL_BUTTON_MIDDLE:
|
||||||
|
return MouseInput::MouseButton::Wheel;
|
||||||
|
case SDL_BUTTON_X1:
|
||||||
|
return MouseInput::MouseButton::Backward;
|
||||||
|
case SDL_BUTTON_X2:
|
||||||
|
return MouseInput::MouseButton::Forward;
|
||||||
|
default:
|
||||||
|
return MouseInput::MouseButton::Undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
|
void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
|
||||||
|
const auto mouse_button = SDLButtonToMouseButton(button);
|
||||||
if (button == SDL_BUTTON_LEFT) {
|
if (button == SDL_BUTTON_LEFT) {
|
||||||
if (state == SDL_PRESSED) {
|
if (state == SDL_PRESSED) {
|
||||||
TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0);
|
TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0);
|
||||||
} else {
|
} else {
|
||||||
TouchReleased(0);
|
TouchReleased(0);
|
||||||
}
|
}
|
||||||
} else if (button == SDL_BUTTON_RIGHT) {
|
} else {
|
||||||
if (state == SDL_PRESSED) {
|
if (state == SDL_PRESSED) {
|
||||||
input_subsystem->GetMouse()->PressButton(x, y, button);
|
input_subsystem->GetMouse()->PressButton(x, y, mouse_button);
|
||||||
} else {
|
} else {
|
||||||
input_subsystem->GetMouse()->ReleaseButton(button);
|
input_subsystem->GetMouse()->ReleaseButton(mouse_button);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,10 @@ namespace InputCommon {
|
|||||||
class InputSubsystem;
|
class InputSubsystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace MouseInput {
|
||||||
|
enum class MouseButton;
|
||||||
|
}
|
||||||
|
|
||||||
class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
|
class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
|
||||||
public:
|
public:
|
||||||
explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem);
|
explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem);
|
||||||
@ -42,6 +46,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);
|
||||||
|
|
||||||
|
/// Converts a SDL mouse button into MouseInput mouse button
|
||||||
|
MouseInput::MouseButton SDLButtonToMouseButton(u32 button) const;
|
||||||
|
|
||||||
/// Called by WaitEvent when a mouse button is pressed or released
|
/// Called by WaitEvent when a mouse button is pressed or released
|
||||||
void OnMouseButton(u32 button, u8 state, s32 x, s32 y);
|
void OnMouseButton(u32 button, u8 state, s32 x, s32 y);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user