handle all mouse inputs & ask to capture when first opened

This commit is contained in:
Vinicius Rangel 2024-10-19 04:30:41 -03:00
parent 906008e5d7
commit 0a5d13baa5
No known key found for this signature in database
GPG Key ID: A5B154D904B761D9
6 changed files with 228 additions and 93 deletions

View File

@ -425,6 +425,13 @@ constexpr int ORBIS_PAD_ERROR_INVALID_REPORT_LENGTH = 0x80920103;
constexpr int ORBIS_PAD_ERROR_INVALID_REPORT_ID = 0x80920104; constexpr int ORBIS_PAD_ERROR_INVALID_REPORT_ID = 0x80920104;
constexpr int ORBIS_PAD_ERROR_SEND_AGAIN = 0x80920105; constexpr int ORBIS_PAD_ERROR_SEND_AGAIN = 0x80920105;
// Mouse library
constexpr int ORBIS_MOUSE_ERROR_INVALID_ARG = 0x80DF0001;
constexpr int ORBIS_MOUSE_ERROR_INVALID_HANDLE = 0x80DF0003;
constexpr int ORBIS_MOUSE_ERROR_ALREADY_OPENED = 0x80DF0004;
constexpr int ORBIS_MOUSE_ERROR_NOT_INITIALIZED = 0x80DF0005;
constexpr int ORBIS_MOUSE_ERROR_FATAL = 0x80DF00FF;
// UserService library // UserService library
constexpr int ORBIS_USER_SERVICE_ERROR_INTERNAL = 0x80960001; constexpr int ORBIS_USER_SERVICE_ERROR_INTERNAL = 0x80960001;
constexpr int ORBIS_USER_SERVICE_ERROR_NOT_INITIALIZED = 0x80960002; constexpr int ORBIS_USER_SERVICE_ERROR_NOT_INITIALIZED = 0x80960002;

View File

