Skip to content

Commit

Permalink
Properly integrate force feedback type-specific parameter flexibility…
Browse files Browse the repository at this point in the history
… into the DirectInput interfaces.
  • Loading branch information
samuelgr committed Oct 15, 2022
1 parent ecfd59f commit a5da917
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 6 deletions.
3 changes: 1 addition & 2 deletions Include/Xidi/ForceFeedbackEffect.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ namespace Xidi
std::optional<TypeSpecificParameterType> typeSpecificParameters = std::nullopt;


public:
protected:
// -------- CONCRETE INSTANCE METHODS ---------------------- //

/// Validates that the contents of the supplied type-specific parameters are valid.
Expand All @@ -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.
Expand Down
32 changes: 32 additions & 0 deletions Include/Xidi/Test/MockForceFeedbackEffect.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,46 @@ namespace XidiTest
/// Simply returns the received time as the output magnitude and uses a mock type-specific parameter structure.
class MockEffectWithTypeSpecificParameters : public EffectWithTypeSpecificParameters<SMockTypeSpecificParameters>
{
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
{
return newTypeSpecificParameters.valid;
}

void CheckAndFixTypeSpecificParameters(SMockTypeSpecificParameters& newTypeSpecificParameters) const override
{
if (true == canFixInvalidTypeSpecificParameters)
newTypeSpecificParameters.valid = true;
}

std::unique_ptr<Effect> Clone(void) const override
{
return std::make_unique<MockEffectWithTypeSpecificParameters>(*this);
Expand Down
6 changes: 2 additions & 4 deletions Include/Xidi/VirtualDirectInputEffect.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<Controller::ForceFeedback::Effect> updatedEffect = TypedUnderlyingEffect().Clone();
((Controller::ForceFeedback::EffectWithTypeSpecificParameters<TypeSpecificParameterType>*)updatedEffect.get())->SetTypeSpecificParameters(kTypeSpecificParameters);
if (false == ((Controller::ForceFeedback::EffectWithTypeSpecificParameters<TypeSpecificParameterType>*)updatedEffect.get())->SetTypeSpecificParameters(kTypeSpecificParameters))
return nullptr;

return std::move(updatedEffect);
}
Expand Down
37 changes: 37 additions & 0 deletions Source/Test/Case/VirtualDirectInputEffectTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(&parameters, (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(&parameters, (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)
{
Expand Down

0 comments on commit a5da917

Please sign in to comment.