mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-07-10 02:04:42 -06:00
sceMouse HLE (#4568)
* libSceMouse HLE v1 * fix getting event device id, init lib, logging * rest of the mouse events * lol how did it take me this long to notice this * stop the hidden mouse from clicking on random shit * yet another mouse state bug * Implement merged mode * Move RingBufferQueue to common/ * sir clang offnir, the all-formatting * config option for this * review comments
This commit is contained in:
parent
1785b98fbf
commit
d54e6b07f5
@ -494,6 +494,9 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
|
||||
src/core/libraries/razor_cpu/razor_cpu.h
|
||||
src/core/libraries/mouse/mouse.cpp
|
||||
src/core/libraries/mouse/mouse.h
|
||||
src/core/libraries/mouse/mouse_error.h
|
||||
src/core/libraries/mouse/sdl_mouse.cpp
|
||||
src/core/libraries/mouse/sdl_mouse.h
|
||||
src/core/libraries/web_browser_dialog/webbrowserdialog.cpp
|
||||
src/core/libraries/web_browser_dialog/webbrowserdialog.h
|
||||
src/core/libraries/font/font.cpp
|
||||
|
||||
45
src/common/ring_buffer_queue.h
Normal file
45
src/common/ring_buffer_queue.h
Normal file
@ -0,0 +1,45 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "common/types.h"
|
||||
|
||||
template <class T>
|
||||
class RingBufferQueue {
|
||||
public:
|
||||
RingBufferQueue(u64 size) : m_storage(size) {}
|
||||
|
||||
void Push(T item) {
|
||||
const u64 index = (m_begin + m_size) % m_storage.size();
|
||||
m_storage[index] = std::move(item);
|
||||
if (m_size < m_storage.size()) {
|
||||
m_size += 1;
|
||||
} else {
|
||||
m_begin = (m_begin + 1) % m_storage.size();
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<T> Pop() {
|
||||
if (m_size == 0) {
|
||||
return {};
|
||||
}
|
||||
const u64 index = m_begin;
|
||||
m_begin = (m_begin + 1) % m_storage.size();
|
||||
m_size -= 1;
|
||||
return std::move(m_storage[index]);
|
||||
}
|
||||
|
||||
std::optional<T> Peek() {
|
||||
if (m_size == 0) {
|
||||
return {};
|
||||
}
|
||||
return m_storage[m_begin];
|
||||
}
|
||||
|
||||
private:
|
||||
u64 m_begin = 0;
|
||||
u64 m_size = 0;
|
||||
std::vector<T> m_storage;
|
||||
};
|
||||
@ -296,6 +296,7 @@ struct InputSettings {
|
||||
Setting<bool> ime_url_mail_short_panel{false}; // specific
|
||||
Setting<bool> is_circle_enter{false}; // specific
|
||||
Setting<s32> camera_id{-1};
|
||||
Setting<bool> use_mice_as_mice{false};
|
||||
|
||||
std::vector<OverrideItem> GetOverrideableFields() const {
|
||||
return std::vector<OverrideItem>{
|
||||
@ -312,7 +313,8 @@ struct InputSettings {
|
||||
make_override<InputSettings>("ime_url_mail_short_panel",
|
||||
&InputSettings::ime_url_mail_short_panel),
|
||||
make_override<InputSettings>("is_circle_enter", &InputSettings::is_circle_enter),
|
||||
make_override<InputSettings>("camera_id", &InputSettings::camera_id)};
|
||||
make_override<InputSettings>("camera_id", &InputSettings::camera_id),
|
||||
make_override<InputSettings>("use_mice_as_mice", &InputSettings::use_mice_as_mice)};
|
||||
}
|
||||
};
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(InputSettings, cursor_state, cursor_hide_timeout,
|
||||
@ -320,7 +322,7 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(InputSettings, cursor_state, cursor_hide_time
|
||||
motion_controls_enabled, use_unified_input_config,
|
||||
default_controller_id, background_controller_input,
|
||||
ime_accessibility_enabled, ime_url_mail_short_panel, camera_id,
|
||||
is_circle_enter)
|
||||
is_circle_enter, use_mice_as_mice)
|
||||
// -------------------------------
|
||||
// Audio settings
|
||||
// -------------------------------
|
||||
@ -683,6 +685,7 @@ public:
|
||||
SETTING_FORWARD_BOOL(m_input, UseUnifiedInputConfig, use_unified_input_config)
|
||||
SETTING_FORWARD(m_input, CameraId, camera_id)
|
||||
SETTING_FORWARD_BOOL(m_input, CircleEnter, is_circle_enter)
|
||||
SETTING_FORWARD_BOOL(m_input, MiceUsedAsMice, use_mice_as_mice)
|
||||
|
||||
// Vulkan settings
|
||||
SETTING_FORWARD(m_vulkan, GpuId, gpu_id)
|
||||
|
||||
@ -1,15 +1,26 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Generated By moduleGenerator
|
||||
#include "SDL3/SDL_mouse.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/user_settings.h"
|
||||
#include "mouse.h"
|
||||
#include "mouse_error.h"
|
||||
#include "sdl_window.h"
|
||||
|
||||
extern Frontend::WindowSDL* g_window;
|
||||
|
||||
namespace Libraries::Mouse {
|
||||
|
||||
int PS4_SYSV_ABI sceMouseClose() {
|
||||
RingBufferQueue<OrbisMouseData> mouse_states[2]{{64}, {64}};
|
||||
s32 mouse_handles[2]{-1, -1};
|
||||
s32 mouse_sdl_handles[2]{-1, -1};
|
||||
bool g_lib_init = false, g_is_merged_mode = false;
|
||||
|
||||
int PS4_SYSV_ABI sceMouseClose(s32 handle) {
|
||||
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
@ -45,7 +56,16 @@ int PS4_SYSV_ABI sceMouseGetDeviceInfo() {
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceMouseInit() {
|
||||
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||
SDL_WarpMouseInWindow(g_window->GetSDLWindow(), 1, 1);
|
||||
SDL_SetWindowRelativeMouseMode(g_window->GetSDLWindow(), true);
|
||||
int micecount = 0;
|
||||
auto micelist = SDL_GetMice(&micecount);
|
||||
LOG_INFO(Input, "{} mice are currently connected", micecount);
|
||||
for (int i = 0; i < micecount; i++) {
|
||||
LOG_INFO(Lib_Mouse, "{}: {} id: {}", i, SDL_GetMouseNameForID(micelist[i]), micelist[i]);
|
||||
}
|
||||
SDL_free(micelist);
|
||||
g_lib_init = true;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
@ -54,14 +74,47 @@ int PS4_SYSV_ABI sceMouseMbusInit() {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceMouseOpen() {
|
||||
LOG_ERROR(Lib_Mouse, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceMouseOpen(Libraries::UserService::OrbisUserServiceUserId userId, s32 type,
|
||||
s32 index, OrbisMouseOpenParam* pParam) {
|
||||
LOG_WARNING(Lib_Mouse, "(DUMMY) called, uid: {}, type: {}, index: {}", userId, type, index);
|
||||
auto u = UserManagement.GetUserByID(userId);
|
||||
if (!u || !pParam || (u8)pParam->flag > 1 || index < 0 || index > 1) {
|
||||
LOG_ERROR(Lib_Mouse, "invalid argument");
|
||||
return ORBIS_MOUSE_ERROR_INVALID_ARG;
|
||||
}
|
||||
if (pParam->flag == MouseOpenBehaviour::Merged && index != 0) {
|
||||
LOG_ERROR(Lib_Mouse, "Only one mouse can be opened in merged mode!");
|
||||
return ORBIS_MOUSE_ERROR_ALREADY_OPENED;
|
||||
}
|
||||
g_is_merged_mode = pParam->flag == MouseOpenBehaviour::Merged;
|
||||
if (mouse_handles[index] != -1) {
|
||||
LOG_ERROR(Lib_Mouse, "already opened");
|
||||
return ORBIS_MOUSE_ERROR_ALREADY_OPENED;
|
||||
}
|
||||
mouse_handles[index] = index;
|
||||
LOG_INFO(Lib_Mouse, "out handle: {}", mouse_handles[index]);
|
||||
return mouse_handles[index];
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceMouseRead() {
|
||||
LOG_DEBUG(Lib_Mouse, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
int PS4_SYSV_ABI sceMouseRead(s32 handle, OrbisMouseData* pData, s32 num) {
|
||||
LOG_DEBUG(Lib_Mouse, "(DUMMY) called, h: {}, n: {}", handle, num);
|
||||
if (!pData || num > 64) {
|
||||
return ORBIS_MOUSE_ERROR_INVALID_ARG;
|
||||
}
|
||||
if (mouse_handles[0] != handle && mouse_handles[1] != handle) {
|
||||
return ORBIS_MOUSE_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
u64 m = mouse_handles[0] == handle ? 0 : 1;
|
||||
int i = 0;
|
||||
for (; i < num; i++) {
|
||||
std::optional<OrbisMouseData> st = mouse_states[m].Pop();
|
||||
if (!st) {
|
||||
break;
|
||||
}
|
||||
pData[i] = *st;
|
||||
pData[i].connected = mouse_sdl_handles[m] != -1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceMouseSetHandType() {
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
#include "common/types.h"
|
||||
|
||||
#include "common/ring_buffer_queue.h"
|
||||
#include "core/libraries/system/userservice.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
@ -10,20 +12,47 @@ class SymbolsResolver;
|
||||
|
||||
namespace Libraries::Mouse {
|
||||
|
||||
int PS4_SYSV_ABI sceMouseClose();
|
||||
int PS4_SYSV_ABI sceMouseConnectPort();
|
||||
int PS4_SYSV_ABI sceMouseDebugGetDeviceId();
|
||||
int PS4_SYSV_ABI sceMouseDeviceOpen();
|
||||
int PS4_SYSV_ABI sceMouseDisconnectDevice();
|
||||
int PS4_SYSV_ABI sceMouseDisconnectPort();
|
||||
int PS4_SYSV_ABI sceMouseGetDeviceInfo();
|
||||
int PS4_SYSV_ABI sceMouseInit();
|
||||
int PS4_SYSV_ABI sceMouseMbusInit();
|
||||
int PS4_SYSV_ABI sceMouseOpen();
|
||||
int PS4_SYSV_ABI sceMouseRead();
|
||||
int PS4_SYSV_ABI sceMouseSetHandType();
|
||||
int PS4_SYSV_ABI sceMouseSetPointerSpeed();
|
||||
int PS4_SYSV_ABI sceMouseSetProcessPrivilege();
|
||||
struct OrbisMouseData {
|
||||
u64 timestamp;
|
||||
bool connected;
|
||||
u32 buttons;
|
||||
s32 x_axis;
|
||||
s32 y_axis;
|
||||
s32 wheel;
|
||||
s32 tilt;
|
||||
u8 reserve[8];
|
||||
};
|
||||
|
||||
enum class MouseOpenBehaviour : u8 {
|
||||
Normal = 0,
|
||||
Merged = 1,
|
||||
};
|
||||
|
||||
struct OrbisMouseOpenParam {
|
||||
MouseOpenBehaviour flag;
|
||||
u8 reserve[7];
|
||||
};
|
||||
|
||||
extern RingBufferQueue<OrbisMouseData> mouse_states[2];
|
||||
extern s32 mouse_handles[2];
|
||||
extern s32 mouse_sdl_handles[2];
|
||||
extern bool g_lib_init, g_is_merged_mode;
|
||||
|
||||
s32 PS4_SYSV_ABI sceMouseClose(s32 handle);
|
||||
s32 PS4_SYSV_ABI sceMouseConnectPort();
|
||||
s32 PS4_SYSV_ABI sceMouseDebugGetDeviceId();
|
||||
s32 PS4_SYSV_ABI sceMouseDeviceOpen();
|
||||
s32 PS4_SYSV_ABI sceMouseDisconnectDevice();
|
||||
s32 PS4_SYSV_ABI sceMouseDisconnectPort();
|
||||
s32 PS4_SYSV_ABI sceMouseGetDeviceInfo();
|
||||
s32 PS4_SYSV_ABI sceMouseInit();
|
||||
s32 PS4_SYSV_ABI sceMouseMbusInit();
|
||||
s32 PS4_SYSV_ABI sceMouseOpen(Libraries::UserService::OrbisUserServiceUserId userId, s32 type,
|
||||
s32 index, OrbisMouseOpenParam* pParam);
|
||||
s32 PS4_SYSV_ABI sceMouseRead(s32 handle, OrbisMouseData* pData, s32 num);
|
||||
s32 PS4_SYSV_ABI sceMouseSetHandType();
|
||||
s32 PS4_SYSV_ABI sceMouseSetPointerSpeed();
|
||||
s32 PS4_SYSV_ABI sceMouseSetProcessPrivilege();
|
||||
|
||||
void RegisterLib(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Mouse
|
||||
11
src/core/libraries/mouse/mouse_error.h
Normal file
11
src/core/libraries/mouse/mouse_error.h
Normal file
@ -0,0 +1,11 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
#include "common/types.h"
|
||||
|
||||
constexpr s32 ORBIS_MOUSE_ERROR_INVALID_ARG = 0x80DF0001;
|
||||
constexpr s32 ORBIS_MOUSE_ERROR_INVALID_HANDLE = 0x80DF0003;
|
||||
constexpr s32 ORBIS_MOUSE_ERROR_ALREADY_OPENED = 0x80DF0004;
|
||||
constexpr s32 ORBIS_MOUSE_ERROR_NOT_INITIALIZED = 0x80DF0005;
|
||||
constexpr s32 ORBIS_MOUSE_ERROR_FATAL = 0x80DF00FF;
|
||||
124
src/core/libraries/mouse/sdl_mouse.cpp
Normal file
124
src/core/libraries/mouse/sdl_mouse.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/emulator_settings.h"
|
||||
#include "core/libraries/kernel/time.h"
|
||||
#include "sdl_mouse.h"
|
||||
|
||||
namespace Libraries::Mouse {
|
||||
|
||||
static u64 GetIndexFromSdlHandle(SDL_MouseID id) {
|
||||
return g_is_merged_mode ? 0
|
||||
: mouse_sdl_handles[0] == id ? 0
|
||||
: mouse_sdl_handles[1] == id ? 1
|
||||
: 2;
|
||||
}
|
||||
|
||||
constexpr u32 OrbisButtonFromSDL(Uint8 button) {
|
||||
switch (button) {
|
||||
case SDL_BUTTON_LEFT:
|
||||
return 1u << 0;
|
||||
case SDL_BUTTON_RIGHT:
|
||||
return 1u << 1;
|
||||
case SDL_BUTTON_MIDDLE:
|
||||
return 1u << 2;
|
||||
case SDL_BUTTON_X1:
|
||||
return 1u << 3;
|
||||
case SDL_BUTTON_X2:
|
||||
return 1u << 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool PushSDLEvent(SDL_Event const& e) {
|
||||
static OrbisMouseData current_state[2]{};
|
||||
if (!EmulatorSettings.IsMiceUsedAsMice()) {
|
||||
return false;
|
||||
}
|
||||
if (!g_lib_init) {
|
||||
return false;
|
||||
}
|
||||
switch (e.type) {
|
||||
default:
|
||||
return false;
|
||||
case SDL_EVENT_MOUSE_REMOVED: {
|
||||
LOG_INFO(Lib_Mouse, "Mouse removed, id: {}", e.mdevice.which);
|
||||
if (g_is_merged_mode) {
|
||||
break;
|
||||
}
|
||||
u64 index = GetIndexFromSdlHandle(e.mdevice.which);
|
||||
if (index == 2) {
|
||||
return false;
|
||||
}
|
||||
mouse_sdl_handles[index] = -1;
|
||||
break;
|
||||
}
|
||||
case SDL_EVENT_MOUSE_MOTION: {
|
||||
u64 index = GetIndexFromSdlHandle(e.motion.which);
|
||||
if (index == 2) {
|
||||
index = GetIndexFromSdlHandle(-1);
|
||||
if (index < 2)
|
||||
mouse_sdl_handles[index] = e.motion.which;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
auto& s = current_state[index];
|
||||
s.x_axis = (s32)e.motion.xrel;
|
||||
s.y_axis = (s32)e.motion.yrel;
|
||||
s.wheel = 0;
|
||||
s.timestamp = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
|
||||
mouse_states[index].Push(s);
|
||||
break;
|
||||
}
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN: {
|
||||
u64 index = GetIndexFromSdlHandle(e.button.which);
|
||||
if (index >= 2)
|
||||
return false;
|
||||
|
||||
auto& s = current_state[index];
|
||||
s.x_axis = 0;
|
||||
s.y_axis = 0;
|
||||
s.wheel = 0;
|
||||
s.buttons |= OrbisButtonFromSDL(e.button.button);
|
||||
s.timestamp = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
|
||||
mouse_states[index].Push(s);
|
||||
break;
|
||||
}
|
||||
case SDL_EVENT_MOUSE_BUTTON_UP: {
|
||||
u64 index = GetIndexFromSdlHandle(e.button.which);
|
||||
if (index >= 2)
|
||||
return false;
|
||||
|
||||
auto& s = current_state[index];
|
||||
s.x_axis = 0;
|
||||
s.y_axis = 0;
|
||||
s.wheel = 0;
|
||||
s.buttons &= ~OrbisButtonFromSDL(e.button.button);
|
||||
s.timestamp = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
|
||||
mouse_states[index].Push(s);
|
||||
break;
|
||||
}
|
||||
case SDL_EVENT_MOUSE_WHEEL: {
|
||||
u64 index = GetIndexFromSdlHandle(e.wheel.which);
|
||||
if (index >= 2)
|
||||
return false;
|
||||
|
||||
auto& s = current_state[index];
|
||||
s.x_axis = 0;
|
||||
s.y_axis = 0;
|
||||
s.wheel = e.wheel.y;
|
||||
s.tilt = e.wheel.x;
|
||||
s.timestamp = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
|
||||
mouse_states[index].Push(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace Libraries::Mouse
|
||||
12
src/core/libraries/mouse/sdl_mouse.h
Normal file
12
src/core/libraries/mouse/sdl_mouse.h
Normal file
@ -0,0 +1,12 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SDL3/SDL_events.h"
|
||||
#include "common/types.h"
|
||||
#include "mouse.h"
|
||||
|
||||
namespace Libraries::Mouse {
|
||||
bool PushSDLEvent(SDL_Event const& e);
|
||||
}
|
||||
@ -10,7 +10,7 @@
|
||||
#include <SDL3/SDL_gamepad.h>
|
||||
#include "SDL3/SDL_joystick.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/types.h"
|
||||
#include "common/ring_buffer_queue.h"
|
||||
#include "core/libraries/pad/pad.h"
|
||||
#include "core/libraries/system/userservice.h"
|
||||
|
||||
@ -83,37 +83,6 @@ inline int GetAxis(int min, int max, int value) {
|
||||
return (v < 0 ? 0 : (v > 255 ? 255 : v));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class RingBufferQueue {
|
||||
public:
|
||||
RingBufferQueue(size_t size) : m_storage(size) {}
|
||||
|
||||
void Push(T item) {
|
||||
const size_t index = (m_begin + m_size) % m_storage.size();
|
||||
m_storage[index] = std::move(item);
|
||||
if (m_size < m_storage.size()) {
|
||||
m_size += 1;
|
||||
} else {
|
||||
m_begin = (m_begin + 1) % m_storage.size();
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<T> Pop() {
|
||||
if (m_size == 0) {
|
||||
return {};
|
||||
}
|
||||
const size_t index = m_begin;
|
||||
m_begin = (m_begin + 1) % m_storage.size();
|
||||
m_size -= 1;
|
||||
return std::move(m_storage[index]);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_begin = 0;
|
||||
size_t m_size = 0;
|
||||
std::vector<T> m_storage;
|
||||
};
|
||||
|
||||
class GameController {
|
||||
friend class GameControllers;
|
||||
|
||||
|
||||
@ -32,6 +32,8 @@
|
||||
#ifdef __APPLE__
|
||||
#include <SDL3/SDL_metal.h>
|
||||
#endif
|
||||
#include <core/emulator_settings.h>
|
||||
#include "core/libraries/mouse/sdl_mouse.h"
|
||||
|
||||
CMRC_DECLARE(res);
|
||||
|
||||
@ -217,6 +219,10 @@ void WindowSDL::WaitEvent() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Libraries::Mouse::PushSDLEvent(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ImGui::Core::ProcessEvent(&event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user