diff options
Diffstat (limited to 'Src/Plugins/Library/ml_devices/eventRelay.cpp')
-rw-r--r-- | Src/Plugins/Library/ml_devices/eventRelay.cpp | 465 |
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); +} |