aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Library/ml_devices/eventRelay.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Plugins/Library/ml_devices/eventRelay.cpp')
-rw-r--r--Src/Plugins/Library/ml_devices/eventRelay.cpp465
1 files changed, 465 insertions, 0 deletions
diff --git a/Src/Plugins/Library/ml_devices/eventRelay.cpp b/Src/Plugins/Library/ml_devices/eventRelay.cpp
new file mode 100644
index 00000000..38226887
--- /dev/null
+++ b/Src/Plugins/Library/ml_devices/eventRelay.cpp
@@ -0,0 +1,465 @@
+#include "main.h"
+#include "./eventRelay.h"
+#include <vector>
+
+#define EVENT_RELAY_WINDOW_CLASS L"NullsoftEventRelay"
+
+typedef struct EventHandler
+{
+ size_t cookie;
+ DeviceEventCallbacks callbacks;
+ void *user;
+} EventHandler;
+
+typedef std::vector<EventHandler*> EventHandlerList;
+
+typedef struct EventRelay
+{
+ EventHandlerList handlerList;
+ DeviceManagerHandler *managerHandler;
+ DeviceHandler *deviceHandler;
+} EventRelay;
+
+#define EVENTRELAY(_hwnd) ((EventRelay*)(LONGX86)GetWindowLongPtrW((_hwnd), 0))
+#define EVENTRELAY_RET_VOID(_self, _hwnd) {(_self) = EVENTRELAY((_hwnd)); if (NULL == (_self)) return;}
+#define EVENTRELAY_RET_VAL(_self, _hwnd, _error) {(_self) = EVENTRELAY((_hwnd)); if (NULL == (_self)) return (_error);}
+
+
+static LRESULT CALLBACK
+EventRelay_WindowProc(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam);
+
+
+static ATOM
+EventRelay_GetClassAtom(HINSTANCE instance)
+{
+ WNDCLASSEXW klass;
+ ATOM klassAtom;
+
+ klassAtom = (ATOM)GetClassInfoExW(instance, EVENT_RELAY_WINDOW_CLASS, &klass);
+ if (0 != klassAtom)
+ return klassAtom;
+
+ memset(&klass, 0, sizeof(klass));
+ klass.cbSize = sizeof(klass);
+ klass.style = 0;
+ klass.lpfnWndProc = EventRelay_WindowProc;
+ klass.cbClsExtra = 0;
+ klass.cbWndExtra = sizeof(EventRelay*);
+ klass.hInstance = instance;
+ klass.hIcon = NULL;
+ klass.hCursor = NULL;
+ klass.hbrBackground = NULL;
+ klass.lpszMenuName = NULL;
+ klass.lpszClassName = EVENT_RELAY_WINDOW_CLASS;
+ klass.hIconSm = NULL;
+ klassAtom = RegisterClassExW(&klass);
+
+ return klassAtom;
+}
+
+HWND
+EventRelay_CreateWindow()
+{
+ HINSTANCE instance;
+ ATOM klassAtom;
+ HWND hwnd;
+
+ instance = GetModuleHandleW(NULL);
+ klassAtom = EventRelay_GetClassAtom(instance);
+ if (0 == klassAtom)
+ return NULL;
+
+ hwnd = CreateWindowEx(WS_EX_NOACTIVATE | WS_EX_NOPARENTNOTIFY,
+ MAKEINTATOM(klassAtom),
+ NULL,
+ WS_OVERLAPPED,
+ 0, 0, 0, 0,
+ HWND_MESSAGE,
+ NULL,
+ instance,
+ NULL);
+
+ return hwnd;
+}
+
+
+static size_t
+EventRelay_GenerateCookie(EventRelay *self)
+{
+ size_t cookie;
+ EventHandler *handler;
+
+
+ if (NULL == self)
+ return 0;
+
+ cookie = self->handlerList.size() + 1;
+
+ for(;;)
+ {
+ size_t index = self->handlerList.size();
+ while(index--)
+ {
+ handler = self->handlerList[index];
+ if (cookie == handler->cookie)
+ {
+ cookie++;
+ break;
+ }
+ }
+
+ if (((size_t)-1) == index)
+ return cookie;
+ }
+
+ return cookie;
+}
+
+static EventHandler *
+EventRelay_CreateEventHandler(EventRelay *self, DeviceEventCallbacks *callbacks, void *user)
+{
+ EventHandler *handler;
+ size_t cookie;
+
+ if (NULL == self || NULL == callbacks)
+ return NULL;
+
+ cookie = EventRelay_GenerateCookie(self);
+ if (0 == cookie)
+ return NULL;
+
+ handler = (EventHandler*)malloc(sizeof(EventHandler));
+ if (NULL == handler)
+ return NULL;
+
+ handler->user = user;
+ handler->cookie = cookie;
+ handler->callbacks.deviceCb = callbacks->deviceCb;
+ handler->callbacks.typeCb = callbacks->typeCb;
+ handler->callbacks.connectionCb = callbacks->connectionCb;
+ handler->callbacks.commandCb = callbacks->commandCb;
+ handler->callbacks.discoveryCb = callbacks->discoveryCb;
+
+ return handler;
+}
+
+static void
+EventRelay_DestroyEventHandler(EventHandler *handler)
+{
+ if (NULL == handler)
+ return;
+
+ free(handler);
+}
+
+static LRESULT
+EventRelay_OnCreate(HWND hwnd, CREATESTRUCT *createStruct)
+{
+ EventRelay *self;
+ ifc_deviceobjectenum *enumerator;
+ ifc_deviceobject *object;
+ ifc_device *device;
+
+ if (NULL == WASABI_API_DEVICES)
+ return -1;
+
+ self = new EventRelay();
+ if (NULL == self)
+ return -1;
+
+ self->deviceHandler = NULL;
+ self->managerHandler = NULL;
+
+ SetLastError(ERROR_SUCCESS);
+ if (!SetWindowLongPtr(hwnd, 0, (LONGX86)self) && ERROR_SUCCESS != GetLastError())
+ return -1;
+
+ if (FAILED(DeviceHandler::CreateInstance(&self->deviceHandler)))
+ return -1;
+
+ self->deviceHandler->SetRelayWindow(hwnd);
+
+ if (SUCCEEDED(WASABI_API_DEVICES->DeviceEnumerate(&enumerator)))
+ {
+ while(S_OK == enumerator->Next(&object, 1, NULL))
+ {
+ if (SUCCEEDED(object->QueryInterface(IFC_Device, (void**)&device)))
+ {
+ self->deviceHandler->Advise(device);
+ device->Release();
+ }
+ object->Release();
+ }
+ enumerator->Release();
+ }
+
+ if (FAILED(DeviceManagerHandler::CreateInstance(&self->managerHandler)))
+ return -1;
+
+ self->managerHandler->SetRelayWindow(hwnd);
+ if (FAILED(self->managerHandler->Advise(WASABI_API_DEVICES)))
+ return -1;
+
+ return 0;
+}
+
+static void
+EventRelay_OnDestroy(HWND hwnd)
+{
+ EventRelay *self;
+ MSG msg;
+
+ self = EVENTRELAY(hwnd);
+ SetWindowLongPtr(hwnd, 0, 0);
+
+ if (NULL == self)
+ return;
+
+ size_t index = self->handlerList.size();
+ while(index--)
+ {
+ EventHandler *handler = self->handlerList[index];
+ EventRelay_DestroyEventHandler(handler);
+ }
+
+ if (NULL != self->managerHandler)
+ {
+ self->managerHandler->SetRelayWindow(NULL);
+
+ if (NULL != WASABI_API_DEVICES)
+ self->managerHandler->Unadvise(WASABI_API_DEVICES);
+
+ self->managerHandler->Release();
+ }
+
+ if (NULL != self->deviceHandler)
+ {
+ self->deviceHandler->SetRelayWindow(NULL);
+
+ if (NULL != WASABI_API_DEVICES)
+ {
+ ifc_deviceobjectenum *enumerator;
+ ifc_deviceobject *object;
+ ifc_device *device;
+
+ if (SUCCEEDED(WASABI_API_DEVICES->DeviceEnumerate(&enumerator)))
+ {
+ while(S_OK == enumerator->Next(&object, 1, NULL))
+ {
+ if (SUCCEEDED(object->QueryInterface(IFC_Device, (void**)&device)))
+ {
+ self->deviceHandler->Unadvise(device);
+ device->Release();
+ }
+ object->Release();
+ }
+ enumerator->Release();
+ }
+ }
+
+ self->deviceHandler->Release();
+ }
+
+ delete self;
+
+ // finish pumping messages
+ while(FALSE != PeekMessage(&msg, hwnd, EVENTRELAY_WM_FIRST, EVENTRELAY_WM_LAST, PM_REMOVE))
+ {
+ EventRelay_WindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
+ }
+}
+
+static LRESULT
+EventRelay_OnRegisterHandler(HWND hwnd, DeviceEventCallbacks *callbacks, void *user)
+{
+ EventRelay *self;
+ EventHandler *handler;
+
+ EVENTRELAY_RET_VAL(self, hwnd, 0);
+
+ handler = EventRelay_CreateEventHandler(self, callbacks, user);
+ if(NULL == handler)
+ return 0;
+
+ self->handlerList.push_back(handler);
+ return (LRESULT)handler->cookie;
+}
+
+static LRESULT
+EventRelay_OnUnregisterHandler(HWND hwnd, size_t cookie)
+{
+ EventRelay *self;
+
+ EVENTRELAY_RET_VAL(self, hwnd, FALSE);
+
+ size_t index = self->handlerList.size();
+ while(index--)
+ {
+ EventHandler *handler = self->handlerList[index];
+ if (handler->cookie == cookie)
+ {
+ self->handlerList.erase(self->handlerList.begin() + index);
+ EventRelay_DestroyEventHandler(handler);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+EventRelay_OnNotifyDevice(HWND hwnd, ifc_device *device, DeviceEvent eventId)
+{
+ ReplyMessage(0);
+
+ if (NULL != device)
+ {
+ EventRelay *self;
+ self = EVENTRELAY(hwnd);
+
+ if (NULL != self)
+ {
+ switch(eventId)
+ {
+ case Event_DeviceAdded:
+ if (NULL != self->deviceHandler)
+ self->deviceHandler->Advise(device);
+ break;
+
+ case Event_DeviceRemoved:
+ if (NULL != self->deviceHandler)
+ self->deviceHandler->Unadvise(device);
+ break;
+ }
+
+ size_t index = self->handlerList.size();
+ while(index--)
+ {
+ EventHandler *handler = self->handlerList[index];
+ if (NULL != handler->callbacks.deviceCb)
+ handler->callbacks.deviceCb(device, eventId, handler->user);
+ }
+ }
+
+ device->Release();
+ }
+}
+
+static void
+EventRelay_OnNotifyDiscovery(HWND hwnd, api_devicemanager *manager, DeviceDiscoveryEvent eventId)
+{
+ ReplyMessage(0);
+
+ if (NULL != manager)
+ {
+ EventRelay *self;
+ self = EVENTRELAY(hwnd);
+
+ if (NULL != self)
+ {
+ size_t index = self->handlerList.size();
+ while(index--)
+ {
+ EventHandler *handler = self->handlerList[index];
+ if (NULL != handler->callbacks.discoveryCb)
+ handler->callbacks.discoveryCb(manager, eventId, handler->user);
+ }
+ }
+
+ manager->Release();
+ }
+}
+
+static void
+EventRelay_OnNotifyType(HWND hwnd, ifc_devicetype *type, DeviceTypeEvent eventId)
+{
+ ReplyMessage(0);
+
+ if (NULL != type)
+ {
+ EventRelay *self;
+ self = EVENTRELAY(hwnd);
+
+ if (NULL != self)
+ {
+ size_t index = self->handlerList.size();
+ while(index--)
+ {
+ EventHandler *handler = self->handlerList[index];
+ if (NULL != handler->callbacks.typeCb)
+ handler->callbacks.typeCb(type, eventId, handler->user);
+ }
+ }
+
+ type->Release();
+ }
+}
+
+static void
+EventRelay_OnNotifyConnection(HWND hwnd, ifc_deviceconnection *connection, DeviceConnectionEvent eventId)
+{
+ ReplyMessage(0);
+
+ if (NULL != connection)
+ {
+ EventRelay *self;
+ self = EVENTRELAY(hwnd);
+
+ if (NULL != self)
+ {
+ size_t index = self->handlerList.size();
+ while(index--)
+ {
+ EventHandler *handler = self->handlerList[index];
+ if (NULL != handler->callbacks.connectionCb)
+ handler->callbacks.connectionCb(connection, eventId, handler->user);
+ }
+ }
+
+ connection->Release();
+ }
+}
+
+static void
+EventRelay_OnNotifyCommand(HWND hwnd, ifc_devicecommand *command, DeviceCommandEvent eventId)
+{
+ ReplyMessage(0);
+
+ if (NULL != command)
+ {
+ EventRelay *self;
+ self = EVENTRELAY(hwnd);
+
+ if (NULL != self)
+ {
+ size_t index = self->handlerList.size();
+ while(index--)
+ {
+ EventHandler *handler = self->handlerList[index];
+ if (NULL != handler->callbacks.commandCb)
+ handler->callbacks.commandCb(command, eventId, handler->user);
+ }
+ }
+
+ command->Release();
+ }
+}
+
+static LRESULT CALLBACK
+EventRelay_WindowProc(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch(uMsg)
+ {
+ case WM_CREATE: return EventRelay_OnCreate(hwnd, (CREATESTRUCT*)lParam);
+ case WM_DESTROY: EventRelay_OnDestroy(hwnd); return 0;
+
+ case EVENTRELAY_WM_REGISTER_HANDLER: return EventRelay_OnRegisterHandler(hwnd, (DeviceEventCallbacks*)lParam, (void*)wParam);
+ case EVENTRELAY_WM_UNREGISTER_HANDLER: return EventRelay_OnUnregisterHandler(hwnd, (size_t)lParam);
+ case EVENTRELAY_WM_NOTIFY_DEVICE: EventRelay_OnNotifyDevice(hwnd, (ifc_device*)lParam, (DeviceEvent)wParam); return 0;
+ case EVENTRELAY_WM_NOTIFY_DISCOVERY: EventRelay_OnNotifyDiscovery(hwnd, (api_devicemanager*)lParam, (DeviceDiscoveryEvent)wParam); return 0;
+ case EVENTRELAY_WM_NOTIFY_TYPE: EventRelay_OnNotifyType(hwnd, (ifc_devicetype*)lParam, (DeviceTypeEvent)wParam); return 0;
+ case EVENTRELAY_WM_NOTIFY_CONNECTION: EventRelay_OnNotifyConnection(hwnd, (ifc_deviceconnection*)lParam, (DeviceConnectionEvent)wParam); return 0;
+ case EVENTRELAY_WM_NOTIFY_COMMAND: EventRelay_OnNotifyCommand(hwnd, (ifc_devicecommand*)lParam, (DeviceCommandEvent)wParam); return 0;
+ }
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+}