diff --git a/Include/Xidi/ForceFeedbackEffect.h b/Include/Xidi/ForceFeedbackEffect.h index 7300d1b..237a07b 100644 --- a/Include/Xidi/ForceFeedbackEffect.h +++ b/Include/Xidi/ForceFeedbackEffect.h @@ -380,7 +380,7 @@ namespace Xidi std::optional typeSpecificParameters = std::nullopt; - public: + protected: // -------- CONCRETE INSTANCE METHODS ---------------------- // /// Validates that the contents of the supplied type-specific parameters are valid. @@ -402,7 +402,6 @@ namespace Xidi // Nothing to do here. } - protected: /// Default implementation of checking that this type-specific event is completely defined, which simply verifies that type-specific parameters exist. /// Subclasses that define more complex type-specific parameters or need to do other checks can override this method. /// @return `true` if all type-specific parameters are valid and have been defined, `false` otherwise. diff --git a/Include/Xidi/Test/MockForceFeedbackEffect.h b/Include/Xidi/Test/MockForceFeedbackEffect.h index 7118a62..d97b7de 100644 --- a/Include/Xidi/Test/MockForceFeedbackEffect.h +++ b/Include/Xidi/Test/MockForceFeedbackEffect.h @@ -62,7 +62,33 @@ namespace XidiTest /// Simply returns the received time as the output magnitude and uses a mock type-specific parameter structure. class MockEffectWithTypeSpecificParameters : public EffectWithTypeSpecificParameters { + private: + // -------- INSTANCE VARIABLES ------------------------------------- // + + /// Specifies if whatever error might be present in a set of invalid type-specific parameters can be automatically fixed. + bool canFixInvalidTypeSpecificParameters = false; + + public: + // -------- INSTANCE METHODS --------------------------------------- // + + /// Retrieves whether or not this effect's type-specific parameters have an error that can automatically be fixed somehow. + /// This value is intended to be set by tests exercising automatic fixing of type-specific parameter errors. + /// @return `true` if so, `false` if not. + inline bool GetCanFixInvalidTypeSpecificParameters(void) + { + return canFixInvalidTypeSpecificParameters; + } + + /// Enables or disables this effect's ability to fix an error in type-specific parameters. + /// This value is intended to be set by tests exercising automatic fixing of type-specific parameter errors. + /// @param [in] newCanFixInvalidTypeSpecificParameters Whether or not an error should be considered fixable. + inline void SetCanFixInvalidTypeSpecificParameters(bool newCanFixInvalidTypeSpecificParameters) + { + canFixInvalidTypeSpecificParameters = newCanFixInvalidTypeSpecificParameters; + } + + // -------- CONCRETE INSTANCE METHODS ------------------------------ // bool AreTypeSpecificParametersValid(const SMockTypeSpecificParameters& newTypeSpecificParameters) const override @@ -70,6 +96,12 @@ namespace XidiTest return newTypeSpecificParameters.valid; } + void CheckAndFixTypeSpecificParameters(SMockTypeSpecificParameters& newTypeSpecificParameters) const override + { + if (true == canFixInvalidTypeSpecificParameters) + newTypeSpecificParameters.valid = true; + } + std::unique_ptr Clone(void) const override { return std::make_unique(*this); diff --git a/Include/Xidi/VirtualDirectInputEffect.h b/Include/Xidi/VirtualDirectInputEffect.h index d3cd495..c1d567e 100644 --- a/Include/Xidi/VirtualDirectInputEffect.h +++ b/Include/Xidi/VirtualDirectInputEffect.h @@ -241,11 +241,9 @@ namespace Xidi const DirectInputTypeSpecificParameterType& kDirectInputTypeSpecificParams = *((DirectInputTypeSpecificParameterType*)peff->lpvTypeSpecificParams); const TypeSpecificParameterType kTypeSpecificParameters = ConvertFromDirectInput(kDirectInputTypeSpecificParams); - if (false == TypedUnderlyingEffect().AreTypeSpecificParametersValid(kTypeSpecificParameters)) - return nullptr; - std::unique_ptr updatedEffect = TypedUnderlyingEffect().Clone(); - ((Controller::ForceFeedback::EffectWithTypeSpecificParameters*)updatedEffect.get())->SetTypeSpecificParameters(kTypeSpecificParameters); + if (false == ((Controller::ForceFeedback::EffectWithTypeSpecificParameters*)updatedEffect.get())->SetTypeSpecificParameters(kTypeSpecificParameters)) + return nullptr; return std::move(updatedEffect); } diff --git a/Source/Test/Case/VirtualDirectInputEffectTest.cpp b/Source/Test/Case/VirtualDirectInputEffectTest.cpp index 7505b98..f20dfbf 100644 --- a/Source/Test/Case/VirtualDirectInputEffectTest.cpp +++ b/Source/Test/Case/VirtualDirectInputEffectTest.cpp @@ -630,6 +630,43 @@ namespace XidiTest TEST_ASSERT(actualTypeSpecificParameters == expectedTypeSpecificParameters); } + // Type-specific parameters that are invalid and cannot be automatically fixed + TEST_CASE(VirtualDirectInputEffect_SetParameters_InvalidTypeSpecificParameters) + { + auto physicalController = CreateMockPhysicalController(); + auto diDevice = CreateAndAcquireTestDirectInputDevice(*physicalController); + auto diEffect = CreateTestDirectInputEffect(*diDevice); + + MockEffectWithTypeSpecificParameters& ffEffect = (MockEffectWithTypeSpecificParameters&)diEffect->UnderlyingEffect(); + ffEffect.SetCanFixInvalidTypeSpecificParameters(false); + + SMockTypeSpecificParameters invalidTypeSpecificParameters = {.valid = false, .param1 = 1000, .param2 = 2000}; + DIEFFECT parameters = {.dwSize = sizeof(DIEFFECT), .cbTypeSpecificParams = sizeof(invalidTypeSpecificParameters), .lpvTypeSpecificParams = &invalidTypeSpecificParameters}; + TEST_ASSERT(DIERR_INVALIDPARAM == diEffect->SetParametersInternal(¶meters, (DIEP_TYPESPECIFICPARAMS | DIEP_NODOWNLOAD))); + TEST_ASSERT(false == ffEffect.HasTypeSpecificParameters()); + } + + // Type-specific parameters that are invalid but can be automatically fixed + TEST_CASE(VirtualDirectInputEffect_SetParameters_InvalidFixableTypeSpecificParameters) + { + auto physicalController = CreateMockPhysicalController(); + auto diDevice = CreateAndAcquireTestDirectInputDevice(*physicalController); + auto diEffect = CreateTestDirectInputEffect(*diDevice); + + MockEffectWithTypeSpecificParameters& ffEffect = (MockEffectWithTypeSpecificParameters&)diEffect->UnderlyingEffect(); + ffEffect.SetCanFixInvalidTypeSpecificParameters(true); + + SMockTypeSpecificParameters invalidTypeSpecificParameters = {.valid = false, .param1 = 1000, .param2 = 2000}; + DIEFFECT parameters = {.dwSize = sizeof(DIEFFECT), .cbTypeSpecificParams = sizeof(invalidTypeSpecificParameters), .lpvTypeSpecificParams = &invalidTypeSpecificParameters}; + TEST_ASSERT(DI_DOWNLOADSKIPPED == diEffect->SetParametersInternal(¶meters, (DIEP_TYPESPECIFICPARAMS | DIEP_NODOWNLOAD))); + + TEST_ASSERT(true == ffEffect.HasTypeSpecificParameters()); + + const SMockTypeSpecificParameters kExpectedTypeSpecificParameters = {.valid = true, .param1 = invalidTypeSpecificParameters.param1, .param2 = invalidTypeSpecificParameters.param2}; + const SMockTypeSpecificParameters kActualTypeSpecificParameters = ffEffect.GetTypeSpecificParameters().value(); + TEST_ASSERT(kActualTypeSpecificParameters == kExpectedTypeSpecificParameters); + } + // Specifies a complete set of parameters and automatically downloads, but does not start, the effect. TEST_CASE(VirtualDirectInputEffect_SetParameters_CompleteAndDownload) {