@ -3,6 +3,7 @@
// Generated By moduleGenerator // Generated By moduleGenerator
#include <common/singleton.h> #include <common/singleton.h>
#include <core/libraries/system/msgdialog_ui.h>
#include <input/mouse.h> #include <input/mouse.h>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
@ -11,10 +12,32 @@
namespace Libraries::Mouse { namespace Libraries::Mouse {
int PS4_SYSV_ABI sceMouseClose() { static bool g_initialized = false;
LOG_ERROR(Lib_Mouse, "(STUBBED) called"); static bool g_mouse1_open = false;
static bool g_mouse2_open = false;
constexpr auto MOUSE1_HANDLE = 0xF1;
constexpr auto MOUSE2_HANDLE = 0xF2;
constexpr auto ORBIS_MOUSE_OPEN_PARAM_NORMAL = 0x00;
constexpr auto ORBIS_MOUSE_OPEN_PARAM_MERGED = 0x01;
int PS4_SYSV_ABI sceMouseClose(s32 handle) {
LOG_INFO(Lib_Mouse, "called");
if (!g_initialized) {
return ORBIS_MOUSE_ERROR_NOT_INITIALIZED;
}
if (handle == MOUSE1_HANDLE && g_mouse1_open) {
g_mouse1_open = false;
return ORBIS_OK; return ORBIS_OK;
} }
if (handle == MOUSE2_HANDLE && g_mouse2_open) {
g_mouse2_open = false;
return ORBIS_OK;
}
return ORBIS_MOUSE_ERROR_INVALID_HANDLE;
}
int PS4_SYSV_ABI sceMouseConnectPort() { int PS4_SYSV_ABI sceMouseConnectPort() {
LOG_ERROR(Lib_Mouse, "(STUBBED) called"); LOG_ERROR(Lib_Mouse, "(STUBBED) called");
@ -48,6 +71,7 @@ int PS4_SYSV_ABI sceMouseGetDeviceInfo() {
int PS4_SYSV_ABI sceMouseInit() { int PS4_SYSV_ABI sceMouseInit() {
LOG_INFO(Lib_Mouse, "called"); LOG_INFO(Lib_Mouse, "called");
g_initialized = true;
return ORBIS_OK; return ORBIS_OK;
} }
@ -57,28 +81,93 @@ int PS4_SYSV_ABI sceMouseMbusInit() {
} }
int PS4_SYSV_ABI sceMouseOpen(s32 userId, s32 type, s32 index, OrbisMouseOpenParam* pParam) { int PS4_SYSV_ABI sceMouseOpen(s32 userId, s32 type, s32 index, OrbisMouseOpenParam* pParam) {
LOG_INFO(Lib_Mouse, "(DUMMY) called"); LOG_INFO(Lib_Mouse, "called");
return 2; // dummy if (!g_initialized) {
return ORBIS_MOUSE_ERROR_NOT_INITIALIZED;
}
bool merge = pParam != nullptr && (pParam->behaviorFlag & ORBIS_MOUSE_OPEN_PARAM_MERGED) != 0;
if (merge || index == 0) {
if (g_mouse1_open) {
return ORBIS_PAD_ERROR_ALREADY_OPENED;
}
g_mouse1_open = true;
if (!Common::Singleton<Input::GameMouse>::Instance()->m_connected) {
MsgDialog::ShowMsgDialog(
MsgDialog::MsgDialogState(MsgDialog::MsgDialogState::UserState{
.type = MsgDialog::ButtonType::YESNO,
.msg = "Game wants to use your mouse.\nDo you want to allow it?",
}),
false, [](MsgDialog::DialogResult result) {
if (result.buttonId == MsgDialog::ButtonId::YES) {
auto* mouse = Common::Singleton<Input::GameMouse>::Instance();
mouse->m_connected = true;
}
});
}
return MOUSE1_HANDLE;
}
if (index == 1) {
if (g_mouse2_open) {
return ORBIS_PAD_ERROR_ALREADY_OPENED;
}
g_mouse2_open = true;
return MOUSE2_HANDLE;
}
return ORBIS_MOUSE_ERROR_INVALID_ARG;
} }
int PS4_SYSV_ABI sceMouseRead(s32 handle, OrbisMouseData* pData, s32 num) { int PS4_SYSV_ABI sceMouseRead(s32 handle, OrbisMouseData* pData, s32 num) {
bool connected = false; LOG_TRACE(Lib_Mouse, "called");
Input::MouseState states[64];
auto* mouse = Common::Singleton<Input::GameMouse>::Instance();
int ret_num = mouse->ReadStates(states, num, &connected);
if (!connected) { if (!g_initialized) {
ret_num = 1; return ORBIS_MOUSE_ERROR_NOT_INITIALIZED;
} }
if (num < 1 || num > 64 || pData == nullptr) {
return ORBIS_MOUSE_ERROR_INVALID_ARG;
}
auto* mouse = Common::Singleton<Input::GameMouse>::Instance();
if (handle == MOUSE1_HANDLE) {
if (!g_mouse1_open) {
return ORBIS_MOUSE_ERROR_INVALID_HANDLE;
}
} else if (handle == MOUSE2_HANDLE) {
if (!g_mouse2_open) {
return ORBIS_MOUSE_ERROR_INVALID_HANDLE;
}
// Mouse 2 will never be connected
pData[0] = OrbisMouseData{
.connected = false,
};
return 1;
} else {
return ORBIS_MOUSE_ERROR_INVALID_HANDLE;
}
if (!mouse->m_connected) {
pData[0] = OrbisMouseData{
.connected = false,
};
return 1;
}
Input::MouseState states[64];
int ret_num = mouse->ReadStates(states, num);
for (int i = 0; i < ret_num; i++) { for (int i = 0; i < ret_num; i++) {
pData[i].buttons = states[i].buttonsState; const auto& s = states[i];
pData[i].connected = connected; pData[i] = OrbisMouseData{
pData[i].timestamp = states[i].time; .timestamp = s.time,
pData[i].xAxis = 0; .connected = true,
pData[i].yAxis = 0; .buttons = s.button_state,
pData[i].wheel = 0; .xAxis = s.x_axis,
pData[i].tilt = 0; .yAxis = s.y_axis,
.wheel = s.wheel,
.tilt = s.tilt,
};
} }
return ret_num; return ret_num;
} }

View File

@ -23,15 +23,18 @@ struct OrbisMouseData {
s32 yAxis; s32 yAxis;
s32 wheel; s32 wheel;
s32 tilt; s32 tilt;
u8 reserve[8]; std::array<u8, 8> reserve{};
}; };
enum OrbisMouseButtonDataOffset { enum OrbisMouseButtonDataOffset {
ORBIS_MOUSE_BUTTON_PRIMARY = 0x00000001, ORBIS_MOUSE_BUTTON_PRIMARY = 0x00000001,
ORBIS_MOUSE_BUTTON_SECONDARY = 0x00000002 ORBIS_MOUSE_BUTTON_SECONDARY = 0x00000002,
ORBIS_MOUSE_BUTTON_OPTIONAL = 0x00000004,
ORBIS_MOUSE_BUTTON_OPTIONAL2 = 0x00000008,
ORBIS_MOUSE_BUTTON_OPTIONAL3 = 0x00000010,
}; };
int PS4_SYSV_ABI sceMouseClose(); int PS4_SYSV_ABI sceMouseClose(s32 handle);
int PS4_SYSV_ABI sceMouseConnectPort(); int PS4_SYSV_ABI sceMouseConnectPort();
int PS4_SYSV_ABI sceMouseDebugGetDeviceId(); int PS4_SYSV_ABI sceMouseDebugGetDeviceId();
int PS4_SYSV_ABI sceMouseDeviceOpen(); int PS4_SYSV_ABI sceMouseDeviceOpen();

View File

@ -11,70 +11,71 @@ GameMouse::GameMouse() {
m_last_state = MouseState(); m_last_state = MouseState();
} }
int GameMouse::ReadStates(MouseState* states, int states_num, bool* isConnected) { int GameMouse::ReadStates(MouseState* states, int states_num) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
*isConnected = m_connected; const u32 count = std::min(m_states_num, u32(states_num));
int ret_num = 0; u32 begin = (m_index - m_states_num + 1) % MAX_MOUSE_STATES;
for (u32 i = 0; i < count; i++) {
if (m_connected) { u32 idx = (begin + i) % MAX_MOUSE_STATES;
if (m_states_num == 0) { states[i] = m_states[idx];
ret_num = 1;
states[0] = m_last_state;
} else {
for (uint32_t i = 0; i < m_states_num; i++) {
if (ret_num >= states_num) {
break;
}
auto index = (m_first_state + i) % MAX_MOUSE_STATES;
if (!m_private[index].obtained) {
m_private[index].obtained = true;
states[ret_num++] = m_states[index];
}
}
}
} }
return ret_num; m_states_num -= count;
} return static_cast<int>(count);
MouseState GameMouse::GetLastState() const {
if (m_states_num == 0) {
return m_last_state;
}
auto last = (m_first_state + m_states_num - 1) % MAX_MOUSE_STATES;
return m_states[last];
} }
void GameMouse::AddState(const MouseState& state) { void GameMouse::AddState(const MouseState& state) {
if (m_states_num >= MAX_MOUSE_STATES) {
m_states_num = MAX_MOUSE_STATES - 1;
m_first_state = (m_first_state + 1) % MAX_MOUSE_STATES;
}
auto index = (m_first_state + m_states_num) % MAX_MOUSE_STATES;
m_states[index] = state;
m_last_state = state;
m_private[index].obtained = false;
m_states_num++;
}
void GameMouse::CheckButton(int id, u32 button, bool isPressed) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
auto state = GetLastState();
m_index = (m_index + 1) % MAX_MOUSE_STATES;
if (m_states_num < MAX_MOUSE_STATES) {
++m_states_num;
}
m_states[m_index] = state;
m_last_state = MouseState{
.button_state = state.button_state,
};
}
void GameMouse::CheckButton(u32 button, bool isPressed) {
if (!m_connected) {
return;
}
MouseState state = m_last_state;
state.time = Libraries::Kernel::sceKernelGetProcessTime(); state.time = Libraries::Kernel::sceKernelGetProcessTime();
if (isPressed) { if (isPressed) {
state.buttonsState |= button; state.button_state |= button;
} else { } else {
state.buttonsState &= ~button; state.button_state &= ~button;
} }
AddState(state); AddState(state);
} }
void GameMouse::CheckMove(int x, int y) {
if (!m_connected) {
return;
}
MouseState state = m_last_state;
state.time = Libraries::Kernel::sceKernelGetProcessTime();
state.x_axis = x;
state.y_axis = y;
AddState(state);
}
void GameMouse::CheckWheel(int x, int y) {
if (!m_connected) {
return;
}
MouseState state = m_last_state;
state.time = Libraries::Kernel::sceKernelGetProcessTime();
state.wheel = y;
state.tilt = x;
AddState(state);
}
}; // namespace Input }; // namespace Input

