bool HIDDevice::openDevice() { memset(&ReadOverlapped, 0, sizeof(OVERLAPPED)); Device = HIDManager->CreateHIDFile(DevDesc.Path.ToCStr()); if (Device == INVALID_HANDLE_VALUE) { OVR_DEBUG_LOG(("Failed 'CreateHIDFile' while opening device, error = 0x%X.", ::GetLastError())); Device = 0; return false; } if (!HIDManager->HidD_SetNumInputBuffers(Device, 128)) { OVR_ASSERT_LOG(false, ("Failed 'HidD_SetNumInputBuffers' while initializing device.")); ::CloseHandle(Device); Device = 0; return false; } // Create a manual-reset non-signaled event. ReadOverlapped.hEvent = ::CreateEvent(0, TRUE, FALSE, 0); if (!ReadOverlapped.hEvent) { OVR_ASSERT_LOG(false, ("Failed to create event.")); ::CloseHandle(Device); Device = 0; return false; } if (!initInfo()) { OVR_ASSERT_LOG(false, ("Failed to get HIDDevice info.")); ::CloseHandle(ReadOverlapped.hEvent); memset(&ReadOverlapped, 0, sizeof(OVERLAPPED)); ::CloseHandle(Device); Device = 0; return false; } if (!initializeRead()) { OVR_ASSERT_LOG(false, ("Failed to get intialize read for HIDDevice.")); ::CloseHandle(ReadOverlapped.hEvent); memset(&ReadOverlapped, 0, sizeof(OVERLAPPED)); ::CloseHandle(Device); Device = 0; return false; } return true; }
MessageHandler::~MessageHandler() { MessageHandlerImpl* handlerImpl = MessageHandlerImpl::FromHandler(this); { Lock::Locker lockedScope(handlerImpl->pLock); OVR_ASSERT_LOG(handlerImpl->UseList.IsEmpty(), ("~MessageHandler %p - Handler still active; call RemoveHandlerFromDevices", this)); } Destruct<MessageHandlerImpl>(handlerImpl); }
bool HIDDevice::initInfo() { // Device must have been successfully opened. OVR_ASSERT(Device); // Get report lengths. HIDP_PREPARSED_DATA* preparsedData = 0; if (!HIDManager->HidD_GetPreparsedData(Device, &preparsedData)) { return false; } HIDP_CAPS caps; if (HIDManager->HidP_GetCaps(preparsedData, &caps) != HIDP_STATUS_SUCCESS) { HIDManager->HidD_FreePreparsedData(preparsedData); return false; } InputReportBufferLength = caps.InputReportByteLength; OutputReportBufferLength = caps.OutputReportByteLength; FeatureReportBufferLength= caps.FeatureReportByteLength; HIDManager->HidD_FreePreparsedData(preparsedData); if (ReadBufferSize < InputReportBufferLength) { OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer.")); return false; } // Get device desc. if (!HIDManager->getFullDesc(Device, &DevDesc)) { OVR_ASSERT_LOG(false, ("Failed to get device desc while initializing device.")); return false; } return true; }
void DeviceStatus::ShutDown() { OVR_ASSERT(hMessageWindow); if (!UnregisterDeviceNotification(hDeviceNotify)) { OVR_ASSERT_LOG(false, ("Failed to unregister device notification.")); } PostMessage(hMessageWindow, WM_CLOSE, 0, 0); while (hMessageWindow != NULL) { ProcessMessages(); Sleep(1); } if (!UnregisterClass(windowClassName, NULL)) { OVR_ASSERT_LOG(false, ("Failed to unregister window class.")); } }
void DeviceStatus::ProcessMessages() { OVR_ASSERT_LOG(hMessageWindow != NULL, ("Need to call 'Initialize' before first use.")); MSG msg; // Note WM_DEVICECHANGED messages are dispatched but not retrieved by PeekMessage. // I think this is because they are pending, non-queued messages. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
bool HIDDeviceManager::getStringProperty(IOHIDDeviceRef device, CFStringRef propertyName, String* pResult) { CFStringRef str = (CFStringRef) IOHIDDeviceGetProperty(device, propertyName); if (!str) { return false; } CFIndex length = CFStringGetLength(str); CFRange range = CFRangeMake(0, length); // Test the conversion first to get required buffer size. CFIndex bufferLength; CFIndex numberOfChars = CFStringGetBytes(str, range, kCFStringEncodingUTF8, (char) '?', FALSE, NULL, 0, &bufferLength); if (numberOfChars == 0) { return false; } // Now allocate buffer. char* buffer = new char[bufferLength+1]; numberOfChars = CFStringGetBytes(str, range, kCFStringEncodingUTF8, (char) '?', FALSE, (UInt8*) buffer, bufferLength, NULL); OVR_ASSERT_LOG(numberOfChars != 0, ("CFStringGetBytes failed.")); buffer[bufferLength] = '\0'; *pResult = String(buffer); return true; }
bool HIDDevice::initInfo() { // Device must have been successfully opened. OVR_ASSERT(Device); // Get report lengths. SInt32 bufferLength; bool getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxInputReportSizeKey), &bufferLength); OVR_ASSERT(getResult); InputReportBufferLength = (UInt16) bufferLength; getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxOutputReportSizeKey), &bufferLength); OVR_ASSERT(getResult); OutputReportBufferLength = (UInt16) bufferLength; getResult = HIDManager->getIntProperty(Device, CFSTR(kIOHIDMaxFeatureReportSizeKey), &bufferLength); OVR_ASSERT(getResult); FeatureReportBufferLength = (UInt16) bufferLength; if (ReadBufferSize < InputReportBufferLength) { OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer.")); return false; } // Get device desc. if (!HIDManager->getFullDesc(Device, &DevDesc)) { OVR_ASSERT_LOG(false, ("Failed to get device desc while initializing device.")); return false; } return true; }
//----------------------------------------------------------------------------- void HIDDeviceManager::Shutdown() { OVR_ASSERT_LOG((UdevInstance), ("Should have called 'Initialize' before 'Shutdown'.")); if (HIDMonitor) { DevManager->pThread->RemoveSelectFd(this, HIDMonHandle); close(HIDMonHandle); HIDMonHandle = -1; udev_monitor_unref(HIDMonitor); HIDMonitor = NULL; } udev_unref(UdevInstance); // release the library LogText("OVR::Linux::HIDDeviceManager - shutting down.\n"); }
//----------------------------------------------------------------------------- bool HIDDevice::initInfo() { // Device must have been successfully opened. OVR_ASSERT(DeviceHandle >= 0); // Get report lengths. // TODO: hard-coded for now. Need to interpret these values from the report descriptor InputReportBufferLength = 62; OutputReportBufferLength = 0; FeatureReportBufferLength = 69; if (ReadBufferSize < InputReportBufferLength) { OVR_ASSERT_LOG(false, ("Input report buffer length is bigger than read buffer.")); return false; } return true; }
void StringBuffer::AppendFormat(const char* format, ...) { va_list argList; va_start(argList, format); UPInt size = OVR_vscprintf(format, argList); va_end(argList); char* buffer = (char*) OVR_ALLOC(sizeof(char) * (size+1)); va_start(argList, format); UPInt result = OVR_vsprintf(buffer, size+1, format, argList); OVR_UNUSED1(result); va_end(argList); OVR_ASSERT_LOG(result == size, ("Error in OVR_vsprintf")); AppendString(buffer); OVR_FREE(buffer); }
//----------------------------------------------------------------------------- // Render a value to text. char* JSON::PrintValue(int depth, bool fmt) { char *out=0; switch (Type) { case JSON_Null: out = JSON_strdup("null"); break; case JSON_Bool: if ((int)dValue == 0) out = JSON_strdup("false"); else out = JSON_strdup("true"); break; case JSON_Number: out = PrintNumber(dValue); break; case JSON_String: out = PrintString(Value); break; case JSON_Array: out = PrintArray(depth, fmt); break; case JSON_Object: out = PrintObject(depth, fmt); break; case JSON_None: OVR_ASSERT_LOG(false, ("Bad JSON type.")); break; } return out; }
bool DeviceStatus::Initialize() { WNDCLASS wndClass; wndClass.style = CS_HREDRAW | CS_VREDRAW; wndClass.lpfnWndProc = WindowsMessageCallback; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hInstance = 0; wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); wndClass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wndClass.lpszMenuName = NULL; wndClass.lpszClassName = windowClassName; if (!RegisterClass(&wndClass)) { OVR_ASSERT_LOG(false, ("Failed to register window class.")); return false; } // We're going to create a 'message-only' window. This will be hidden, can't be enumerated etc. // To do this we supply 'HWND_MESSAGE' as the hWndParent. // http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#message_only hMessageWindow = CreateWindow( windowClassName, windowClassName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_MESSAGE, NULL, 0, this); // Pass this object via the CREATESTRUCT mechanism // so that we can attach it to the window user data. if (hMessageWindow == NULL) { OVR_ASSERT_LOG(false, ("Failed to create window.")); return false; } // According to MS, topmost windows receive WM_DEVICECHANGE faster. ::SetWindowPos(hMessageWindow, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); UpdateWindow(hMessageWindow); // Register notification for additional HID messages. HIDDeviceManager* hidDeviceManager = new HIDDeviceManager(NULL); HidGuid = hidDeviceManager->GetHIDGuid(); hidDeviceManager->Release(); DEV_BROADCAST_DEVICEINTERFACE notificationFilter; ZeroMemory(¬ificationFilter, sizeof(notificationFilter)); notificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; //notificationFilter.dbcc_classguid = hidguid; // We need DEVICE_NOTIFY_ALL_INTERFACE_CLASSES to detect // HDMI plug/unplug events. hDeviceNotify = RegisterDeviceNotification( hMessageWindow, ¬ificationFilter, DEVICE_NOTIFY_ALL_INTERFACE_CLASSES|DEVICE_NOTIFY_WINDOW_HANDLE); if (hDeviceNotify == NULL) { OVR_ASSERT_LOG(false, ("Failed to register for device notifications.")); return false; } return true; }
DeviceStatus::~DeviceStatus() { OVR_ASSERT_LOG(hMessageWindow == NULL, ("Need to call 'ShutDown' from DeviceManagerThread.")); }
int DeviceManagerThread::Run() { SetThreadName("OVR::DeviceManagerThread"); LogText("OVR::DeviceManagerThread - running (ThreadId=0x%p).\n", GetThreadId()); // Store out the run loop ref. RunLoop = CFRunLoopGetCurrent(); // Create a 'source' to enable us to signal the run loop to process the command queue. CFRunLoopSourceContext sourceContext; memset(&sourceContext, 0, sizeof(sourceContext)); sourceContext.version = 0; sourceContext.info = this; sourceContext.perform = &staticCommandQueueSourceCallback; CommandQueueSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0 , &sourceContext); CFRunLoopAddSource(RunLoop, CommandQueueSource, kCFRunLoopDefaultMode); // Signal to the parent thread that initialization has finished. StartupEvent.SetEvent(); ThreadCommand::PopBuffer command; while(!IsExiting()) { // PopCommand will reset event on empty queue. if (PopCommand(&command)) { command.Execute(); } else { SInt32 exitReason = 0; do { UInt32 waitMs = INT_MAX; // If devices have time-dependent logic registered, get the longest wait // allowed based on current ticks. if (!TicksNotifiers.IsEmpty()) { UInt64 ticksMks = Timer::GetTicks(); UInt32 waitAllowed; for (UPInt j = 0; j < TicksNotifiers.GetSize(); j++) { waitAllowed = (UInt32)(TicksNotifiers[j]->OnTicks(ticksMks) / Timer::MksPerMs); if (waitAllowed < waitMs) waitMs = waitAllowed; } } // Enter blocking run loop. We may continue until we timeout in which // case it's time to service the ticks. Or if commands arrive in the command // queue then the source callback will call 'CFRunLoopStop' causing this // to return. CFTimeInterval blockInterval = 0.001 * (double) waitMs; exitReason = CFRunLoopRunInMode(kCFRunLoopDefaultMode, blockInterval, false); if (exitReason == kCFRunLoopRunFinished) { // Maybe this will occur during shutdown? break; } else if (exitReason == kCFRunLoopRunStopped ) { // Commands need processing or we're being shutdown. break; } else if (exitReason == kCFRunLoopRunTimedOut) { // Timed out so that we can service our ticks callbacks. continue; } else if (exitReason == kCFRunLoopRunHandledSource) { // Should never occur since the last param when we call // 'CFRunLoopRunInMode' is false. OVR_ASSERT(false); break; } else { OVR_ASSERT_LOG(false, ("CFRunLoopRunInMode returned unexpected code")); break; } } while(true); } } CFRunLoopRemoveSource(RunLoop, CommandQueueSource, kCFRunLoopDefaultMode); CFRelease(CommandQueueSource); LogText("OVR::DeviceManagerThread - exiting (ThreadId=0x%p).\n", GetThreadId()); return 0; }