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(&notificationFilter, 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,
		&notificationFilter,
		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;
}