View File

@ -8,8 +8,12 @@
namespace Input { namespace Input {
struct MouseState { struct MouseState {
u32 buttonsState = 0;
u64 time = 0; u64 time = 0;
u32 button_state = 0;
s32 x_axis = 0;
s32 y_axis = 0;
s32 wheel = 0;
s32 tilt = 0;
}; };
constexpr u32 MAX_MOUSE_STATES = 64; constexpr u32 MAX_MOUSE_STATES = 64;
@ -19,25 +23,23 @@ public:
GameMouse(); GameMouse();
virtual ~GameMouse() = default; virtual ~GameMouse() = default;
int ReadStates(MouseState* states, int states_num, bool* isConnected); int ReadStates(MouseState* states, int states_num);
MouseState GetLastState() const;
void CheckButton(int id, u32 button, bool isPressed); void CheckButton(u32 button, bool isPressed);
void AddState(const MouseState& state); void CheckMove(int x, int y);
void CheckWheel(int x, int y);
bool m_connected = false;
float speed = 1.0f;
private: private:
struct StateInternal { void AddState(const MouseState& state);
bool obtained = false;
};
std::mutex m_mutex; std::mutex m_mutex;
bool m_connected = true;
MouseState m_last_state; MouseState m_last_state;
int m_connected_count = 0;
u32 m_states_num = 0; u32 m_states_num = 0;
u32 m_first_state = 0; u32 m_index = 0;
std::array<MouseState, MAX_MOUSE_STATES> m_states; std::array<MouseState, MAX_MOUSE_STATES> m_states;
std::array<StateInternal, MAX_MOUSE_STATES> m_private;
}; };
} // namespace Input } // namespace Input

