// Vita3K emulator project // Copyright (C) 2025 Vita3K team // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include #include #include #include #include #include TRACY_MODULE_NAME(SceCtrl); template <> std::string to_debug_str(const MemState &mem, SceCtrlPadInputMode type) { switch (type) { case SCE_CTRL_MODE_DIGITAL: return "SCE_CTRL_MODE_DIGITAL"; case SCE_CTRL_MODE_ANALOG: return "SCE_CTRL_MODE_ANALOG"; case SCE_CTRL_MODE_ANALOG_WIDE: return "SCE_CTRL_MODE_ANALOG_WIDE"; } return std::to_string(type); } EXPORT(int, sceCtrlClearRapidFire) { TRACY_FUNC(sceCtrlClearRapidFire); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlDisconnect) { TRACY_FUNC(sceCtrlDisconnect); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlGetAnalogStickCheckMode) { TRACY_FUNC(sceCtrlGetAnalogStickCheckMode); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlGetAnalogStickCheckTarget) { TRACY_FUNC(sceCtrlGetAnalogStickCheckTarget); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlGetBatteryInfo) { TRACY_FUNC(sceCtrlGetBatteryInfo); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlGetButtonIntercept) { TRACY_FUNC(sceCtrlGetButtonIntercept); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlGetControllerPortInfo, SceCtrlPortInfo *info) { TRACY_FUNC(sceCtrlGetControllerPortInfo, info); info->port[0] = emuenv.cfg.current_config.pstv_mode ? SCE_CTRL_TYPE_VIRT : SCE_CTRL_TYPE_PHY; for (int i = 0; i < SCE_CTRL_MAX_WIRELESS_NUM; i++) { info->port[i + 1] = (emuenv.cfg.current_config.pstv_mode && !emuenv.ctrl.free_ports[i]) ? get_type_of_controller(i) : SCE_CTRL_TYPE_UNPAIRED; } return 0; } EXPORT(int, sceCtrlGetProcessStatus) { TRACY_FUNC(sceCtrlGetProcessStatus); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlGetSamplingMode, SceCtrlPadInputMode *mode) { TRACY_FUNC(sceCtrlGetSamplingMode, mode); if (mode == nullptr) { return RET_ERROR(SCE_CTRL_ERROR_INVALID_ARG); } *mode = emuenv.ctrl.input_mode; return SCE_KERNEL_OK; } EXPORT(int, sceCtrlGetSamplingModeExt, SceCtrlPadInputMode *mode) { TRACY_FUNC(sceCtrlGetSamplingModeExt, mode); if (mode == nullptr) { return RET_ERROR(SCE_CTRL_ERROR_INVALID_ARG); } *mode = emuenv.ctrl.input_mode_ext; return SCE_KERNEL_OK; } EXPORT(int, sceCtrlGetWirelessControllerInfo, SceCtrlWirelessControllerInfo *pInfo) { TRACY_FUNC(sceCtrlGetWirelessControllerInfo, pInfo); memset(pInfo->connected, SCE_CTRL_WIRELESS_INFO_NOT_CONNECTED, sizeof(pInfo->connected)); if (emuenv.cfg.current_config.pstv_mode) { CtrlState &state = emuenv.ctrl; for (auto i = 0; i < state.controllers_num; i++) pInfo->connected[i] = SCE_CTRL_WIRELESS_INFO_CONNECTED; } return 0; } EXPORT(bool, sceCtrlIsMultiControllerSupported) { TRACY_FUNC(sceCtrlIsMultiControllerSupported); return emuenv.cfg.current_config.pstv_mode; } EXPORT(int, sceCtrlPeekBufferNegative, int port, SceCtrlData *pad_data, int count) { TRACY_FUNC(sceCtrlPeekBufferNegative, port, pad_data, count); return ctrl_get(thread_id, emuenv, port, reinterpret_cast(pad_data), count, true, true, false, false); } EXPORT(int, sceCtrlPeekBufferNegative2, int port, SceCtrlData2 *pad_data, int count) { TRACY_FUNC(sceCtrlPeekBufferNegative2, port, pad_data, count); return ctrl_get(thread_id, emuenv, port, pad_data, count, true, true, true, false); } EXPORT(int, sceCtrlPeekBufferPositive, int port, SceCtrlData *pad_data, int count) { TRACY_FUNC(sceCtrlPeekBufferPositive, port, pad_data, count); return ctrl_get(thread_id, emuenv, port, reinterpret_cast(pad_data), count, false, true, false, false); } EXPORT(int, sceCtrlPeekBufferPositive2, int port, SceCtrlData2 *pad_data, int count) { TRACY_FUNC(sceCtrlPeekBufferPositive2, port, pad_data, count); return ctrl_get(thread_id, emuenv, port, pad_data, count, false, true, true, false); } EXPORT(int, sceCtrlPeekBufferPositiveExt, int port, SceCtrlData *pad_data, int count) { TRACY_FUNC(sceCtrlPeekBufferPositiveExt, port, pad_data, count); return ctrl_get(thread_id, emuenv, port, reinterpret_cast(pad_data), count, false, true, false, true); } EXPORT(int, sceCtrlPeekBufferPositiveExt2, int port, SceCtrlData2 *pad_data, int count) { TRACY_FUNC(sceCtrlPeekBufferPositiveExt2, port, pad_data, count); return ctrl_get(thread_id, emuenv, port, pad_data, count, false, true, true, true); } EXPORT(int, sceCtrlReadBufferNegative, int port, SceCtrlData *pad_data, int count) { TRACY_FUNC(sceCtrlReadBufferNegative, port, pad_data, count); return ctrl_get(thread_id, emuenv, port, reinterpret_cast(pad_data), count, true, false, false, false); } EXPORT(int, sceCtrlReadBufferNegative2, int port, SceCtrlData2 *pad_data, int count) { TRACY_FUNC(sceCtrlReadBufferNegative2, port, pad_data, count); return ctrl_get(thread_id, emuenv, port, pad_data, count, true, false, true, false); } EXPORT(int, sceCtrlReadBufferPositive, int port, SceCtrlData *pad_data, int count) { TRACY_FUNC(sceCtrlReadBufferPositive, port, pad_data, count); return ctrl_get(thread_id, emuenv, port, reinterpret_cast(pad_data), count, false, false, false, false); } EXPORT(int, sceCtrlReadBufferPositive2, int port, SceCtrlData2 *pad_data, int count) { TRACY_FUNC(sceCtrlReadBufferPositive2, port, pad_data, count); return ctrl_get(thread_id, emuenv, port, pad_data, count, false, false, true, false); } EXPORT(int, sceCtrlReadBufferPositiveExt, int port, SceCtrlData *pad_data, int count) { TRACY_FUNC(sceCtrlReadBufferPositiveExt, port, pad_data, count); return ctrl_get(thread_id, emuenv, port, reinterpret_cast(pad_data), count, false, false, false, true); } EXPORT(int, sceCtrlReadBufferPositiveExt2, int port, SceCtrlData2 *pad_data, int count) { TRACY_FUNC(sceCtrlReadBufferPositiveExt2, port, pad_data, count); return ctrl_get(thread_id, emuenv, port, pad_data, count, false, false, true, true); } EXPORT(int, sceCtrlRegisterBdRMCCallback) { TRACY_FUNC(sceCtrlRegisterBdRMCCallback); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlResetLightBar) { TRACY_FUNC(sceCtrlResetLightBar); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlSetActuator, int port, const SceCtrlActuator *pState) { TRACY_FUNC(sceCtrlSetActuator, port, pState); if (!emuenv.cfg.current_config.pstv_mode) { return RET_ERROR(SCE_CTRL_ERROR_NOT_SUPPORTED); } CtrlState &state = emuenv.ctrl; for (const auto &controller : state.controllers) { if (controller.second.port + 1 == port) { // sceCtrl ports are 1-based and SDL_GameController index is 0-based. Need to convert. SDL_GameControllerRumble(controller.second.controller.get(), pState->small * 655.35f, pState->large * 655.35f, SDL_HAPTIC_INFINITY); return 0; } } return RET_ERROR(SCE_CTRL_ERROR_NO_DEVICE); } EXPORT(int, sceCtrlSetAnalogStickCheckMode) { TRACY_FUNC(sceCtrlSetAnalogStickCheckMode); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlSetAnalogStickCheckTarget) { TRACY_FUNC(sceCtrlSetAnalogStickCheckTarget); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlSetButtonIntercept) { TRACY_FUNC(sceCtrlSetButtonIntercept); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlSetButtonRemappingInfo) { TRACY_FUNC(sceCtrlSetButtonRemappingInfo); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlSetLightBar) { TRACY_FUNC(sceCtrlSetLightBar); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlSetRapidFire) { TRACY_FUNC(sceCtrlSetRapidFire); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlSetSamplingMode, SceCtrlPadInputMode mode) { TRACY_FUNC(sceCtrlSetSamplingMode, mode); SceCtrlPadInputMode old = emuenv.ctrl.input_mode; if (mode < SCE_CTRL_MODE_DIGITAL || mode > SCE_CTRL_MODE_ANALOG_WIDE) { return RET_ERROR(SCE_CTRL_ERROR_INVALID_ARG); } emuenv.ctrl.input_mode = mode; return old; } EXPORT(int, sceCtrlSetSamplingModeExt, SceCtrlPadInputMode mode) { TRACY_FUNC(sceCtrlSetSamplingModeExt, mode); SceCtrlPadInputMode old = emuenv.ctrl.input_mode_ext; if (mode < SCE_CTRL_MODE_DIGITAL || mode > SCE_CTRL_MODE_ANALOG_WIDE) { return RET_ERROR(SCE_CTRL_ERROR_INVALID_ARG); } emuenv.ctrl.input_mode_ext = mode; return old; } EXPORT(int, sceCtrlSingleControllerMode) { TRACY_FUNC(sceCtrlSingleControllerMode); return UNIMPLEMENTED(); } EXPORT(int, sceCtrlUnregisterBdRMCCallback) { TRACY_FUNC(sceCtrlUnregisterBdRMCCallback); return UNIMPLEMENTED(); }