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", "CoreUObject",
"Engine", "Engine",
"Sockets", "Sockets",
"InputCore",
"Slate",
"SlateCore",
} }
); );
@@ -121,6 +121,7 @@ struct FOscDataElemStruct
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
/// Cast the value to T.
template <class T> template <class T>
T GetValue() const T GetValue() const
{ {
+7
View File
@@ -61,8 +61,12 @@ public:
virtual void ShutdownModule( ) override virtual void ShutdownModule( ) override
{ {
UE_LOG(LogOSC, Display, TEXT("Shutdown")); UE_LOG(LogOSC, Display, TEXT("Shutdown"));
if(_dispatcher.IsValid()) if(_dispatcher.IsValid())
{ {
auto settings = GetMutableDefault<UOscSettings>();
settings->ClearKeyInputs(*_dispatcher);
_dispatcher->Stop(); _dispatcher->Stop();
} }
} }
@@ -94,6 +98,9 @@ public:
// send settings // send settings
settings->UpdateSendAddresses(); settings->UpdateSendAddresses();
// input settings
settings->UpdateKeyInputs(*_dispatcher);
return true; return true;
} }
+24
View File
@@ -1,5 +1,8 @@
#include "OscPrivatePCH.h" #include "OscPrivatePCH.h"
#include "OscReceiverInputKey.h"
#include "OscDispatcher.h"
UOscSettings::UOscSettings( const class FPostConstructInitializeProperties& PCIP ) UOscSettings::UOscSettings( const class FPostConstructInitializeProperties& PCIP )
: Super(PCIP), : Super(PCIP),
@@ -100,3 +103,24 @@ bool UOscSettings::Parse(const FString & address_port, FIPv4Address * address, u
*port = portResult; *port = portResult;
return true; 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 #pragma once
#include <utility> #include <utility>
#include "OscSettings.generated.h" #include "OscSettings.generated.h"
class OscReceiverInputKey;
class UOscDispatcher;
UCLASS(config=Engine) UCLASS(config=Engine)
class UOscSettings : public UObject class UOscSettings : public UObject
@@ -27,11 +28,24 @@ public:
UPROPERTY(Config, EditAnywhere, Category=Send) UPROPERTY(Config, EditAnywhere, Category=Send)
TArray<FString> SendTargets; 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: public:
void UpdateSendAddresses(); void UpdateSendAddresses();
void Send(const uint8 *buffer, int32 length, int32 targetIndex); void Send(const uint8 *buffer, int32 length, int32 targetIndex);
void ClearKeyInputs(UOscDispatcher & dispatcher);
void UpdateKeyInputs(UOscDispatcher & dispatcher);
public: public:
/** /**
@@ -43,4 +57,5 @@ public:
private: private:
TSharedRef<FSocket> _sendSocket; TSharedRef<FSocket> _sendSocket;
TArray<std::pair<FString, TSharedRef<FInternetAddr>>> _sendAddresses; TArray<std::pair<FString, TSharedRef<FInternetAddr>>> _sendAddresses;
TArray<OscReceiverInputKey> _keyReceivers;
}; };
@@ -70,11 +70,13 @@ void UOscDispatcher::Stop()
void UOscDispatcher::RegisterReceiver(IOscReceiverInterface * receiver) void UOscDispatcher::RegisterReceiver(IOscReceiverInterface * receiver)
{ {
FScopeLock ScopeLock(&_receiversMutex);
_receivers.AddUnique(receiver); _receivers.AddUnique(receiver);
} }
void UOscDispatcher::UnregisterReceiver(IOscReceiverInterface * receiver) void UOscDispatcher::UnregisterReceiver(IOscReceiverInterface * receiver)
{ {
FScopeLock ScopeLock(&_receiversMutex);
_receivers.Remove(receiver); _receivers.Remove(receiver);
} }
@@ -176,6 +178,8 @@ void UOscDispatcher::Callback(const FArrayReaderPtr& data, const FIPv4Endpoint&)
void UOscDispatcher::CallbackMainThread() void UOscDispatcher::CallbackMainThread()
{ {
FScopeLock ScopeLock(&_receiversMutex);
std::pair<FName, TArray<FOscDataElemStruct>> message; std::pair<FName, TArray<FOscDataElemStruct>> message;
while(_pendingMessages.Dequeue(message)) while(_pendingMessages.Dequeue(message))
{ {
@@ -3,7 +3,7 @@
#include "OscDataElemStruct.h" #include "OscDataElemStruct.h"
#include "OscDispatcher.generated.h" #include "OscDispatcher.generated.h"
class IOscReceiverInterface; struct IOscReceiverInterface;
class FSocket; class FSocket;
class FUdpSocketReceiver; class FUdpSocketReceiver;
@@ -45,4 +45,7 @@ private:
FSocket * _socket; FSocket * _socket;
FUdpSocketReceiver * _socketReceiver; FUdpSocketReceiver * _socketReceiver;
TCircularQueue<std::pair<FName, TArray<FOscDataElemStruct>>> _pendingMessages; TCircularQueue<std::pair<FName, TArray<FOscDataElemStruct>>> _pendingMessages;
/// Protects _receivers
FCriticalSection _receiversMutex;
}; };
@@ -4,12 +4,13 @@
AOscReceiverActor::AOscReceiverActor(const class FPostConstructInitializeProperties& PCIP) AOscReceiverActor::AOscReceiverActor(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP) : Super(PCIP),
_listener(this)
{ {
auto instance = UOscDispatcher::Get(); auto instance = UOscDispatcher::Get();
if (instance && !HasAnyFlags(RF_ClassDefaultObject)) if (instance && !HasAnyFlags(RF_ClassDefaultObject))
{ {
instance->RegisterReceiver(this); instance->RegisterReceiver(&_listener);
} }
} }
@@ -18,7 +19,7 @@ void AOscReceiverActor::BeginDestroy()
auto instance = UOscDispatcher::Get(); auto instance = UOscDispatcher::Get();
if (instance && !HasAnyFlags(RF_ClassDefaultObject)) if (instance && !HasAnyFlags(RF_ClassDefaultObject))
{ {
instance->UnregisterReceiver(this); instance->UnregisterReceiver(&_listener);
} }
Super::BeginDestroy(); Super::BeginDestroy();
@@ -7,7 +7,7 @@
UCLASS() UCLASS()
class AOscReceiverActor : public AActor, public IOscReceiverInterface class AOscReceiverActor : public AActor
{ {
GENERATED_UCLASS_BODY() GENERATED_UCLASS_BODY()
@@ -17,17 +17,20 @@ class AOscReceiverActor : public AActor, public IOscReceiverInterface
UFUNCTION(BlueprintImplementableEvent, Category=OSC) UFUNCTION(BlueprintImplementableEvent, Category=OSC)
void OnOscReceived(const FName & Address, const TArray<FOscDataElemStruct> & Data); void OnOscReceived(const FName & Address, const TArray<FOscDataElemStruct> & Data);
protected: public:
const FString & GetAddressFilter() const
virtual void BeginDestroy() override;
virtual const FString & GetAddressFilter() override
{ {
return AddressFilter; 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); OnOscReceived(Address, Data);
} }
private:
void BeginDestroy() override;
private:
BasicOscReceiver<AOscReceiverActor> _listener;
}; };
@@ -4,7 +4,8 @@
UOscReceiverComponent::UOscReceiverComponent(const class FPostConstructInitializeProperties& PCIP) UOscReceiverComponent::UOscReceiverComponent(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP) : Super(PCIP),
_listener(this)
{ {
} }
@@ -16,7 +17,7 @@ void UOscReceiverComponent::OnRegister()
auto instance = UOscDispatcher::Get(); auto instance = UOscDispatcher::Get();
if (instance && !HasAnyFlags(RF_ClassDefaultObject)) if (instance && !HasAnyFlags(RF_ClassDefaultObject))
{ {
instance->RegisterReceiver(this); instance->RegisterReceiver(&_listener);
} }
} }
@@ -25,7 +26,7 @@ void UOscReceiverComponent::OnUnregister()
auto instance = UOscDispatcher::Get(); auto instance = UOscDispatcher::Get();
if (instance && !HasAnyFlags(RF_ClassDefaultObject)) if (instance && !HasAnyFlags(RF_ClassDefaultObject))
{ {
instance->UnregisterReceiver(this); instance->UnregisterReceiver(&_listener);
} }
Super::OnUnregister(); Super::OnUnregister();
@@ -11,7 +11,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FComponentOscReceivedSignature, con
UCLASS(meta = (BlueprintSpawnableComponent)) UCLASS(meta = (BlueprintSpawnableComponent))
class UOscReceiverComponent : public UActorComponent, public IOscReceiverInterface class UOscReceiverComponent : public UActorComponent
{ {
GENERATED_UCLASS_BODY() GENERATED_UCLASS_BODY()
@@ -21,18 +21,22 @@ class UOscReceiverComponent : public UActorComponent, public IOscReceiverInterfa
UPROPERTY(BlueprintAssignable, Category=OSC) UPROPERTY(BlueprintAssignable, Category=OSC)
FComponentOscReceivedSignature OnOscReceived; FComponentOscReceivedSignature OnOscReceived;
protected: public:
virtual void OnRegister() override; const FString & GetAddressFilter() const
virtual void OnUnregister() override;
virtual const FString & GetAddressFilter() override
{ {
return AddressFilter; 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); 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 #pragma once
#include "OscDataElemStruct.h" #include "OscDataElemStruct.h"
#include "OscReceiverInterface.generated.h"
UINTERFACE(MinimalAPI) /// Base class to receive OSC messages.
class UOscReceiverInterface : public UInterface 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(); /// Forward calls to an impl object.
virtual void SendEvent(const FName & Address, const TArray<FOscDataElemStruct> & Data); 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);
}
}; };