From 31b3b1976bcebe17204447d94ad4cfc96c527f92 Mon Sep 17 00:00:00 2001 From: Vinicius Rangel Date: Mon, 11 Nov 2024 15:26:11 -0300 Subject: [PATCH] devices: add mouse abstraction --- CMakeLists.txt | 3 + src/core/devices/hid_device.cpp | 68 ++++++++++++++++++++ src/core/devices/hid_device.h | 30 +++++++++ src/core/devices/hid_device_mouse.cpp | 76 +++++++++++++++++++++++ src/core/devices/ioccom.h | 10 +++ src/core/libraries/kernel/file_system.cpp | 2 + src/core/libraries/kernel/libkernel.cpp | 1 - src/core/libraries/libs.cpp | 2 +- src/emulator.cpp | 34 +++++----- src/input/mouse.cpp | 8 +++ 10 files changed, 216 insertions(+), 18 deletions(-) create mode 100644 src/core/devices/hid_device.cpp create mode 100644 src/core/devices/hid_device.h create mode 100644 src/core/devices/hid_device_mouse.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index bc4d23e34..33e651a05 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -490,6 +490,9 @@ set(CORE src/core/aerolib/stubs.cpp src/core/crypto/keys.h src/core/devices/base_device.cpp src/core/devices/base_device.h + src/core/devices/hid_device.cpp + src/core/devices/hid_device.h + src/core/devices/hid_device_mouse.cpp src/core/file_format/pfs.h src/core/file_format/pkg.cpp src/core/file_format/pkg.h diff --git a/src/core/devices/hid_device.cpp b/src/core/devices/hid_device.cpp new file mode 100644 index 000000000..ce567b107 --- /dev/null +++ b/src/core/devices/hid_device.cpp @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include "common/logging/log.h" +#include "common/singleton.h" +#include "common/va_ctx.h" +#include "core/libraries/error_codes.h" +#include "hid_device.h" +#include "input/mouse.h" +#include "ioccom.h" + +namespace Core::Devices { + +struct InitHidRaw { + u32 user_id; + u32 type; + u32 _unknown2; +}; +static_assert(sizeof(InitHidRaw) == 0xC); + +constexpr auto HID_CMD_INIT_HANDLE_FOR_USER_ID = _IOW('H', 0x2, InitHidRaw); + +int HidDevice::GenericCallback(u64 cmd, Common::VaCtx* args) { + LOG_TRACE(Core_Devices, "HID({:X}) generic: ioctl cmd={:X}", handle, cmd); + if (cmd == HID_CMD_INIT_HANDLE_FOR_USER_ID) { + auto data = vaArgPtr(&args->va_list); + this->user_id = data->user_id; + if (data->type == 0) { + LOG_INFO(Core_Devices, "HID({:X}) open: type=mouse, user_id={}", handle, data->user_id); + this->m_callback = &HidDevice::MouseCallback; + // FIXME Replace by status bar + if (!Common::Singleton::Instance()->m_connected) { + using namespace ::Libraries::MsgDialog; + ShowMsgDialog(MsgDialogState(MsgDialogState::UserState{ + .type = ButtonType::YESNO, + .msg = "Game wants to use your mouse.\nDo you want to allow it?", + }), + false, [](DialogResult result) { + if (result.buttonId == ButtonId::YES) { + auto* mouse = Common::Singleton::Instance(); + mouse->m_connected = true; + } + }); + } + } else { + LOG_WARNING(Core_Devices, "HID({:X}) open: unknown type={}", handle, data->type); + } + return static_cast(handle); + } + LOG_WARNING(Core_Devices, "HID({:X}) generic: unknown ioctl cmd = {:X}", handle, cmd); + return ORBIS_KERNEL_ERROR_ENOTTY; +} + +BaseDevice* HidDevice::Create(u32 handle, const char*, int, u16) { + return new HidDevice(handle); +} + +HidDevice::HidDevice(u32 handle) : handle{handle} {} + +HidDevice::~HidDevice() = default; + +int HidDevice::ioctl(u64 cmd, Common::VaCtx* args) { + return (this->*m_callback)(cmd, args); +} + +} // namespace Core::Devices \ No newline at end of file diff --git a/src/core/devices/hid_device.h b/src/core/devices/hid_device.h new file mode 100644 index 000000000..051481ecd --- /dev/null +++ b/src/core/devices/hid_device.h @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "base_device.h" + +namespace Core::Devices { + +class HidDevice final : BaseDevice { + u32 handle; + u32 user_id{}; + + int MouseCallback(u64 cmd, Common::VaCtx* args); + + int GenericCallback(u64 cmd, Common::VaCtx* args); + + int (HidDevice::*m_callback)(u64 cmd, Common::VaCtx* args) = &HidDevice::GenericCallback; + +public: + static BaseDevice* Create(u32 handle, const char*, int, u16); + + explicit HidDevice(u32 handle); + + ~HidDevice() override; + + int ioctl(u64 cmd, Common::VaCtx* args) override; +}; + +} // namespace Core::Devices diff --git a/src/core/devices/hid_device_mouse.cpp b/src/core/devices/hid_device_mouse.cpp new file mode 100644 index 000000000..5cc256a7f --- /dev/null +++ b/src/core/devices/hid_device_mouse.cpp @@ -0,0 +1,76 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "common/singleton.h" +#include "hid_device.h" +#include "input/mouse.h" +#include "ioccom.h" + +struct MouseInfo {}; + +struct MouseDataEntry { + std::array _unknown1; + s16 x; + s16 y; + u8 buttons; + bool system_capture; + s8 wheel; + s8 tilt; + std::array _reserved; +}; + +static_assert(sizeof(MouseDataEntry) == 0x18); + +struct MouseData { + u32 handle; + std::array _unknown1; + MouseDataEntry* data; + int max_data; + std::array _unknown2; + int* read_count; +}; +static_assert(sizeof(MouseData) == 0x20); + +constexpr auto HID_CMD_READ_MOUSE_STATE = _IOW('H', 0x19, MouseData); + +namespace Core::Devices { + +int HidDevice::MouseCallback(u64 cmd, Common::VaCtx* args) { + switch (cmd) { + case HID_CMD_READ_DEVICE_INFO: { + auto info = vaArgPtr>(&args->va_list); + info->data = nullptr; + // TODO Fill data with the mouse info + return ORBIS_OK; + } + case HID_CMD_READ_MOUSE_STATE: { + auto mouse_data = vaArgPtr(&args->va_list); + auto* mouse = Common::Singleton::Instance(); + if (!mouse->m_connected) { + *mouse_data->read_count = 0; + return 0; + } + std::array states; + int total = std::min((int)states.size(), mouse_data->max_data); + total = mouse->ReadStates(states.data(), total); + for (int i = 0; i < total; ++i) { + const auto& s = states[i]; + mouse_data->data[i] = MouseDataEntry{ + .x = static_cast(s.x_axis), + .y = static_cast(s.y_axis), + .buttons = static_cast(s.button_state), + .system_capture = false, + .wheel = static_cast(s.wheel), + .tilt = static_cast(s.tilt), + }; + } + return total; + } + default: + LOG_WARNING(Core_Devices, "HID({:X}) mouse: unknown ioctl request: {:X}", handle, cmd); + return ORBIS_OK; + } +} + +} // namespace Core::Devices diff --git a/src/core/devices/ioccom.h b/src/core/devices/ioccom.h index 671ee33d4..5ce58f533 100644 --- a/src/core/devices/ioccom.h +++ b/src/core/devices/ioccom.h @@ -65,3 +65,13 @@ def parse(v): print('group', chr(v >> 8 & 0xFF)) print('num', hex(v & 0xFF)) */ + +template +struct DeviceInfo { + int handle; + std::array _pad1; + T* data; +}; +static_assert(sizeof(DeviceInfo) == 0x10); + +constexpr auto HID_CMD_READ_DEVICE_INFO = _IOW('H', 0x1, DeviceInfo); diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index f312fd5fa..4a025374f 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -14,11 +14,13 @@ #include #include +#include "core/devices/hid_device.h" using FactoryDevice = std::function; // prefix path static std::map available_device = { + {"/dev/hid", &Core::Devices::HidDevice::Create}, }; namespace Libraries::Kernel { diff --git a/src/core/libraries/kernel/libkernel.cpp b/src/core/libraries/kernel/libkernel.cpp index cc2f7a9f7..b3167a8d5 100644 --- a/src/core/libraries/kernel/libkernel.cpp +++ b/src/core/libraries/kernel/libkernel.cpp @@ -408,7 +408,6 @@ int PS4_SYSV_ABI kernel_ioctl(int fd, u64 cmd, VA_ARGS) { } VA_CTX(ctx); int result = file->device->ioctl(cmd, &ctx); - LOG_TRACE(Lib_Kernel, "ioctl: fd = {:X} cmd = {:X} result = {}", fd, cmd, result); if (result < 0) { ErrSceToPosix(result); return -1; diff --git a/src/core/libraries/libs.cpp b/src/core/libraries/libs.cpp index aa91a72af..3a359f401 100644 --- a/src/core/libraries/libs.cpp +++ b/src/core/libraries/libs.cpp @@ -90,7 +90,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) { Libraries::SharePlay::RegisterlibSceSharePlay(sym); Libraries::Remoteplay::RegisterlibSceRemoteplay(sym); Libraries::Videodec::RegisterlibSceVideodec(sym); - Libraries::Mouse::RegisterlibSceMouse(sym); + // Libraries::Mouse::RegisterlibSceMouse(sym); } } // namespace Libraries diff --git a/src/emulator.cpp b/src/emulator.cpp index d9d32ec1d..6470dcdec 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -117,10 +117,10 @@ void Emulator::Run(const std::filesystem::path& file) { auto& game_info = Common::ElfInfo::Instance(); // Loading param.sfo file if exists - std::string id; - std::string title; - std::string app_version; - u32 fw_version; + std::string id = "unknown_serial"; + std::string title = "unknown_title"; + std::string app_version = "unknown_version"; + u32 fw_version = 0x4700000; std::filesystem::path sce_sys_folder = eboot_path.parent_path() / "sce_sys"; if (std::filesystem::is_directory(sce_sys_folder)) { @@ -274,18 +274,20 @@ void Emulator::Run(const std::filesystem::path& file) { } void Emulator::LoadSystemModules(const std::filesystem::path& file, std::string game_serial) { - constexpr std::array ModulesToLoad{ - {{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2}, - {"libSceFiber.sprx", &Libraries::Fiber::RegisterlibSceFiber}, - {"libSceUlt.sprx", nullptr}, - {"libSceJson.sprx", nullptr}, - {"libSceJson2.sprx", nullptr}, - {"libSceLibcInternal.sprx", &Libraries::LibcInternal::RegisterlibSceLibcInternal}, - {"libSceDiscMap.sprx", &Libraries::DiscMap::RegisterlibSceDiscMap}, - {"libSceRtc.sprx", &Libraries::Rtc::RegisterlibSceRtc}, - {"libSceJpegEnc.sprx", nullptr}, - {"libSceRazorCpu.sprx", nullptr}, - {"libSceCesCs.sprx", nullptr}}}; + constexpr std::array ModulesToLoad{{ + {"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2}, + {"libSceFiber.sprx", &Libraries::Fiber::RegisterlibSceFiber}, + {"libSceUlt.sprx", nullptr}, + {"libSceJson.sprx", nullptr}, + {"libSceJson2.sprx", nullptr}, + {"libSceLibcInternal.sprx", &Libraries::LibcInternal::RegisterlibSceLibcInternal}, + {"libSceDiscMap.sprx", &Libraries::DiscMap::RegisterlibSceDiscMap}, + {"libSceRtc.sprx", &Libraries::Rtc::RegisterlibSceRtc}, + {"libSceJpegEnc.sprx", nullptr}, + {"libSceRazorCpu.sprx", nullptr}, + {"libSceCesCs.sprx", nullptr}, + {"libSceMouse.sprx", nullptr}, + }}; std::vector found_modules; const auto& sys_module_path = Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir); diff --git a/src/input/mouse.cpp b/src/input/mouse.cpp index afc2a8750..f4373075d 100644 --- a/src/input/mouse.cpp +++ b/src/input/mouse.cpp @@ -12,10 +12,18 @@ GameMouse::GameMouse() { } int GameMouse::ReadStates(MouseState* states, int states_num) { + if (states_num == 0) { + return 0; + } std::scoped_lock lock{m_mutex}; const u32 count = std::min(m_states_num, u32(states_num)); + if (count == 0) { + states[0] = m_last_state; + return 1; + } + u32 begin = (m_index - m_states_num + 1) % MAX_MOUSE_STATES; for (u32 i = 0; i < count; i++) { u32 idx = (begin + i) % MAX_MOUSE_STATES;