diff --git a/src/common/input/InputManager.h b/src/common/input/InputManager.h index 71ab792be..628cbcf7d 100644 --- a/src/common/input/InputManager.h +++ b/src/common/input/InputManager.h @@ -157,6 +157,15 @@ struct XidSBCOutput { #pragma pack() +struct LightGunOffsets { + xbox::short_xt x; + xbox::short_xt y; +}; + +union ExtraData { + LightGunOffsets offsets; +}; + union InputBuff { XidGamepadInput ctrl; XidSBCInput sbc; @@ -170,8 +179,9 @@ struct DeviceInfo { uint8_t ucSubType; // xapi subtype uint8_t ucInputStateSize; // input state size in bytes, does not include dwPacketNumber uint8_t ucFeedbackSize; // feedback size in bytes, does not include FeedbackHeader - uint32_t dwPacketNumber; - InputBuff buff; + uint32_t dwPacketNumber; // increases by one when the input state changes + InputBuff buff; // input buffer + ExtraData data; // device-specific additional data }; struct DeviceState { diff --git a/src/core/hle/Patches.cpp b/src/core/hle/Patches.cpp index 1325a56e7..f2503ea58 100644 --- a/src/core/hle/Patches.cpp +++ b/src/core/hle/Patches.cpp @@ -346,6 +346,7 @@ std::map g_PatchTable = { PATCH_ENTRY("XInputGetState", xbox::EMUPATCH(XInputGetState), PATCH_HLE_OHCI), PATCH_ENTRY("XInputOpen", xbox::EMUPATCH(XInputOpen), PATCH_HLE_OHCI), PATCH_ENTRY("XInputPoll", xbox::EMUPATCH(XInputPoll), PATCH_HLE_OHCI), + PATCH_ENTRY("XInputSetLightgunCalibration", xbox::EMUPATCH(XInputSetLightgunCalibration), PATCH_HLE_OHCI), PATCH_ENTRY("XInputSetState", xbox::EMUPATCH(XInputSetState), PATCH_HLE_OHCI), // XAPI diff --git a/src/core/hle/XAPI/Xapi.cpp b/src/core/hle/XAPI/Xapi.cpp index dba81fc92..ee4aaf8b6 100644 --- a/src/core/hle/XAPI/Xapi.cpp +++ b/src/core/hle/XAPI/Xapi.cpp @@ -114,6 +114,7 @@ bool operator==(xbox::PXPP_DEVICE_TYPE XppType, XBOX_INPUT_DEVICE XidType) { case XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE: case XBOX_INPUT_DEVICE::MS_CONTROLLER_S: + case XBOX_INPUT_DEVICE::LIGHTGUN: case XBOX_INPUT_DEVICE::ARCADE_STICK: case XBOX_INPUT_DEVICE::HW_XBOX_CONTROLLER: { if (XppType == g_DeviceType_Gamepad) { @@ -137,7 +138,6 @@ bool operator==(xbox::PXPP_DEVICE_TYPE XppType, XBOX_INPUT_DEVICE XidType) } break; - case XBOX_INPUT_DEVICE::LIGHTGUN: case XBOX_INPUT_DEVICE::STEERING_WHEEL: case XBOX_INPUT_DEVICE::IR_DONGLE: default: @@ -154,6 +154,7 @@ void UpdateXppState(DeviceState *dev, XBOX_INPUT_DEVICE type, std::string_view p { case XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE: case XBOX_INPUT_DEVICE::MS_CONTROLLER_S: + case XBOX_INPUT_DEVICE::LIGHTGUN: case XBOX_INPUT_DEVICE::ARCADE_STICK: case XBOX_INPUT_DEVICE::HW_XBOX_CONTROLLER: xpp = g_DeviceType_Gamepad; @@ -256,6 +257,15 @@ void ConstructHleInputDevice(DeviceState *dev, DeviceState *upstream, int type, dev->info.ucFeedbackSize = sizeof(XpadOutput); break; + case to_underlying(XBOX_INPUT_DEVICE::LIGHTGUN): + dev->type = XBOX_INPUT_DEVICE::LIGHTGUN; + dev->info.bAutoPollDefault = true; + dev->info.ucType = XINPUT_DEVTYPE_GAMEPAD; + dev->info.ucSubType = XINPUT_DEVSUBTYPE_GC_LIGHTGUN; + dev->info.ucInputStateSize = sizeof(XpadInput); + dev->info.ucFeedbackSize = sizeof(XpadOutput); + break; + case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): case to_underlying(XBOX_INPUT_DEVICE::HW_STEEL_BATTALION_CONTROLLER): dev->type = XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER; @@ -325,6 +335,7 @@ void DestructHleInputDevice(DeviceState *dev) { case XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE: case XBOX_INPUT_DEVICE::MS_CONTROLLER_S: + case XBOX_INPUT_DEVICE::LIGHTGUN: dev->info.bAutoPollDefault = false; dev->info.ucType = 0; dev->info.ucSubType = 0; @@ -480,7 +491,7 @@ xbox::dword_xt CxbxImpl_XInputHandler(xbox::HANDLE hDevice, xbox::PXINPUT_STATE } if constexpr (!IsXInputPoll) { - std::memcpy((void *)&pState->Gamepad, reinterpret_cast(&g_devs[port].info.buff) + 2, g_devs[port].info.ucInputStateSize); + std::memcpy((void *)&pState->Gamepad, reinterpret_cast(&g_devs[port].info.buff) + XID_PACKET_HEADER, g_devs[port].info.ucInputStateSize); pState->dwPacketNumber = g_devs[port].info.dwPacketNumber; } @@ -787,6 +798,86 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XInputSetState) RETURN(pFeedback->Header.dwStatus); } +// ****************************************************************** +// * patch: XGetDeviceEnumerationStatus +// ****************************************************************** +xbox::dword_xt WINAPI xbox::EMUPATCH(XGetDeviceEnumerationStatus)() +{ + LOG_FUNC(); + + dword_xt ret = (g_bIsDevicesInitializing || g_bIsDevicesEmulating) ? XDEVICE_ENUMERATION_BUSY : XDEVICE_ENUMERATION_IDLE; + + RETURN(ret); +} + +// ****************************************************************** +// * patch: XInputGetDeviceDescription +// ****************************************************************** +xbox::dword_xt WINAPI xbox::EMUPATCH(XInputGetDeviceDescription) +( + HANDLE hDevice, + PXINPUT_DEVICE_DESCRIPTION pDescription +) +{ + LOG_FUNC_BEGIN + LOG_FUNC_ARG(hDevice) + LOG_FUNC_ARG(pDescription) + LOG_FUNC_END; + + dword_xt ret; + int port = static_cast(hDevice)->port_idx; + if (g_devs[port].info.hHandle == hDevice && !g_devs[port].bPendingRemoval) { + if (g_devs[port].type == XBOX_INPUT_DEVICE::LIGHTGUN) { + // These values are those reported in the device descriptor for the EMS TopGun II documented in the xboxdevwiki + pDescription->wVendorID = 0x0b9a; + pDescription->wProductID = 0x016b; + pDescription->wVersion = 0x457; + ret = ERROR_SUCCESS; + } + else { + // NOTE: Phantasy star online also calls this on the keyboard device + ret = ERROR_NOT_SUPPORTED; + } + } + else { + ret = ERROR_DEVICE_NOT_CONNECTED; + } + + RETURN(ret); +} + +// ****************************************************************** +// * patch: XInputSetLightgunCalibration +// ****************************************************************** +xbox::dword_xt WINAPI xbox::EMUPATCH(XInputSetLightgunCalibration) +( + HANDLE hDevice, + PXINPUT_LIGHTGUN_CALIBRATION_OFFSETS pCalibrationOffsets +) +{ + LOG_FUNC_BEGIN + LOG_FUNC_ARG(hDevice) + LOG_FUNC_ARG(pCalibrationOffsets) + LOG_FUNC_END; + + dword_xt ret; + int port = static_cast(hDevice)->port_idx; + if (g_devs[port].info.hHandle == hDevice && !g_devs[port].bPendingRemoval) { + if (g_devs[port].type == XBOX_INPUT_DEVICE::LIGHTGUN) { + g_devs[port].info.data.offsets.x = pCalibrationOffsets->wCenterX; + g_devs[port].info.data.offsets.y = pCalibrationOffsets->wCenterY; + ret = ERROR_SUCCESS; + } + else { + ret = ERROR_NOT_SUPPORTED; + } + } + else { + ret = ERROR_DEVICE_NOT_CONNECTED; + } + + RETURN(ret); +} // ****************************************************************** // * patch: SetThreadPriorityBoost @@ -1394,42 +1485,6 @@ xbox::dword_xt WINAPI xbox::EMUPATCH(XMountMUA) RETURN(ERROR_SUCCESS); } -// ****************************************************************** -// * patch: XGetDeviceEnumerationStatus -// ****************************************************************** -xbox::dword_xt WINAPI xbox::EMUPATCH(XGetDeviceEnumerationStatus)() -{ - - - LOG_FUNC(); - - dword_xt ret = (g_bIsDevicesInitializing || g_bIsDevicesEmulating) ? XDEVICE_ENUMERATION_BUSY : XDEVICE_ENUMERATION_IDLE; - - RETURN(ret); -} - -// ****************************************************************** -// * patch: XInputGetDeviceDescription -// ****************************************************************** -xbox::dword_xt WINAPI xbox::EMUPATCH(XInputGetDeviceDescription) -( - HANDLE hDevice, - PVOID pDescription -) -{ - - - LOG_FUNC_BEGIN - LOG_FUNC_ARG(hDevice) - LOG_FUNC_ARG(pDescription) - LOG_FUNC_END; - - // TODO: Lightgun support? - LOG_UNIMPLEMENTED(); - - RETURN(ERROR_NOT_SUPPORTED); // ERROR_DEVICE_NOT_CONNECTED; -} - // ****************************************************************** // * patch: XMountMURootA // ****************************************************************** diff --git a/src/core/hle/XAPI/Xapi.h b/src/core/hle/XAPI/Xapi.h index e28f12465..6be07729d 100644 --- a/src/core/hle/XAPI/Xapi.h +++ b/src/core/hle/XAPI/Xapi.h @@ -270,6 +270,30 @@ typedef struct _XINPUT_FEEDBACK } XINPUT_FEEDBACK, *PXINPUT_FEEDBACK; #pragma pack() + +// ****************************************************************** +// * XINPUT_DEVICE_DESCRIPTION +// ****************************************************************** +typedef struct _XINPUT_DEVICE_DESCRIPTION +{ + WORD wVendorID; + WORD wProductID; + WORD wVersion; +} +XINPUT_DEVICE_DESCRIPTION, *PXINPUT_DEVICE_DESCRIPTION; + +// ****************************************************************** +// * XINPUT_LIGHTGUN_CALIBRATION_OFFSETS +// ****************************************************************** +typedef struct _XINPUT_LIGHTGUN_CALIBRATION_OFFSETS +{ + WORD wCenterX; + WORD wCenterY; + WORD wUpperLeftX; + WORD wUpperLeftY; +} +XINPUT_LIGHTGUN_CALIBRATION_OFFSETS, *PXINPUT_LIGHTGUN_CALIBRATION_OFFSETS; + // ****************************************************************** // * RTL_HEAP_PARAMETERS // ****************************************************************** @@ -439,6 +463,28 @@ xbox::dword_xt WINAPI EMUPATCH(XInputSetState) IN OUT PXINPUT_FEEDBACK pFeedback ); +// ****************************************************************** +// * patch: XGetDeviceEnumerationStatus +// ****************************************************************** +xbox::dword_xt WINAPI EMUPATCH(XGetDeviceEnumerationStatus)(); + +// ****************************************************************** +// * patch: XInputGetDeviceDescription +// ****************************************************************** +xbox::dword_xt WINAPI EMUPATCH(XInputGetDeviceDescription) +( + HANDLE hDevice, + PXINPUT_DEVICE_DESCRIPTION pDescription +); + +// ****************************************************************** +// * patch: XInputSetLightgunCalibration +// ****************************************************************** +xbox::dword_xt WINAPI EMUPATCH(XInputSetLightgunCalibration) +( + HANDLE hDevice, + PXINPUT_LIGHTGUN_CALIBRATION_OFFSETS pCalibrationOffsets +); // ****************************************************************** // * patch: CreateMutex @@ -732,25 +778,11 @@ xbox::bool_xt WINAPI EMUPATCH(MoveFileA) LPCSTR lpNewFileName ); -// ****************************************************************** -// * patch: XGetDeviceEnumerationStatus -// ****************************************************************** -xbox::dword_xt WINAPI EMUPATCH(XGetDeviceEnumerationStatus)(); - // ****************************************************************** // * patch: SwitchToThread // ****************************************************************** xbox::bool_xt WINAPI EMUPATCH(SwitchToThread)(); -// ****************************************************************** -// * patch: XInputGetDeviceDescription -// ****************************************************************** -xbox::dword_xt WINAPI EMUPATCH(XInputGetDeviceDescription) -( - HANDLE hDevice, - PVOID pDescription -); - // ****************************************************************** // * patch: ReadFileEx // ******************************************************************