From 27820f037169c86695ae9251fd35038e6962e100 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Thu, 7 Jun 2018 09:59:27 +0200 Subject: [PATCH] cellMouse: improvements --- rpcs3/Emu/Cell/Modules/cellMouse.cpp | 248 +++++++++++++++++++++++---- rpcs3/Emu/Cell/Modules/cellMouse.h | 33 ++-- rpcs3/Emu/Io/MouseHandler.h | 118 +++++++++---- rpcs3/basic_mouse_handler.cpp | 7 +- 4 files changed, 329 insertions(+), 77 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellMouse.cpp b/rpcs3/Emu/Cell/Modules/cellMouse.cpp index 33cd10ee8c..a76e1df342 100644 --- a/rpcs3/Emu/Cell/Modules/cellMouse.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMouse.cpp @@ -12,14 +12,21 @@ s32 cellMouseInit(u32 max_connect) { sys_io.warning("cellMouseInit(max_connect=%d)", max_connect); - const auto handler = fxm::import(Emu.GetCallbacks().get_mouse_handler); + auto handler = fxm::get(); - if (!handler) + if (handler) { return CELL_MOUSE_ERROR_ALREADY_INITIALIZED; } + if (max_connect == 0 || max_connect > CELL_MAX_MICE) + { + return CELL_MOUSE_ERROR_INVALID_PARAMETER; + } + + handler = fxm::import(Emu.GetCallbacks().get_mouse_handler); handler->Init(std::min(max_connect, 7u)); + return CELL_OK; } @@ -34,12 +41,28 @@ s32 cellMouseClearBuf(u32 port_no) return CELL_MOUSE_ERROR_UNINITIALIZED; } - if (port_no >= handler->GetMice().size()) + if (port_no >= CELL_MAX_MICE) { return CELL_MOUSE_ERROR_INVALID_PARAMETER; } - //? + const MouseInfo& current_info = handler->GetInfo(); + + if (port_no >= handler->GetMice().size() || current_info.status[port_no] != CELL_MOUSE_STATUS_CONNECTED) + { + return CELL_MOUSE_ERROR_NO_DEVICE; + } + + handler->GetDataList(port_no).clear(); + handler->GetTabletDataList(port_no).clear(); + + MouseRawData& raw_data = handler->GetRawData(port_no); + raw_data.len = 0; + + for (int i = 0; i < CELL_MOUSE_MAX_CODES; i++) + { + raw_data.data[i] = 0; + } return CELL_OK; } @@ -67,6 +90,11 @@ s32 cellMouseGetInfo(vm::ptr info) return CELL_MOUSE_ERROR_UNINITIALIZED; } + if (!info) + { + return CELL_MOUSE_ERROR_INVALID_PARAMETER; + } + const MouseInfo& current_info = handler->GetInfo(); info->max_connect = current_info.max_connect; info->now_connect = current_info.now_connect; @@ -89,13 +117,28 @@ s32 cellMouseInfoTabletMode(u32 port_no, vm::ptr info) return CELL_MOUSE_ERROR_UNINITIALIZED; } - if (port_no >= handler->GetMice().size()) + // only check for port_no here. Tests show that valid ports lead to ERROR_FATAL with disconnected devices regardless of info + if (port_no >= CELL_MAX_MICE) { return CELL_MOUSE_ERROR_INVALID_PARAMETER; } - info->is_supported = 0; // Unimplemented: (0=Tablet mode is not supported) - info->mode = 1; // Unimplemented: (1=Mouse mode) + const MouseInfo& current_info = handler->GetInfo(); + + if (port_no >= handler->GetMice().size() || current_info.status[port_no] != CELL_MOUSE_STATUS_CONNECTED) + { + return CELL_MOUSE_ERROR_FATAL; + } + + if (!info) + { + return CELL_EFAULT; // we don't get CELL_MOUSE_ERROR_INVALID_PARAMETER here :thonkang: + } + + info->is_supported = current_info.tablet_is_supported[port_no]; + info->mode = current_info.mode[port_no]; + + // TODO: decr returns CELL_ENOTSUP ... How should we handle this? return CELL_OK; } @@ -111,12 +154,21 @@ s32 cellMouseGetData(u32 port_no, vm::ptr data) return CELL_MOUSE_ERROR_UNINITIALIZED; } - if (port_no >= handler->GetMice().size()) + if (port_no >= CELL_MAX_MICE || !data) + { + return CELL_MOUSE_ERROR_INVALID_PARAMETER; + } + + const MouseInfo& current_info = handler->GetInfo(); + + if (port_no >= handler->GetMice().size() || current_info.status[port_no] != CELL_MOUSE_STATUS_CONNECTED) { return CELL_MOUSE_ERROR_NO_DEVICE; } - MouseData& current_data = handler->GetData(port_no); + // 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(); data->update = current_data.update; data->buttons = current_data.buttons; data->x_axis = current_data.x_axis; @@ -134,33 +186,7 @@ s32 cellMouseGetData(u32 port_no, vm::ptr data) s32 cellMouseGetDataList(u32 port_no, vm::ptr data) { - sys_io.todo("cellMouseGetDataList(port_no=%d, data=0x%x)", port_no, data); - if (g_cfg.io.mouse == mouse_handler::null) - return CELL_MOUSE_ERROR_NO_DEVICE; - else - { - data->list_num = 0; - return CELL_OK; - } -} - -s32 cellMouseSetTabletMode(u32 port_no, u32 mode) -{ - UNIMPLEMENTED_FUNC(sys_io); - - return CELL_OK; -} - -s32 cellMouseGetTabletDataList(u32 port_no, u32 data_addr) -{ - UNIMPLEMENTED_FUNC(sys_io); - - return CELL_OK; -} - -s32 cellMouseGetRawData(u32 port_no, vm::ptr data) -{ - sys_io.todo("cellMouseGetRawData(port_no=%d, data=*0x%x)", port_no, data); + sys_io.warning("cellMouseGetDataList(port_no=%d, data=0x%x)", port_no, data); const auto handler = fxm::get(); @@ -169,11 +195,159 @@ s32 cellMouseGetRawData(u32 port_no, vm::ptr data) return CELL_MOUSE_ERROR_UNINITIALIZED; } - if (port_no >= handler->GetMice().size()) + if (port_no >= CELL_MAX_MICE || !data) + { + return CELL_MOUSE_ERROR_INVALID_PARAMETER; + } + + const MouseInfo& current_info = handler->GetInfo(); + + if (port_no >= handler->GetMice().size() || current_info.status[port_no] != CELL_MOUSE_STATUS_CONNECTED) { return CELL_MOUSE_ERROR_NO_DEVICE; } + // TODO: check if (current_info.mode[port_no] != CELL_MOUSE_INFO_TABLET_MOUSE_MODE) has any impact + + auto& list = handler->GetDataList(port_no); + data->list_num = std::min((u32)CELL_MOUSE_MAX_DATA_LIST_NUM, (u32)list.size()); + + int i = 0; + for (auto it = list.begin(); it != list.end() && i < CELL_MOUSE_MAX_DATA_LIST_NUM; ++it, ++i) + { + data->list[i].update = it->update; + data->list[i].buttons = it->buttons; + data->list[i].x_axis = it->x_axis; + 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; + } + + return CELL_OK; +} + +s32 cellMouseSetTabletMode(u32 port_no, u32 mode) +{ + sys_io.warning("cellMouseSetTabletMode(port_no=%d, mode=%d)", port_no, mode); + + const auto handler = fxm::get(); + + if (!handler) + { + return CELL_MOUSE_ERROR_UNINITIALIZED; + } + + // only check for port_no here. Tests show that valid ports lead to ERROR_FATAL with disconnected devices regardless of info + if (port_no >= CELL_MAX_MICE) + { + return CELL_MOUSE_ERROR_INVALID_PARAMETER; + } + + MouseInfo& current_info = handler->GetInfo(); + + if (port_no >= handler->GetMice().size() || current_info.status[port_no] != CELL_MOUSE_STATUS_CONNECTED) + { + return CELL_MOUSE_ERROR_FATAL; + } + + if (mode != CELL_MOUSE_INFO_TABLET_MOUSE_MODE && mode != CELL_MOUSE_INFO_TABLET_TABLET_MODE) + { + return CELL_EINVAL; // lol... why not CELL_MOUSE_ERROR_INVALID_PARAMETER. Sony is drunk + } + + current_info.mode[port_no] = mode; + + // TODO: decr returns CELL_ENOTSUP ... How should we handle this? + + return CELL_OK; +} + +s32 cellMouseGetTabletDataList(u32 port_no, vm::ptr data) +{ + sys_io.warning("cellMouseGetTabletDataList(port_no=%d, data=0x%x)", port_no, data); + + const auto handler = fxm::get(); + + if (!handler) + { + return CELL_MOUSE_ERROR_UNINITIALIZED; + } + + if (port_no >= CELL_MAX_MICE || !data) + { + return CELL_MOUSE_ERROR_INVALID_PARAMETER; + } + + const MouseInfo& current_info = handler->GetInfo(); + + if (port_no >= handler->GetMice().size() || current_info.status[port_no] != CELL_MOUSE_STATUS_CONNECTED) + { + return CELL_MOUSE_ERROR_NO_DEVICE; + } + + // TODO: decr tests show that CELL_MOUSE_ERROR_DATA_READ_FAILED is returned when a mouse is connected + // TODO: check if (current_info.mode[port_no] != CELL_MOUSE_INFO_TABLET_TABLET_MODE) has any impact + + auto& list = handler->GetTabletDataList(port_no); + data->list_num = std::min((u32)CELL_MOUSE_MAX_DATA_LIST_NUM, (u32)list.size()); + + int i = 0; + for (auto it = list.begin(); it != list.end() && i < CELL_MOUSE_MAX_DATA_LIST_NUM; ++it, ++i) + { + data->list[i].len = it->len; + it->len = 0; + + for (int k = 0; k < CELL_MOUSE_MAX_CODES; k++) + { + data->list[i].data[k] = it->data[k]; + it->data[k] = 0; + } + } + + return CELL_OK; +} + +s32 cellMouseGetRawData(u32 port_no, vm::ptr data) +{ + sys_io.warning("cellMouseGetRawData(port_no=%d, data=*0x%x)", port_no, data); + + const auto handler = fxm::get(); + + if (!handler) + { + return CELL_MOUSE_ERROR_UNINITIALIZED; + } + + if (port_no >= CELL_MAX_MICE || !data) + { + return CELL_MOUSE_ERROR_INVALID_PARAMETER; + } + + const MouseInfo& current_info = handler->GetInfo(); + + if (port_no >= handler->GetMice().size() || current_info.status[port_no] != CELL_MOUSE_STATUS_CONNECTED) + { + return CELL_MOUSE_ERROR_NO_DEVICE; + } + + // TODO: decr tests show that CELL_MOUSE_ERROR_DATA_READ_FAILED is returned when a mouse is connected + // TODO: check if (current_info.mode[port_no] != CELL_MOUSE_INFO_TABLET_MOUSE_MODE) has any impact + + MouseRawData& current_data = handler->GetRawData(port_no); + data->len = current_data.len; + current_data.len = 0; + + for (int i = 0; i < CELL_MOUSE_MAX_CODES; i++) + { + data->data[i] = current_data.data[i]; + current_data.data[i] = 0; + } + return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellMouse.h b/rpcs3/Emu/Cell/Modules/cellMouse.h index e407003814..eca0759d89 100644 --- a/rpcs3/Emu/Cell/Modules/cellMouse.h +++ b/rpcs3/Emu/Cell/Modules/cellMouse.h @@ -4,17 +4,22 @@ enum { - CELL_MOUSE_ERROR_FATAL = 0x80121201, - CELL_MOUSE_ERROR_INVALID_PARAMETER = 0x80121202, - CELL_MOUSE_ERROR_ALREADY_INITIALIZED = 0x80121203, - CELL_MOUSE_ERROR_UNINITIALIZED = 0x80121204, + CELL_MOUSE_ERROR_FATAL = 0x80121201, + CELL_MOUSE_ERROR_INVALID_PARAMETER = 0x80121202, + CELL_MOUSE_ERROR_ALREADY_INITIALIZED = 0x80121203, + CELL_MOUSE_ERROR_UNINITIALIZED = 0x80121204, CELL_MOUSE_ERROR_RESOURCE_ALLOCATION_FAILED = 0x80121205, - CELL_MOUSE_ERROR_DATA_READ_FAILED = 0x80121206, - CELL_MOUSE_ERROR_NO_DEVICE = 0x80121207, - CELL_MOUSE_ERROR_SYS_SETTING_FAILED = 0x80121208, + CELL_MOUSE_ERROR_DATA_READ_FAILED = 0x80121206, + CELL_MOUSE_ERROR_NO_DEVICE = 0x80121207, + CELL_MOUSE_ERROR_SYS_SETTING_FAILED = 0x80121208, }; -static const u32 CELL_MAX_MICE = 127; +enum +{ + CELL_MOUSE_MAX_DATA_LIST_NUM = 8, + CELL_MOUSE_MAX_CODES = 64, + CELL_MAX_MICE = 127, +}; struct CellMouseInfo { @@ -42,7 +47,11 @@ struct CellMouseData s8 tilt; }; -static const u32 CELL_MOUSE_MAX_DATA_LIST_NUM = 8; +struct CellMouseTabletData +{ + be_t len; + u8 data[CELL_MOUSE_MAX_CODES]; +}; struct CellMouseDataList { @@ -50,7 +59,11 @@ struct CellMouseDataList CellMouseData list[CELL_MOUSE_MAX_DATA_LIST_NUM]; }; -static const u32 CELL_MOUSE_MAX_CODES = 64; +struct CellMouseTabletDataList +{ + be_t list_num; + CellMouseTabletData list[CELL_MOUSE_MAX_DATA_LIST_NUM]; +}; struct CellMouseRawData { diff --git a/rpcs3/Emu/Io/MouseHandler.h b/rpcs3/Emu/Io/MouseHandler.h index 8d82d33aa8..3663d4ab87 100644 --- a/rpcs3/Emu/Io/MouseHandler.h +++ b/rpcs3/Emu/Io/MouseHandler.h @@ -1,7 +1,20 @@ #pragma once +#include + // TODO: HLE info (constants, structs, etc.) should not be available here +enum +{ + // is_supported + CELL_MOUSE_INFO_TABLET_NOT_SUPPORTED = 0, + CELL_MOUSE_INFO_TABLET_SUPPORTED = 1, + + // mode + CELL_MOUSE_INFO_TABLET_MOUSE_MODE = 1, + CELL_MOUSE_INFO_TABLET_TABLET_MODE = 2, +}; + enum MousePortStatus { CELL_MOUSE_STATUS_DISCONNECTED = 0x00000000, @@ -35,6 +48,8 @@ struct MouseInfo u32 max_connect; u32 now_connect; u32 info; + u32 mode[MAX_MICE]; // TODO: tablet support + u32 tablet_is_supported[MAX_MICE]; // TODO: tablet support u16 vendor_id[MAX_MICE]; u16 product_id[MAX_MICE]; u8 status[MAX_MICE]; @@ -71,27 +86,35 @@ struct MouseData } }; -struct MouseDataList +struct MouseTabletData { - u32 list_num; - MouseData list[MOUSE_MAX_DATA_LIST_NUM]; + s32 len; + u8 data[MOUSE_MAX_CODES]; - MouseDataList() - : list_num(0) + MouseTabletData() + : len(0) { + for (auto d : data) + { + d = 0; + } } }; +using MouseTabletDataList = std::list; +using MouseDataList = std::list; + struct Mouse { s16 x_pos; s16 y_pos; - MouseData m_data; + MouseTabletDataList m_tablet_datalist; + MouseDataList m_datalist; MouseRawData m_rawdata; Mouse() - : m_data() + : m_datalist() , m_rawdata() { x_pos = 0; @@ -113,13 +136,27 @@ public: { for(u32 p=0; p < (u32)m_mice.size(); ++p) { - if (m_info.status[p] == CELL_MOUSE_STATUS_CONNECTED) + if (m_info.status[p] != CELL_MOUSE_STATUS_CONNECTED) { - MouseData& data = GetData(p); - data.update = CELL_MOUSE_DATA_UPDATE; - if (pressed) data.buttons |= button; - else data.buttons &= ~button; + continue; } + + MouseDataList& datalist = GetDataList(p); + + if (datalist.size() > MOUSE_MAX_DATA_LIST_NUM) + { + datalist.pop_front(); + } + + MouseData new_data; + new_data.update = CELL_MOUSE_DATA_UPDATE; + + if (pressed) + new_data.buttons |= button; + else + new_data.buttons &= ~button; + + datalist.push_back(new_data); } } @@ -127,12 +164,23 @@ public: { for(u32 p=0; p < (u32)m_mice.size(); ++p) { - if (m_info.status[p] == CELL_MOUSE_STATUS_CONNECTED) + if (m_info.status[p] != CELL_MOUSE_STATUS_CONNECTED) { - MouseData& data = GetData(p); - data.update = CELL_MOUSE_DATA_UPDATE; - data.wheel = rotation/120; //120=event.GetWheelDelta() + continue; } + + MouseDataList& datalist = GetDataList(p); + + if (datalist.size() > MOUSE_MAX_DATA_LIST_NUM) + { + datalist.pop_front(); + } + + MouseData new_data; + new_data.update = CELL_MOUSE_DATA_UPDATE; + new_data.wheel = rotation / 120; //120=event.GetWheelDelta() + + datalist.push_back(new_data); } } @@ -140,25 +188,37 @@ public: { for(u32 p=0; p < (u32)m_mice.size(); ++p) { - if (m_info.status[p] == CELL_MOUSE_STATUS_CONNECTED) + if (m_info.status[p] != CELL_MOUSE_STATUS_CONNECTED) { - MouseData& data = GetData(p); - data.update = CELL_MOUSE_DATA_UPDATE; - data.x_axis += x_pos_new - m_mice[p].x_pos; - data.y_axis += y_pos_new - m_mice[p].y_pos; - - 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) - rawdata.len++;*/ + continue; } + + MouseDataList& datalist = GetDataList(p); + + if (datalist.size() > MOUSE_MAX_DATA_LIST_NUM) + { + datalist.pop_front(); + } + + 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; + + 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) + rawdata.len++;*/ + + datalist.push_back(new_data); } } MouseInfo& GetInfo() { return m_info; } std::vector& GetMice() { return m_mice; } - MouseData& GetData(const u32 mouse) { return m_mice[mouse].m_data; } + MouseDataList& GetDataList(const u32 mouse) { return m_mice[mouse].m_datalist; } + MouseTabletDataList& GetTabletDataList(const u32 mouse) { return m_mice[mouse].m_tablet_datalist; } MouseRawData& GetRawData(const u32 mouse) { return m_mice[mouse].m_rawdata; } }; diff --git a/rpcs3/basic_mouse_handler.cpp b/rpcs3/basic_mouse_handler.cpp index cb17e01e61..bef461f3e1 100644 --- a/rpcs3/basic_mouse_handler.cpp +++ b/rpcs3/basic_mouse_handler.cpp @@ -9,8 +9,13 @@ void basic_mouse_handler::Init(const u32 max_connect) m_info.max_connect = max_connect; m_info.now_connect = std::min(m_mice.size(), (size_t)max_connect); m_info.info = 0; // Ownership of mouse data: 0=Application, 1=System + for (u32 i = 1; i < max_connect; i++) + { + m_info.status[i] = CELL_MOUSE_STATUS_DISCONNECTED; + m_info.mode[i] = CELL_MOUSE_INFO_TABLET_MOUSE_MODE; + m_info.tablet_is_supported[i] = CELL_MOUSE_INFO_TABLET_NOT_SUPPORTED; + } m_info.status[0] = CELL_MOUSE_STATUS_CONNECTED; // (TODO: Support for more mice) - for (u32 i = 1; i