diff --git a/rpcs3/Emu/Cell/Modules/cellMouse.cpp b/rpcs3/Emu/Cell/Modules/cellMouse.cpp index a76e1df342..53681daa16 100644 --- a/rpcs3/Emu/Cell/Modules/cellMouse.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMouse.cpp @@ -4,6 +4,9 @@ #include "Emu/Cell/PPUModule.h" #include "Emu/Io/MouseHandler.h" + +#include "Utilities/sema.h" + #include "cellMouse.h" extern logs::channel sys_io; @@ -159,6 +162,8 @@ s32 cellMouseGetData(u32 port_no, vm::ptr data) return CELL_MOUSE_ERROR_INVALID_PARAMETER; } + semaphore_lock lock(handler->mutex); + const MouseInfo& current_info = handler->GetInfo(); if (port_no >= handler->GetMice().size() || current_info.status[port_no] != CELL_MOUSE_STATUS_CONNECTED) @@ -168,7 +173,15 @@ s32 cellMouseGetData(u32 port_no, vm::ptr data) // TODO: check if (current_info.mode[port_no] != CELL_MOUSE_INFO_TABLET_MOUSE_MODE) has any impact - MouseData& current_data = handler->GetDataList(port_no).front(); + MouseDataList& data_list = handler->GetDataList(port_no); + + if (data_list.size() == 0) + { + *data = {}; + return CELL_OK; + } + + const MouseData current_data = data_list.front(); data->update = current_data.update; data->buttons = current_data.buttons; data->x_axis = current_data.x_axis; @@ -176,10 +189,7 @@ s32 cellMouseGetData(u32 port_no, vm::ptr data) data->wheel = current_data.wheel; data->tilt = current_data.tilt; - current_data.update = CELL_MOUSE_DATA_NON; - current_data.x_axis = 0; - current_data.y_axis = 0; - current_data.wheel = 0; + data_list.pop_front(); return CELL_OK; } @@ -200,6 +210,8 @@ s32 cellMouseGetDataList(u32 port_no, vm::ptr data) return CELL_MOUSE_ERROR_INVALID_PARAMETER; } + semaphore_lock lock(handler->mutex); + const MouseInfo& current_info = handler->GetInfo(); if (port_no >= handler->GetMice().size() || current_info.status[port_no] != CELL_MOUSE_STATUS_CONNECTED) @@ -221,13 +233,10 @@ s32 cellMouseGetDataList(u32 port_no, vm::ptr data) data->list[i].y_axis = it->y_axis; data->list[i].wheel = it->wheel; data->list[i].tilt = it->tilt; - - it->update = CELL_MOUSE_DATA_NON; - it->x_axis = 0; - it->y_axis = 0; - it->wheel = 0; } + list.clear(); + return CELL_OK; } diff --git a/rpcs3/Emu/Io/MouseHandler.h b/rpcs3/Emu/Io/MouseHandler.h index 3663d4ab87..6d6e6dbf2d 100644 --- a/rpcs3/Emu/Io/MouseHandler.h +++ b/rpcs3/Emu/Io/MouseHandler.h @@ -1,6 +1,7 @@ #pragma once #include +#include "Utilities/sema.h" // TODO: HLE info (constants, structs, etc.) should not be available here @@ -108,6 +109,7 @@ struct Mouse { s16 x_pos; s16 y_pos; + u8 buttons; // actual mouse button positions MouseTabletDataList m_tablet_datalist; MouseDataList m_datalist; @@ -127,14 +129,32 @@ class MouseHandlerBase protected: MouseInfo m_info; std::vector m_mice; + std::chrono::steady_clock::time_point last_update; + + bool is_time_for_update(double elapsed_time = 10.0) // 4-10 ms, let's use 10 for now + { + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + double elapsed = std::chrono::duration_cast(now - last_update).count() / 1000.0; + + if (elapsed > elapsed_time) + { + last_update = now; + return true; + } + return false; + } public: + semaphore<> mutex; + virtual void Init(const u32 max_connect) = 0; virtual ~MouseHandlerBase() = default; void Button(u8 button, bool pressed) { - for(u32 p=0; p < (u32)m_mice.size(); ++p) + semaphore_lock lock(mutex); + + for (u32 p = 0; p < (u32)m_mice.size(); ++p) { if (m_info.status[p] != CELL_MOUSE_STATUS_CONNECTED) { @@ -148,13 +168,14 @@ public: datalist.pop_front(); } + if (pressed) + m_mice[p].buttons |= button; + else + m_mice[p].buttons &= ~button; + MouseData new_data; new_data.update = CELL_MOUSE_DATA_UPDATE; - - if (pressed) - new_data.buttons |= button; - else - new_data.buttons &= ~button; + new_data.buttons = m_mice[p].buttons; datalist.push_back(new_data); } @@ -162,7 +183,9 @@ public: void Scroll(const s8 rotation) { - for(u32 p=0; p < (u32)m_mice.size(); ++p) + semaphore_lock lock(mutex); + + for (u32 p = 0; p < (u32)m_mice.size(); ++p) { if (m_info.status[p] != CELL_MOUSE_STATUS_CONNECTED) { @@ -179,14 +202,17 @@ public: MouseData new_data; new_data.update = CELL_MOUSE_DATA_UPDATE; new_data.wheel = rotation / 120; //120=event.GetWheelDelta() + new_data.buttons = m_mice[p].buttons; datalist.push_back(new_data); } } - void Move(const s16 x_pos_new, const s16 y_pos_new) + void Move(const s32 x_pos_new, const s32 y_pos_new, bool is_qt_fullscreen = false) { - for(u32 p=0; p < (u32)m_mice.size(); ++p) + semaphore_lock lock(mutex); + + for (u32 p = 0; p < (u32)m_mice.size(); ++p) { if (m_info.status[p] != CELL_MOUSE_STATUS_CONNECTED) { @@ -202,11 +228,21 @@ public: MouseData new_data; new_data.update = CELL_MOUSE_DATA_UPDATE; - new_data.x_axis += x_pos_new - m_mice[p].x_pos; - new_data.y_axis += y_pos_new - m_mice[p].y_pos; + new_data.buttons = m_mice[p].buttons; - m_mice[p].x_pos = x_pos_new; - m_mice[p].y_pos = y_pos_new; + if (is_qt_fullscreen) + { + new_data.x_axis = static_cast(std::clamp(x_pos_new, -127, 128)); + new_data.y_axis = static_cast(std::clamp(y_pos_new, -127, 128)); + } + else + { + new_data.x_axis = static_cast(std::clamp(x_pos_new - m_mice[p].x_pos, -127, 128)); + new_data.y_axis = static_cast(std::clamp(y_pos_new - m_mice[p].y_pos, -127, 128)); + + m_mice[p].x_pos = x_pos_new; + m_mice[p].y_pos = y_pos_new; + } /*CellMouseRawData& rawdata = GetRawData(p); rawdata.data[rawdata.len % CELL_MOUSE_MAX_CODES] = 0; // (TODO) diff --git a/rpcs3/basic_mouse_handler.cpp b/rpcs3/basic_mouse_handler.cpp index bef461f3e1..babe75eb51 100644 --- a/rpcs3/basic_mouse_handler.cpp +++ b/rpcs3/basic_mouse_handler.cpp @@ -1,6 +1,7 @@ #include "basic_mouse_handler.h" #include +#include void basic_mouse_handler::Init(const u32 max_connect) { @@ -83,11 +84,22 @@ void basic_mouse_handler::MouseButtonUp(QMouseEvent* event) void basic_mouse_handler::MouseScroll(QWheelEvent* event) { - // Woo lads, Qt handles multidimensional scrolls. Just gonna grab the x for now. Not sure if this works. TODO: Test - MouseHandlerBase::Scroll(event->angleDelta().x()); + MouseHandlerBase::Scroll(event->angleDelta().y()); } void basic_mouse_handler::MouseMove(QMouseEvent* event) { - MouseHandlerBase::Move(event->x(), event->y()); + if (is_time_for_update()) + { + if (m_target && m_target->visibility() == QWindow::Visibility::FullScreen) + { + QPoint p_delta = m_target->geometry().topLeft() + QPoint(m_target->width() / 2, m_target->height() / 2); + QCursor::setPos(p_delta); + MouseHandlerBase::Move(event->x() - p_delta.x(), event->y() - p_delta.y(), true); + } + else + { + MouseHandlerBase::Move(event->x(), event->y()); + } + } }