can bind OSC message to game inputs

This commit is contained in:
monsieurgustav
2015-02-04 22:35:23 +01:00
parent 852682cd6f
commit bde87ae9dc
15 changed files with 208 additions and 51 deletions
+3
View File
@@ -17,6 +17,9 @@ namespace UnrealBuildTool.Rules
"CoreUObject",
"Engine",
"Sockets",
"InputCore",
"Slate",
"SlateCore",
}
);
@@ -121,6 +121,7 @@ struct FOscDataElemStruct
//-------------------------------------------------------------------------
/// Cast the value to T.
template <class T>
T GetValue() const
{
+7
View File
@@ -61,8 +61,12 @@ public:
virtual void ShutdownModule( ) override
{
UE_LOG(LogOSC, Display, TEXT("Shutdown"));
if(_dispatcher.IsValid())
{
auto settings = GetMutableDefault<UOscSettings>();
settings->ClearKeyInputs(*_dispatcher);
_dispatcher->Stop();
}
}
@@ -94,6 +98,9 @@ public:
// send settings
settings->UpdateSendAddresses();
// input settings
settings->UpdateKeyInputs(*_dispatcher);
return true;
}
+24
View File
@@ -1,5 +1,8 @@
#include "OscPrivatePCH.h"
#include "OscReceiverInputKey.h"
#include "OscDispatcher.h"
UOscSettings::UOscSettings( const class FPostConstructInitializeProperties& PCIP )
: Super(PCIP),
@@ -100,3 +103,24 @@ bool UOscSettings::Parse(const FString & address_port, FIPv4Address * address, u
*port = portResult;
return true;
}
void UOscSettings::ClearKeyInputs(UOscDispatcher & dispatcher)
{
for(auto & receiver : _keyReceivers)
{
// Unregister here, not in the OscReceiverInputKey destructor
// because it would crash at the application exit.
dispatcher.UnregisterReceiver(&receiver);
}
_keyReceivers.Reset(0);
}
void UOscSettings::UpdateKeyInputs(UOscDispatcher & dispatcher)
{
ClearKeyInputs(dispatcher);
for(const auto & address : Inputs)
{
_keyReceivers.Emplace(address);
dispatcher.RegisterReceiver(&_keyReceivers.Last());
}
}
+17 -2
View File
@@ -1,10 +1,11 @@
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#pragma once
#include <utility>
#include "OscSettings.generated.h"
class OscReceiverInputKey;
class UOscDispatcher;
UCLASS(config=Engine)
class UOscSettings : public UObject
@@ -27,11 +28,24 @@ public:
UPROPERTY(Config, EditAnywhere, Category=Send)
TArray<FString> SendTargets;
/**
* List of the messages treated as inputs.
*
* Every entry adds a key in the input mapping project setting.
* e.g. "/position/x" -> "OSC_position_x"
*/
UPROPERTY(Config, EditAnywhere, Category=Input)
TArray<FString> Inputs;
public:
void UpdateSendAddresses();
void Send(const uint8 *buffer, int32 length, int32 targetIndex);
void ClearKeyInputs(UOscDispatcher & dispatcher);
void UpdateKeyInputs(UOscDispatcher & dispatcher);
public:
/**
@@ -43,4 +57,5 @@ public:
private:
TSharedRef<FSocket> _sendSocket;
TArray<std::pair<FString, TSharedRef<FInternetAddr>>> _sendAddresses;
TArray<OscReceiverInputKey> _keyReceivers;
};
@@ -70,11 +70,13 @@ void UOscDispatcher::Stop()
void UOscDispatcher::RegisterReceiver(IOscReceiverInterface * receiver)
{
FScopeLock ScopeLock(&_receiversMutex);
_receivers.AddUnique(receiver);
}
void UOscDispatcher::UnregisterReceiver(IOscReceiverInterface * receiver)
{
FScopeLock ScopeLock(&_receiversMutex);
_receivers.Remove(receiver);
}
@@ -176,6 +178,8 @@ void UOscDispatcher::Callback(const FArrayReaderPtr& data, const FIPv4Endpoint&)
void UOscDispatcher::CallbackMainThread()
{
FScopeLock ScopeLock(&_receiversMutex);
std::pair<FName, TArray<FOscDataElemStruct>> message;
while(_pendingMessages.Dequeue(message))
{
@@ -3,7 +3,7 @@
#include "OscDataElemStruct.h"
#include "OscDispatcher.generated.h"
class IOscReceiverInterface;
struct IOscReceiverInterface;
class FSocket;
class FUdpSocketReceiver;
@@ -45,4 +45,7 @@ private:
FSocket * _socket;
FUdpSocketReceiver * _socketReceiver;
TCircularQueue<std::pair<FName, TArray<FOscDataElemStruct>>> _pendingMessages;
/// Protects _receivers
FCriticalSection _receiversMutex;
};
@@ -4,12 +4,13 @@
AOscReceiverActor::AOscReceiverActor(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
: Super(PCIP),
_listener(this)
{
auto instance = UOscDispatcher::Get();
if (instance && !HasAnyFlags(RF_ClassDefaultObject))
{
instance->RegisterReceiver(this);
instance->RegisterReceiver(&_listener);
}
}
@@ -18,7 +19,7 @@ void AOscReceiverActor::BeginDestroy()
auto instance = UOscDispatcher::Get();
if (instance && !HasAnyFlags(RF_ClassDefaultObject))
{
instance->UnregisterReceiver(this);
instance->UnregisterReceiver(&_listener);
}
Super::BeginDestroy();
@@ -7,7 +7,7 @@
UCLASS()
class AOscReceiverActor : public AActor, public IOscReceiverInterface
class AOscReceiverActor : public AActor
{
GENERATED_UCLASS_BODY()
@@ -17,17 +17,20 @@ class AOscReceiverActor : public AActor, public IOscReceiverInterface
UFUNCTION(BlueprintImplementableEvent, Category=OSC)
void OnOscReceived(const FName & Address, const TArray<FOscDataElemStruct> & Data);
protected:
virtual void BeginDestroy() override;
virtual const FString & GetAddressFilter() override
public:
const FString & GetAddressFilter() const
{
return AddressFilter;
}
virtual void SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data) override
void SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data)
{
OnOscReceived(Address, Data);
}
private:
void BeginDestroy() override;
private:
BasicOscReceiver<AOscReceiverActor> _listener;
};
@@ -4,7 +4,8 @@
UOscReceiverComponent::UOscReceiverComponent(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
: Super(PCIP),
_listener(this)
{
}
@@ -16,7 +17,7 @@ void UOscReceiverComponent::OnRegister()
auto instance = UOscDispatcher::Get();
if (instance && !HasAnyFlags(RF_ClassDefaultObject))
{
instance->RegisterReceiver(this);
instance->RegisterReceiver(&_listener);
}
}
@@ -25,7 +26,7 @@ void UOscReceiverComponent::OnUnregister()
auto instance = UOscDispatcher::Get();
if (instance && !HasAnyFlags(RF_ClassDefaultObject))
{
instance->UnregisterReceiver(this);
instance->UnregisterReceiver(&_listener);
}
Super::OnUnregister();
@@ -11,7 +11,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FComponentOscReceivedSignature, con
UCLASS(meta = (BlueprintSpawnableComponent))
class UOscReceiverComponent : public UActorComponent, public IOscReceiverInterface
class UOscReceiverComponent : public UActorComponent
{
GENERATED_UCLASS_BODY()
@@ -21,18 +21,22 @@ class UOscReceiverComponent : public UActorComponent, public IOscReceiverInterfa
UPROPERTY(BlueprintAssignable, Category=OSC)
FComponentOscReceivedSignature OnOscReceived;
protected:
virtual void OnRegister() override;
virtual void OnUnregister() override;
virtual const FString & GetAddressFilter() override
public:
const FString & GetAddressFilter() const
{
return AddressFilter;
}
virtual void SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data) override
void SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data)
{
OnOscReceived.Broadcast(Address, Data);
}
private:
void OnRegister() override;
void OnUnregister() override;
private:
BasicOscReceiver<UOscReceiverComponent> _listener;
};
@@ -0,0 +1,62 @@
#include "OscPrivatePCH.h"
#include "OscReceiverInputKey.h"
#include "OscDispatcher.h"
#include "SlateBasics.h"
OscReceiverInputKey::OscReceiverInputKey(const FString &address)
: _address(address),
_addressName(*address)
{
char buffer[512]; // address truncated after 500 chars.
const auto length = sprintf(buffer, "OSC%.500s", StringCast<ANSICHAR>(*address).Get());
// replace '/' by '_' because '/' is not a valid FKey character.
for(int i=0; i!=length; ++i)
{
if(buffer[i] == '/')
{
buffer[i] = '_';
}
}
_key = FName(buffer);
RegisterKey();
}
void OscReceiverInputKey::RegisterKey() const
{
if(!_address.IsEmpty() && !EKeys::GetKeyDetails(_key).IsValid())
{
EKeys::AddKey(FKeyDetails(_key,
FText::FromString(_key.ToString()),
FKeyDetails::FloatAxis));
}
}
void OscReceiverInputKey::SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data)
{
if(Address != _addressName)
{
return;
}
auto & app = FSlateApplication::Get();
const auto value = Data.Num() ? Data[0].GetValue<float>() : 0.f;
FKeyEvent keyEvent(_key, app.GetModifierKeys(), 0, false, 0, 0);
if(value < 0.5f)
{
app.ProcessKeyDownEvent(keyEvent);
}
else
{
app.ProcessKeyUpEvent(keyEvent);
}
FAnalogInputEvent axisEvent(_key, app.GetModifierKeys(), 0, false, 0, 0, value);
app.ProcessAnalogInputEvent(axisEvent);
}
@@ -0,0 +1,33 @@
#pragma once
#include "InputCoreTypes.h"
#include "OscReceiverInterface.h"
#include "OscDataElemStruct.h"
class OscReceiverInputKey : public IOscReceiverInterface
{
public:
OscReceiverInputKey(const FString & address);
OscReceiverInputKey(const OscReceiverInputKey &) = delete;
OscReceiverInputKey& operator=(const OscReceiverInputKey &) = delete;
private:
/// Adds the custom input key to the Slate application.
void RegisterKey() const;
const FString & GetAddressFilter() const override
{
return _address;
}
void SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data) override;
private:
FString _address;
FName _addressName;
FKey _key;
};
@@ -1,18 +0,0 @@
#include "OscPrivatePCH.h"
#include "OscReceiverInterface.h"
UOscReceiverInterface::UOscReceiverInterface(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
}
const FString & IOscReceiverInterface::GetAddressFilter()
{
static FString defaultValue;
return defaultValue;
}
void IOscReceiverInterface::SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data)
{ }
@@ -1,19 +1,33 @@
#pragma once
#include "OscDataElemStruct.h"
#include "OscReceiverInterface.generated.h"
UINTERFACE(MinimalAPI)
class UOscReceiverInterface : public UInterface
/// Base class to receive OSC messages.
struct IOscReceiverInterface
{
GENERATED_UINTERFACE_BODY()
virtual const FString & GetAddressFilter() const = 0;
virtual void SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data) = 0;
};
class IOscReceiverInterface
{
GENERATED_IINTERFACE_BODY()
virtual const FString & GetAddressFilter();
virtual void SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data);
/// Forward calls to an impl object.
template <class T>
struct BasicOscReceiver : IOscReceiverInterface
{
T * const _impl;
BasicOscReceiver(T * impl) : _impl(impl)
{
}
const FString & GetAddressFilter() const final
{
return _impl->GetAddressFilter();
}
void SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data) final
{
_impl->SendEvent(Address, Data);
}
};