|
|
@ -3,79 +3,64 @@ |
|
|
|
#include "dllmain.h"
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
#include <thread>
|
|
|
|
#include "osc/OscReceivedElements.h"
|
|
|
|
#include "osc/OscPacketListener.h"
|
|
|
|
#include "ip/UdpSocket.h"
|
|
|
|
|
|
|
|
class ExamplePacketListener : public osc::OscPacketListener { |
|
|
|
//Class from OSC library (oscpack). This calls our handleOscMsg() on every new message.
|
|
|
|
class ThePacketListener : public osc::OscPacketListener { |
|
|
|
protected: |
|
|
|
|
|
|
|
virtual void ProcessMessage(const osc::ReceivedMessage& m, |
|
|
|
const IpEndpointName& remoteEndpoint) |
|
|
|
{ |
|
|
|
OutputDebugString(L"Got OSC Message!\r\n"); |
|
|
|
(void)remoteEndpoint; // suppress unused parameter warning
|
|
|
|
|
|
|
|
try { |
|
|
|
// example of parsing single messages. osc::OsckPacketListener
|
|
|
|
// handles the bundle traversal.
|
|
|
|
|
|
|
|
if (std::strcmp(m.AddressPattern(), "/test1") == 0) { |
|
|
|
// example #1 -- argument stream interface
|
|
|
|
osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); |
|
|
|
bool a1; |
|
|
|
osc::int32 a2; |
|
|
|
float a3; |
|
|
|
const char* a4; |
|
|
|
args >> a1 >> a2 >> a3 >> a4 >> osc::EndMessage; |
|
|
|
OutputDebugString(L"received '/test1' message with arguments: ... "); |
|
|
|
//std::cout << "received '/test1' message with arguments: "
|
|
|
|
// << a1 << " " << a2 << " " << a3 << " " << a4 << "\n";
|
|
|
|
|
|
|
|
} |
|
|
|
else if (std::strcmp(m.AddressPattern(), "/test2") == 0) { |
|
|
|
// example #2 -- argument iterator interface, supports
|
|
|
|
// reflection for overloaded messages (eg you can call
|
|
|
|
// (*arg)->IsBool() to check if a bool was passed etc).
|
|
|
|
osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin(); |
|
|
|
//bool a1 = (arg++)->AsBool();
|
|
|
|
//int a2 = (arg++)->AsInt32();
|
|
|
|
//float a3 = (arg++)->AsFloat();
|
|
|
|
const char* a4 = (arg++)->AsString(); |
|
|
|
//if (arg != m.ArgumentsEnd())
|
|
|
|
//throw osc::ExcessArgumentException();
|
|
|
|
|
|
|
|
OutputDebugString(L"received '/test2' message with argument: "); |
|
|
|
OutputDebugStringA(a4); |
|
|
|
OutputDebugString(L"\r\n"); |
|
|
|
//std::cout << "received '/test2' message with arguments: "
|
|
|
|
// << a1 << " " << a2 << " " << a3 << " " << a4 << "\n";
|
|
|
|
} |
|
|
|
try { |
|
|
|
handleOscMsg(m); |
|
|
|
} |
|
|
|
catch (osc::Exception& e) { |
|
|
|
// any parsing errors such as unexpected argument types, or
|
|
|
|
// missing arguments get thrown as exceptions.
|
|
|
|
OutputDebugString(L"error while parsing message: ..."); |
|
|
|
//std::cout << "error while parsing message: "
|
|
|
|
// << m.AddressPattern() << ": " << e.what() << "\n";
|
|
|
|
OutputDebugString(L"ProcessMessage: Error while parsing message: ..."); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
/* Definition and declaration of the OSC Listeners.
|
|
|
|
/* Definition and declaration of the registered OSC Listeners.
|
|
|
|
* Contains OSC addresses to listen to and OS message ID to send for each |
|
|
|
* address */ |
|
|
|
* address. These are populated from the AHK script! */ |
|
|
|
struct Listener { |
|
|
|
std::string address; |
|
|
|
unsigned int dataType; |
|
|
|
unsigned int message; |
|
|
|
}; |
|
|
|
std::vector<Listener> listeners; |
|
|
|
/* Handle to the calling window */ |
|
|
|
/* Handle to the calling window, also indicates if this OSC receiver is "opened" by being != NULL*/ |
|
|
|
HWND hwnd = NULL; |
|
|
|
ExamplePacketListener* examplePacketListener; |
|
|
|
/* OSC receiving objects and thread.
|
|
|
|
* From within these, our handleOscMsg() function is called. */ |
|
|
|
ThePacketListener* thePacketListener; |
|
|
|
UdpListeningReceiveSocket* sock; |
|
|
|
std::thread* oscThread; |
|
|
|
|
|
|
|
/* The OSC Thread. Has to be another thread, because
|
|
|
|
* UdpListeningReceiveSocket runs in a blocking loop. [RunUntilSigInt()]*/ |
|
|
|
void runOscThread(unsigned int port) |
|
|
|
{ |
|
|
|
thePacketListener = new ThePacketListener; |
|
|
|
sock = new UdpListeningReceiveSocket( |
|
|
|
IpEndpointName(IpEndpointName::ANY_ADDRESS, port), |
|
|
|
thePacketListener); |
|
|
|
sock->RunUntilSigInt(); //<<--- this is the loop
|
|
|
|
|
|
|
|
//Cleanup after sock exited the loop
|
|
|
|
sock = NULL; |
|
|
|
thePacketListener = NULL; |
|
|
|
} |
|
|
|
|
|
|
|
/* DLL was loaded */ |
|
|
|
BOOL APIENTRY DllMain( HMODULE hModule, |
|
|
|
DWORD ul_reason_for_call, |
|
|
|
LPVOID lpReserved |
|
|
@ -85,7 +70,6 @@ BOOL APIENTRY DllMain( HMODULE hModule, |
|
|
|
{ |
|
|
|
case DLL_PROCESS_ATTACH: |
|
|
|
case DLL_THREAD_ATTACH: |
|
|
|
OutputDebugString(L"ATTACH\r\n"); |
|
|
|
break; |
|
|
|
case DLL_THREAD_DETACH: |
|
|
|
case DLL_PROCESS_DETACH: |
|
|
@ -97,39 +81,53 @@ BOOL APIENTRY DllMain( HMODULE hModule, |
|
|
|
|
|
|
|
DLLEXPORT int open(HWND targetWindowHandle, unsigned int port) |
|
|
|
{ |
|
|
|
OutputDebugString(L"open()\r\n"); |
|
|
|
if (!targetWindowHandle || !port) { |
|
|
|
if (!targetWindowHandle) OutputDebugString(L"open: targetWindowHandle!!\r\n"); |
|
|
|
if (!port) OutputDebugString(L"open: port!!\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/*Store handle to Autohotkey window globally*/ |
|
|
|
hwnd = targetWindowHandle; |
|
|
|
examplePacketListener = new ExamplePacketListener; |
|
|
|
sock = new UdpListeningReceiveSocket( |
|
|
|
IpEndpointName(IpEndpointName::ANY_ADDRESS, port), |
|
|
|
examplePacketListener); |
|
|
|
sock->RunUntilSigInt(); |
|
|
|
OutputDebugString(L"open\r\n"); |
|
|
|
/*Start OSC Thread*/ |
|
|
|
oscThread = new std::thread(runOscThread, port); |
|
|
|
|
|
|
|
OutputDebugString(L"open: Opened.\r\n"); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
DLLEXPORT int close() |
|
|
|
{ |
|
|
|
if (sock && sock->IsBound()) |
|
|
|
{ |
|
|
|
sock->AsynchronousBreak(); |
|
|
|
} |
|
|
|
oscThread = NULL; |
|
|
|
hwnd = NULL; |
|
|
|
listeners.clear(); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
DLLEXPORT int addListener(std::string address_, unsigned int messageID_, unsigned int dataType_) |
|
|
|
DLLEXPORT int addListener(LPCSTR address_, unsigned int messageID_, unsigned int dataType_) |
|
|
|
{ |
|
|
|
listeners.push_back(Listener{ address_, dataType_, messageID_ }); |
|
|
|
OutputDebugString(L"addListener: address="); |
|
|
|
OutputDebugStringA(address_); |
|
|
|
OutputDebugString(L"\r\n"); |
|
|
|
listeners.push_back(Listener{ std::string(address_), dataType_, messageID_ }); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
DLLEXPORT int removeListener(std::string address_) |
|
|
|
DLLEXPORT int removeListener(LPCSTR address_) |
|
|
|
{ |
|
|
|
UINT result = 1; |
|
|
|
|
|
|
|
std::string addrStr(address_); |
|
|
|
//All OSC addresses have to start with a '/'
|
|
|
|
if (address_[0] != '/') address_.insert(0, "/"); |
|
|
|
if (addrStr[0] != '/') addrStr.insert(0, "/"); |
|
|
|
|
|
|
|
for (UINT i = 0; i < listeners.size(); i++) |
|
|
|
{ |
|
|
|
if (listeners[i].address == address_) |
|
|
|
if (listeners[i].address == addrStr) |
|
|
|
{ |
|
|
|
listeners.erase(listeners.begin() + i); |
|
|
|
i--; //one step backward, what previously was i+1 is i after erase().
|
|
|
@ -139,11 +137,74 @@ DLLEXPORT int removeListener(std::string address_) |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
DLLEXPORT int handleOscMsg(const osc::ReceivedMessage& m) |
|
|
|
{ |
|
|
|
int ret = 0; |
|
|
|
|
|
|
|
OutputDebugString(L"handleOscMsg: Address="); |
|
|
|
OutputDebugStringA(m.AddressPattern()); |
|
|
|
OutputDebugString(L"\r\n"); |
|
|
|
|
|
|
|
if (!hwnd || !sock->IsBound()) |
|
|
|
{ |
|
|
|
OutputDebugString(L"handleOscMsg: Seems open() was not called yet...\r\n"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
//Loop through all registered listener entries
|
|
|
|
for (UINT i = 0; i < listeners.size(); i++) |
|
|
|
{ |
|
|
|
//Check if incoming OSC address matches current listener entry
|
|
|
|
if (listeners[i].address.compare(m.AddressPattern()) == 0) |
|
|
|
{ |
|
|
|
//No payload
|
|
|
|
if (m.ArgumentCount() == 0) { |
|
|
|
if (listeners[i].dataType == OSC_TYPE_NONE || listeners[i].dataType == OSC_TYPE_ALL) { |
|
|
|
PostMessage(hwnd, listeners[i].message, OSC_TYPE_NONE, 0); |
|
|
|
ret++; |
|
|
|
} |
|
|
|
} |
|
|
|
else //Some paylad, only check first one
|
|
|
|
{ |
|
|
|
osc::ReceivedMessage::const_iterator arg = m.ArgumentsBegin(); |
|
|
|
if (arg->IsInt32()) { //Got Int, check if listener is valid for Int or All
|
|
|
|
if (listeners[i].dataType == OSC_TYPE_ALL || listeners[i].dataType == OSC_TYPE_INT) { |
|
|
|
PostMessage(hwnd, listeners[i].message, OSC_TYPE_INT, arg->AsInt32()); //post to message queue
|
|
|
|
ret++; |
|
|
|
} |
|
|
|
} |
|
|
|
else if (arg->IsFloat()) { //Got Float, check if listener is valid for Float or All
|
|
|
|
if (listeners[i].dataType == OSC_TYPE_ALL || listeners[i].dataType == OSC_TYPE_FLOAT) { |
|
|
|
float floatarg = arg->AsFloat(); |
|
|
|
LPARAM lParam = *(LPARAM*)&floatarg; |
|
|
|
PostMessage(hwnd, listeners[i].message, OSC_TYPE_FLOAT, lParam); //post to message queue
|
|
|
|
ret++; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
OutputDebugString(L"handleOscMsg: Unknown datatype\r\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (ret > 0) OutputDebugString(L"handleOscMsg: Found and posted at least once.\r\n"); |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
/* Debugging function to test messaging. Probably will be removed later. */ |
|
|
|
DLLEXPORT int testMsg(HWND windowHandle, unsigned int messageID) |
|
|
|
{ |
|
|
|
OutputDebugString(L"testMsg()\r\n"); |
|
|
|
if (!windowHandle) |
|
|
|
{ |
|
|
|
OutputDebugString(L"testMsg: windowHandle!!\r\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
if (PostMessage(windowHandle, messageID, 42, 43)) |
|
|
|
return 0; |
|
|
|
else |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|