View File

@ -118,8 +118,10 @@ void WindowSDL::waitEvent() {
is_open = false; is_open = false;
break; break;
case SDL_EVENT_MOUSE_MOTION:
case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP: case SDL_EVENT_MOUSE_BUTTON_UP:
case SDL_EVENT_MOUSE_WHEEL:
onMouseAction(&event); onMouseAction(&event);
break; break;
default: default:
@ -127,19 +129,50 @@ void WindowSDL::waitEvent() {
} }
} }
void WindowSDL::onMouseAction(const SDL_Event* event) { void WindowSDL::onMouseAction(const SDL_Event* event) {
auto* mouse = Common::Singleton<Input::GameMouse>::Instance(); auto& mouse = *Common::Singleton<Input::GameMouse>::Instance();
using Libraries::Mouse::OrbisMouseButtonDataOffset;
u32 button = 0; if (mouse.m_connected && !is_capturing_mouse) {
switch (event->button.button) { SDL_SetWindowRelativeMouseMode(window, true);
case SDL_BUTTON_LEFT: is_capturing_mouse = true;
button = OrbisMouseButtonDataOffset::ORBIS_MOUSE_BUTTON_PRIMARY; } else if (!mouse.m_connected && is_capturing_mouse) {
break; SDL_SetWindowRelativeMouseMode(window, false);
case SDL_BUTTON_RIGHT: is_capturing_mouse = false;
button = OrbisMouseButtonDataOffset::ORBIS_MOUSE_BUTTON_SECONDARY;
break;
} }
if (button != 0) {
mouse->CheckButton(0, button, event->type == SDL_EVENT_MOUSE_BUTTON_DOWN); bool pressed_down = false;
switch (event->type) {
case SDL_EVENT_MOUSE_BUTTON_DOWN:
pressed_down = true;
[[fallthrough]];
case SDL_EVENT_MOUSE_BUTTON_UP: {
using Libraries::Mouse::OrbisMouseButtonDataOffset;
auto btn = event->button.button;
if (btn < 1 || btn > 5) { // 1..5 range
return;
}
constexpr static std::array sdl_to_orbis_buttons = {
static_cast<OrbisMouseButtonDataOffset>(0x00),
OrbisMouseButtonDataOffset::ORBIS_MOUSE_BUTTON_PRIMARY,
OrbisMouseButtonDataOffset::ORBIS_MOUSE_BUTTON_OPTIONAL,
OrbisMouseButtonDataOffset::ORBIS_MOUSE_BUTTON_SECONDARY,
OrbisMouseButtonDataOffset::ORBIS_MOUSE_BUTTON_OPTIONAL2,
OrbisMouseButtonDataOffset::ORBIS_MOUSE_BUTTON_OPTIONAL3,
};
mouse.CheckButton(sdl_to_orbis_buttons[btn], pressed_down);
} break;
case SDL_EVENT_MOUSE_MOTION: {
const auto x = static_cast<int>(event->motion.xrel * mouse.speed);
const auto y = static_cast<int>(event->motion.yrel * mouse.speed);
mouse.CheckMove(x, y);
} break;
case SDL_EVENT_MOUSE_WHEEL: {
const auto x = static_cast<int>(event->wheel.x);
const auto y = static_cast<int>(event->wheel.y);
mouse.CheckWheel(x, y);
} break;
default:
break;
} }
} }
void WindowSDL::onResize() { void WindowSDL::onResize() {