mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-03-10 23:45:16 +01:00
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.6, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.6, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.6, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.6, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, arch -X86_64 .ci/build-mac.sh, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, .ci/build-mac-arm64.sh, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang (win64, clang, clang64) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run
512 lines
14 KiB
C++
512 lines
14 KiB
C++
#include "stdafx.h"
|
|
#include "Emu/IdManager.h"
|
|
#include "Emu/system_config.h"
|
|
#include "Emu/Cell/PPUModule.h"
|
|
#include "Emu/Io/MouseHandler.h"
|
|
#include "Emu/RSX/Overlays/overlay_debug_overlay.h"
|
|
|
|
#include "cellMouse.h"
|
|
|
|
error_code sys_config_start(ppu_thread& ppu);
|
|
error_code sys_config_stop(ppu_thread& ppu);
|
|
|
|
extern bool is_input_allowed();
|
|
|
|
LOG_CHANNEL(cellMouse);
|
|
|
|
void show_debug_overlay(const CellMouseData& data, const MouseData* _mouse)
|
|
{
|
|
// The cell mouse can be set empty without any new mouse input.
|
|
// Only update our mouse input if there is new data.
|
|
static MouseData mouse {};
|
|
if (_mouse)
|
|
{
|
|
mouse = *_mouse;
|
|
}
|
|
|
|
std::string text = fmt::format(
|
|
"> Name: Raw Value Pixel\n"
|
|
">\n"
|
|
"> Update: %5d %5d\n"
|
|
"> Wheel: %5d %5d\n"
|
|
"> Tilt: %5d %5d\n"
|
|
"> X: %5d %5d %5d\n"
|
|
"> Y: %5d %5d %5d\n"
|
|
">\n"
|
|
"> Buttons: 0x%04x 0x%04x\n"
|
|
"> Button 1: %5d %5d\n"
|
|
"> Button 2: %5d %5d\n"
|
|
"> Button 3: %5d %5d\n"
|
|
"> Button 4: %5d %5d\n"
|
|
"> Button 5: %5d %5d\n"
|
|
"> Button 6: %5d %5d\n"
|
|
"> Button 7: %5d %5d\n"
|
|
"> Button 8: %5d %5d\n"
|
|
,
|
|
mouse.update, data.update,
|
|
mouse.wheel, data.wheel,
|
|
mouse.tilt, data.tilt,
|
|
mouse.x_axis, data.x_axis, mouse.pixel_x,
|
|
mouse.y_axis, data.y_axis, mouse.pixel_y,
|
|
mouse.buttons, data.buttons,
|
|
!!(mouse.buttons & CELL_MOUSE_BUTTON_1), !!(data.buttons & CELL_MOUSE_BUTTON_1),
|
|
!!(mouse.buttons & CELL_MOUSE_BUTTON_2), !!(data.buttons & CELL_MOUSE_BUTTON_2),
|
|
!!(mouse.buttons & CELL_MOUSE_BUTTON_3), !!(data.buttons & CELL_MOUSE_BUTTON_3),
|
|
!!(mouse.buttons & CELL_MOUSE_BUTTON_4), !!(data.buttons & CELL_MOUSE_BUTTON_4),
|
|
!!(mouse.buttons & CELL_MOUSE_BUTTON_5), !!(data.buttons & CELL_MOUSE_BUTTON_5),
|
|
!!(mouse.buttons & CELL_MOUSE_BUTTON_6), !!(data.buttons & CELL_MOUSE_BUTTON_6),
|
|
!!(mouse.buttons & CELL_MOUSE_BUTTON_7), !!(data.buttons & CELL_MOUSE_BUTTON_7),
|
|
!!(mouse.buttons & CELL_MOUSE_BUTTON_8), !!(data.buttons & CELL_MOUSE_BUTTON_8)
|
|
);
|
|
|
|
rsx::overlays::set_debug_overlay_text(std::move(text));
|
|
}
|
|
|
|
template<>
|
|
void fmt_class_string<CellMouseError>::format(std::string& out, u64 arg)
|
|
{
|
|
format_enum(out, arg, [](auto error)
|
|
{
|
|
switch (error)
|
|
{
|
|
STR_CASE(CELL_MOUSE_ERROR_FATAL);
|
|
STR_CASE(CELL_MOUSE_ERROR_INVALID_PARAMETER);
|
|
STR_CASE(CELL_MOUSE_ERROR_ALREADY_INITIALIZED);
|
|
STR_CASE(CELL_MOUSE_ERROR_UNINITIALIZED);
|
|
STR_CASE(CELL_MOUSE_ERROR_RESOURCE_ALLOCATION_FAILED);
|
|
STR_CASE(CELL_MOUSE_ERROR_DATA_READ_FAILED);
|
|
STR_CASE(CELL_MOUSE_ERROR_NO_DEVICE);
|
|
STR_CASE(CELL_MOUSE_ERROR_SYS_SETTING_FAILED);
|
|
}
|
|
|
|
return unknown;
|
|
});
|
|
}
|
|
|
|
error_code cellMouseInit(ppu_thread& ppu, u32 max_connect)
|
|
{
|
|
cellMouse.notice("cellMouseInit(max_connect=%d)", max_connect);
|
|
|
|
auto& handler = g_fxo->get<MouseHandlerBase>();
|
|
|
|
auto init = handler.init.init();
|
|
|
|
if (!init)
|
|
return CELL_MOUSE_ERROR_ALREADY_INITIALIZED;
|
|
|
|
if (max_connect == 0 || max_connect > CELL_MAX_MICE)
|
|
{
|
|
init.cancel();
|
|
return CELL_MOUSE_ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
sys_config_start(ppu);
|
|
handler.Init(std::min(max_connect, 7u));
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellMouseClearBuf(u32 port_no)
|
|
{
|
|
cellMouse.trace("cellMouseClearBuf(port_no=%d)", port_no);
|
|
|
|
auto& handler = g_fxo->get<MouseHandlerBase>();
|
|
|
|
const auto init = handler.init.access();
|
|
|
|
if (!init)
|
|
return CELL_MOUSE_ERROR_UNINITIALIZED;
|
|
|
|
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 not_an_error(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;
|
|
}
|
|
|
|
error_code cellMouseEnd(ppu_thread& ppu)
|
|
{
|
|
cellMouse.notice("cellMouseEnd()");
|
|
|
|
auto& handler = g_fxo->get<MouseHandlerBase>();
|
|
|
|
const auto init = handler.init.reset();
|
|
|
|
if (!init)
|
|
return CELL_MOUSE_ERROR_UNINITIALIZED;
|
|
|
|
// TODO
|
|
sys_config_stop(ppu);
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellMouseGetInfo(vm::ptr<CellMouseInfo> info)
|
|
{
|
|
cellMouse.trace("cellMouseGetInfo(info=*0x%x)", info);
|
|
|
|
auto& handler = g_fxo->get<MouseHandlerBase>();
|
|
|
|
const auto init = handler.init.access();
|
|
|
|
if (!init)
|
|
return CELL_MOUSE_ERROR_UNINITIALIZED;
|
|
|
|
if (!info)
|
|
{
|
|
return CELL_MOUSE_ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
std::memset(info.get_ptr(), 0, info.size());
|
|
|
|
const MouseInfo& current_info = handler.GetInfo();
|
|
info->max_connect = current_info.max_connect;
|
|
info->now_connect = current_info.now_connect;
|
|
info->info = current_info.info;
|
|
|
|
for (u32 i = 0; i < CELL_MAX_MICE; i++)
|
|
{
|
|
info->vendor_id[i] = current_info.vendor_id[i];
|
|
info->product_id[i] = current_info.product_id[i];
|
|
info->status[i] = current_info.status[i];
|
|
}
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellMouseInfoTabletMode(u32 port_no, vm::ptr<CellMouseInfoTablet> info)
|
|
{
|
|
cellMouse.trace("cellMouseInfoTabletMode(port_no=%d, info=*0x%x)", port_no, info);
|
|
|
|
auto& handler = g_fxo->get<MouseHandlerBase>();
|
|
|
|
const auto init = handler.init.access();
|
|
|
|
if (!init)
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
error_code cellMouseGetData(u32 port_no, vm::ptr<CellMouseData> data)
|
|
{
|
|
cellMouse.trace("cellMouseGetData(port_no=%d, data=*0x%x)", port_no, data);
|
|
|
|
auto& handler = g_fxo->get<MouseHandlerBase>();
|
|
|
|
const auto init = handler.init.access();
|
|
|
|
if (!init)
|
|
return CELL_MOUSE_ERROR_UNINITIALIZED;
|
|
|
|
if (port_no >= CELL_MAX_MICE || !data)
|
|
{
|
|
return CELL_MOUSE_ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
std::lock_guard lock(handler.mutex);
|
|
|
|
const MouseInfo& current_info = handler.GetInfo();
|
|
|
|
if (port_no >= handler.GetMice().size() || current_info.status[port_no] != CELL_MOUSE_STATUS_CONNECTED)
|
|
{
|
|
return not_an_error(CELL_MOUSE_ERROR_NO_DEVICE);
|
|
}
|
|
|
|
std::memset(data.get_ptr(), 0, data.size());
|
|
|
|
// TODO: check if (current_info.mode[port_no] != CELL_MOUSE_INFO_TABLET_MOUSE_MODE) has any impact
|
|
|
|
MouseDataList& data_list = handler.GetDataList(port_no);
|
|
|
|
if (data_list.empty() || current_info.is_null_handler || (current_info.info & CELL_MOUSE_INFO_INTERCEPTED) || !is_input_allowed())
|
|
{
|
|
data_list.clear();
|
|
|
|
if (port_no == 0 && g_cfg.io.mouse_debug_overlay && !g_cfg.io.pad_debug_overlay && !g_cfg.video.debug_overlay)
|
|
{
|
|
show_debug_overlay(*data, nullptr);
|
|
}
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
const MouseData& current_data = data_list.front();
|
|
data->update = current_data.update;
|
|
data->buttons = current_data.buttons;
|
|
data->x_axis = current_data.x_axis;
|
|
data->y_axis = current_data.y_axis;
|
|
data->wheel = current_data.wheel;
|
|
data->tilt = current_data.tilt;
|
|
|
|
if (port_no == 0 && g_cfg.io.mouse_debug_overlay && !g_cfg.io.pad_debug_overlay && !g_cfg.video.debug_overlay)
|
|
{
|
|
show_debug_overlay(*data, ¤t_data);
|
|
}
|
|
|
|
data_list.pop_front();
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellMouseGetDataList(u32 port_no, vm::ptr<CellMouseDataList> data)
|
|
{
|
|
cellMouse.trace("cellMouseGetDataList(port_no=%d, data=0x%x)", port_no, data);
|
|
|
|
auto& handler = g_fxo->get<MouseHandlerBase>();
|
|
|
|
const auto init = handler.init.access();
|
|
|
|
if (!init)
|
|
return CELL_MOUSE_ERROR_UNINITIALIZED;
|
|
|
|
if (port_no >= CELL_MAX_MICE || !data)
|
|
{
|
|
return CELL_MOUSE_ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
std::lock_guard lock(handler.mutex);
|
|
|
|
const MouseInfo& current_info = handler.GetInfo();
|
|
|
|
if (port_no >= handler.GetMice().size() || current_info.status[port_no] != CELL_MOUSE_STATUS_CONNECTED)
|
|
{
|
|
return not_an_error(CELL_MOUSE_ERROR_NO_DEVICE);
|
|
}
|
|
|
|
std::memset(data.get_ptr(), 0, data.size());
|
|
|
|
// TODO: check if (current_info.mode[port_no] != CELL_MOUSE_INFO_TABLET_MOUSE_MODE) has any impact
|
|
|
|
MouseDataList& list = handler.GetDataList(port_no);
|
|
|
|
if (list.empty() || current_info.is_null_handler || (current_info.info & CELL_MOUSE_INFO_INTERCEPTED) || !is_input_allowed())
|
|
{
|
|
list.clear();
|
|
|
|
if (port_no == 0 && g_cfg.io.mouse_debug_overlay && !g_cfg.io.pad_debug_overlay && !g_cfg.video.debug_overlay)
|
|
{
|
|
show_debug_overlay(data->list[0], nullptr);
|
|
}
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
data->list_num = std::min<u32>(CELL_MOUSE_MAX_DATA_LIST_NUM, static_cast<u32>(list.size()));
|
|
|
|
for (size_t i = 0; i < list.size() && i < CELL_MOUSE_MAX_DATA_LIST_NUM; ++i)
|
|
{
|
|
const MouseData& current_data = list[i];
|
|
data->list[i].update = current_data.update;
|
|
data->list[i].buttons = current_data.buttons;
|
|
data->list[i].x_axis = current_data.x_axis;
|
|
data->list[i].y_axis = current_data.y_axis;
|
|
data->list[i].wheel = current_data.wheel;
|
|
data->list[i].tilt = current_data.tilt;
|
|
|
|
if (port_no == 0 && g_cfg.io.mouse_debug_overlay && !g_cfg.io.pad_debug_overlay && !g_cfg.video.debug_overlay)
|
|
{
|
|
show_debug_overlay(data->list[i], ¤t_data);
|
|
}
|
|
}
|
|
|
|
list.clear();
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellMouseSetTabletMode(u32 port_no, u32 mode)
|
|
{
|
|
cellMouse.warning("cellMouseSetTabletMode(port_no=%d, mode=%d)", port_no, mode);
|
|
|
|
auto& handler = g_fxo->get<MouseHandlerBase>();
|
|
|
|
const auto init = handler.init.access();
|
|
|
|
if (!init)
|
|
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;
|
|
}
|
|
|
|
error_code cellMouseGetTabletDataList(u32 port_no, vm::ptr<CellMouseTabletDataList> data)
|
|
{
|
|
cellMouse.warning("cellMouseGetTabletDataList(port_no=%d, data=0x%x)", port_no, data);
|
|
|
|
auto& handler = g_fxo->get<MouseHandlerBase>();
|
|
|
|
const auto init = handler.init.access();
|
|
|
|
if (!init)
|
|
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 not_an_error(CELL_MOUSE_ERROR_NO_DEVICE);
|
|
}
|
|
|
|
std::memset(data.get_ptr(), 0, data.size());
|
|
|
|
// 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
|
|
|
|
MouseTabletDataList& list = handler.GetTabletDataList(port_no);
|
|
|
|
if (list.empty() || current_info.is_null_handler || (current_info.info & CELL_MOUSE_INFO_INTERCEPTED) || !is_input_allowed())
|
|
{
|
|
list.clear();
|
|
return CELL_OK;
|
|
}
|
|
|
|
data->list_num = std::min<u32>(CELL_MOUSE_MAX_DATA_LIST_NUM, static_cast<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;
|
|
}
|
|
}
|
|
|
|
list.clear();
|
|
|
|
return CELL_OK;
|
|
}
|
|
|
|
error_code cellMouseGetRawData(u32 port_no, vm::ptr<CellMouseRawData> data)
|
|
{
|
|
cellMouse.trace("cellMouseGetRawData(port_no=%d, data=*0x%x)", port_no, data);
|
|
|
|
auto& handler = g_fxo->get<MouseHandlerBase>();
|
|
|
|
const auto init = handler.init.access();
|
|
|
|
if (!init)
|
|
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 not_an_error(CELL_MOUSE_ERROR_NO_DEVICE);
|
|
}
|
|
|
|
std::memset(data.get_ptr(), 0, data.size());
|
|
|
|
// 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);
|
|
|
|
if (current_info.is_null_handler || (current_info.info & CELL_MOUSE_INFO_INTERCEPTED) || !is_input_allowed())
|
|
{
|
|
current_data = {};
|
|
return CELL_OK;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
void cellMouse_init()
|
|
{
|
|
REG_FUNC(sys_io, cellMouseInit);
|
|
REG_FUNC(sys_io, cellMouseClearBuf);
|
|
REG_FUNC(sys_io, cellMouseEnd);
|
|
REG_FUNC(sys_io, cellMouseGetInfo);
|
|
REG_FUNC(sys_io, cellMouseInfoTabletMode);
|
|
REG_FUNC(sys_io, cellMouseGetData);
|
|
REG_FUNC(sys_io, cellMouseGetDataList);
|
|
REG_FUNC(sys_io, cellMouseSetTabletMode);
|
|
REG_FUNC(sys_io, cellMouseGetTabletDataList);
|
|
REG_FUNC(sys_io, cellMouseGetRawData);
|
|
}
|