rpcsx/rpcs3/Emu/Io/MouseHandler.h
2022-07-04 16:02:17 +03:00

264 lines
5.4 KiB
C++

#pragma once
#include <list>
#include <algorithm>
#include <vector>
#include "Utilities/mutex.h"
#include "util/init_mutex.hpp"
// 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,
CELL_MOUSE_STATUS_CONNECTED = 0x00000001,
};
enum MouseDataUpdate
{
CELL_MOUSE_DATA_UPDATE = 1,
CELL_MOUSE_DATA_NON = 0,
};
enum MouseButtonCodes
{
CELL_MOUSE_BUTTON_1 = 0x00000001,
CELL_MOUSE_BUTTON_2 = 0x00000002,
CELL_MOUSE_BUTTON_3 = 0x00000004,
CELL_MOUSE_BUTTON_4 = 0x00000008,
CELL_MOUSE_BUTTON_5 = 0x00000010,
CELL_MOUSE_BUTTON_6 = 0x00000020,
CELL_MOUSE_BUTTON_7 = 0x00000040,
CELL_MOUSE_BUTTON_8 = 0x00000080,
};
enum
{
CELL_MOUSE_INFO_INTERCEPTED = 1
};
static const u32 MAX_MICE = 127;
static const u32 MOUSE_MAX_DATA_LIST_NUM = 8;
static const u32 MOUSE_MAX_CODES = 64;
struct MouseInfo
{
u32 max_connect = 0;
u32 now_connect = 0;
u32 info = 0;
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]{};
bool is_null_handler = false;
};
struct MouseRawData
{
s32 len = 0;
u8 data[MOUSE_MAX_CODES]{};
};
struct MouseData
{
u8 update = 0;
u8 buttons = 0;
s8 x_axis = 0;
s8 y_axis = 0;
s8 wheel = 0;
s8 tilt = 0; // (TODO)
};
struct MouseTabletData
{
s32 len = 0;
u8 data[MOUSE_MAX_CODES]{};
};
using MouseTabletDataList = std::list<MouseTabletData>;
using MouseDataList = std::list<MouseData>;
struct Mouse
{
s32 x_pos = 0;
s32 y_pos = 0;
s32 x_max = 0;
s32 y_max = 0;
u8 buttons = 0; // actual mouse button positions
MouseTabletDataList m_tablet_datalist{};
MouseDataList m_datalist{};
MouseRawData m_rawdata{};
};
class MouseHandlerBase
{
protected:
MouseInfo m_info{};
std::vector<Mouse> m_mice;
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
{
steady_clock::time_point now = steady_clock::now();
double elapsed = (now - last_update).count() / 1000'000.;
if (elapsed > elapsed_time)
{
last_update = now;
return true;
}
return false;
}
public:
shared_mutex mutex;
virtual void Init(const u32 max_connect) = 0;
virtual ~MouseHandlerBase() = default;
SAVESTATE_INIT_POS(18);
MouseHandlerBase(const MouseHandlerBase&) = delete;
MouseHandlerBase(utils::serial* ar);
MouseHandlerBase(utils::serial& ar) : MouseHandlerBase(&ar) {}
void save(utils::serial& ar);
void Button(u8 button, bool pressed)
{
std::lock_guard lock(mutex);
for (u32 p = 0; p < m_mice.size(); ++p)
{
if (m_info.status[p] != CELL_MOUSE_STATUS_CONNECTED)
{
continue;
}
MouseDataList& datalist = GetDataList(p);
if (datalist.size() > MOUSE_MAX_DATA_LIST_NUM)
{
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;
new_data.buttons = m_mice[p].buttons;
datalist.push_back(new_data);
}
}
void Scroll(const s8 rotation)
{
std::lock_guard lock(mutex);
for (u32 p = 0; p < m_mice.size(); ++p)
{
if (m_info.status[p] != CELL_MOUSE_STATUS_CONNECTED)
{
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()
new_data.buttons = m_mice[p].buttons;
datalist.push_back(new_data);
}
}
void Move(s32 x_pos_new, s32 y_pos_new, s32 x_max, s32 y_max, const bool is_qt_fullscreen = false, s32 x_delta = 0, s32 y_delta = 0)
{
std::lock_guard lock(mutex);
for (u32 p = 0; p < m_mice.size(); ++p)
{
if (m_info.status[p] != CELL_MOUSE_STATUS_CONNECTED)
{
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.buttons = m_mice[p].buttons;
if (!is_qt_fullscreen)
{
x_delta = x_pos_new - m_mice[p].x_pos;
y_delta = y_pos_new - m_mice[p].y_pos;
}
new_data.x_axis = static_cast<s8>(std::clamp(x_delta, -127, 128));
new_data.y_axis = static_cast<s8>(std::clamp(y_delta, -127, 128));
m_mice[p].x_max = x_max;
m_mice[p].y_max = y_max;
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);
}
}
void SetIntercepted(bool intercepted)
{
std::lock_guard lock(mutex);
m_info.info = intercepted ? CELL_MOUSE_INFO_INTERCEPTED : 0;
if (intercepted)
{
for (Mouse& mouse : m_mice)
{
mouse = {};
}
}
}
MouseInfo& GetInfo() { return m_info; }
std::vector<Mouse>& GetMice() { return m_mice; }
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; }
stx::init_mutex init;
};