diff --git a/OSC2AHK/dllmain.cpp b/OSC2AHK/dllmain.cpp index 54ed668..914a360 100644 --- a/OSC2AHK/dllmain.cpp +++ b/OSC2AHK/dllmain.cpp @@ -3,79 +3,64 @@ #include "dllmain.h" #include #include +#include #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 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; } + diff --git a/OSC2AHK/dllmain.h b/OSC2AHK/dllmain.h index 514d5fc..ec0e91f 100644 --- a/OSC2AHK/dllmain.h +++ b/OSC2AHK/dllmain.h @@ -2,16 +2,19 @@ #include #include +#include #define DLLEXPORT __declspec(dllexport) -#define OSC_TYPE_ALL 0 +#define OSC_TYPE_NONE 0 #define OSC_TYPE_INT 1 #define OSC_TYPE_FLOAT 2 -#define OSC_TYPE_STRING 4 +#define OSC_TYPE_STRING 3 +#define OSC_TYPE_ALL 255 extern "C" DLLEXPORT int open(HWND targetWindowHandle, unsigned int port); extern "C" DLLEXPORT int close(); -extern "C" DLLEXPORT int addListener(std::string address, unsigned int messageID, unsigned int dataType = OSC_TYPE_ALL); -extern "C" DLLEXPORT int removeListener(std::string address); +extern "C" DLLEXPORT int addListener(LPCSTR address, unsigned int messageID, unsigned int dataType = OSC_TYPE_ALL); +extern "C" DLLEXPORT int removeListener(LPCSTR address); +extern "C" DLLEXPORT int handleOscMsg(const osc::ReceivedMessage & m); extern "C" DLLEXPORT int testMsg(HWND windowHandle, unsigned int messageID); diff --git a/msgtest.ahk b/msgtest.ahk index 7e55683..5cc2a14 100644 --- a/msgtest.ahk +++ b/msgtest.ahk @@ -1,25 +1,49 @@ #SingleInstance, Force SendMode Input SetWorkingDir, %A_ScriptDir% +Gui +LastFound hWnd := WinExist() stdout := FileOpen("tmp.log", "w") stdout.WriteLine("START") retOnMsg := OnMessage(0x1000, "msghandler") -stdout.WriteLine("OnMessage:") +stdout.Write("OnMessage: ") stdout.WriteLine(retOnMsg) OnExit("exithandler") hModule := DllCall("LoadLibrary", "Str", "x64\Debug\OSC2AHK.dll", "Ptr") ; Avoids the need for DllCall() in the loop to load the library. -stdout.WriteLine("DLL handle:") +stdout.Write("DLL handle: ") stdout.WriteLine(hModule) -ret := DllCall("OSC2AHK.dll\testMsg", UInt,hWnd, UInt,0x1000) -stdout.WriteLine("DLL call:") -stdout.WriteLine(ret) +; ret := DllCall("OSC2AHK.dll\testMsg", UInt,hWnd, UInt,0x1000) +; stdout.WriteLine("DLL call:") +; stdout.WriteLine(ret) -DllCall("OSC2AHK.dll\open", UInt, hWnd, UInt, 7002) +ret3 := DllCall("OSC2AHK.dll\open", UInt, hWnd, UInt, 7002) +stdout.Write("DLL open: ") +stdout.WriteLine(ret3) + +ret2 := DllCall("OSC2AHK.dll\addListener", AStr, "/test", UInt, 0x1001, UInt, 1) +retOnMsg := OnMessage(0x1001, "msghandler") +stdout.Write("DLL addListener: ") +stdout.WriteLine(ret2) + +;ret3 := DllCall("OSC2AHK.dll\close") +;stdout.Write("DLL close: ") +;stdout.WriteLine(ret3) + +; ret3 := DllCall("OSC2AHK.dll\open", UInt, hWnd, UInt, 7002) +; stdout.Write("DLL open: ") +; stdout.WriteLine(ret3) + +DllCall("OSC2AHK.dll\addListener", AStr, "/test2", UInt, 0x1001, UInt, 1) +DllCall("OSC2AHK.dll\addListener", AStr, "/test3", UInt, 0x1002, UInt, 255) +OnMessage(0x1002, "msghandlerfloat") +DllCall("OSC2AHK.dll\removeListener", AStr, "/test2") +; retOnMsg := OnMessage(0x1001, "msghandler") +; stdout.Write("DLL addListener: ") +; stdout.WriteLine(ret2) stdout.Close() @@ -27,12 +51,37 @@ return msghandler(wParam, lParam, msg, hwnd) { stdout := FileOpen("tmp.log", "a") - stdout.WriteLine("Received MSG!") - stdout.WriteLine(wParam) + stdout.Write("Received MSG: ") + stdout.Write(msg) + stdout.write(" ") + stdout.Write(wParam) + stdout.write(" ") stdout.WriteLine(lParam) stdout.Close() } +msghandlerfloat(wParam, lParam, msg, hwnd) { + stdout := FileOpen("tmp.log", "a") + thefloat := NumGet(lParam, 0, "Float") + stdout.WriteLine(thefloat) + thefloat := NumGet(lParam, 1, "Float") + stdout.WriteLine(thefloat) + thefloat := NumGet(lParam, 2, "Float") + stdout.WriteLine(thefloat) + thefloat := NumGet(lParam, 3, "Float") + stdout.WriteLine(thefloat) + thefloat := NumGet(lParam, 4, "Float") + stdout.WriteLine(thefloat) + thefloat := NumGet(lParam, 5, "Float") + stdout.WriteLine(thefloat) + thefloat := NumGet(lParam, 6, "Float") + stdout.WriteLine(thefloat) + thefloat := NumGet(lParam, 7, "Float") + stdout.WriteLine(thefloat) + thefloat := NumGet(lParam, 8, "Float") + stdout.WriteLine(thefloat) +} + exithandler() { stdout := FileOpen("tmp.log", "a") stdout.WriteLine("The End")