/** * Called when a Leap Motion controller is plugged in, unplugged, or the device changes state. * * State changes include entering or leaving robust mode and low resource mode. * Note that there is no direct way to query whether the device is in these modes, * although you can use Controller::isLightingBad() to check if there are environmental * IR lighting problems. * * \include Listener_onDeviceChange.txt * * @param controller The Controller object invoking this callback function. * @since 1.2 */ void CServerDriver_Leap::onDeviceChange(const Controller&controller) { DriverLog("CServerDriver_Leap::onDeviceChange()\n"); if (controller.isConnected()) { bool backgroundModeAllowed = controller.config().getInt32("background_app_mode") == 2; if (!backgroundModeAllowed) { // TODO: Show dialog to request permission to allow background mode apps bool userPermission = true; if (userPermission) { controller.config().setInt32("background_app_mode", 2); controller.config().save(); } } controller.setPolicy(Leap::Controller::POLICY_OPTIMIZE_HMD); controller.setPolicy(Leap::Controller::POLICY_BACKGROUND_FRAMES); // make sure we always get background frames even when we lose the focus to another // Leap-enabled application controller.setPolicy((Leap::Controller::PolicyFlag)(15)); // allow other background applications to receive frames even when SteamVR has the focus. controller.setPolicy((Leap::Controller::PolicyFlag)(23)); ScanForNewControllers(true); } else { for (auto it = m_vecControllers.begin(); it != m_vecControllers.end(); ++it) delete (*it); m_vecControllers.clear(); } }
vr::EVRInitError CServerDriver_Hydra::Init( vr::IDriverLog * pDriverLog, vr::IServerDriverHost * pDriverHost, const char * pchUserDriverConfigDir, const char * pchDriverInstallDir ) { InitDriverLog( pDriverLog ); m_pDriverHost = pDriverHost; m_strDriverInstallDir = pchDriverInstallDir; if ( sixenseInit() != SIXENSE_SUCCESS ) return vr::VRInitError_Driver_Failed; // Will not immediately detect controllers at this point. Sixense driver must be initializing // in its own thread... It's okay to dynamically detect devices later, but if controllers are // the only devices (e.g. requireHmd=false) we must have GetTrackedDeviceCount() != 0 before returning. for ( int i = 0; i < 20; ++i ) { ScanForNewControllers( false ); if ( GetTrackedDeviceCount() ) break; Sleep( 100 ); } m_Thread = std::thread( ThreadEntry, this ); return vr::VRInitError_None; }
void CServerDriver_Hydra::ThreadFunc() { // We know the sixense SDK thread is running at "60 FPS", but we don't know when // those frames are. To minimize latency, we sleep for slightly less than the // target rate, and detect when the frame has not advanced to wait a bit longer. auto longInterval = std::chrono::milliseconds( 16 ); auto retryInterval = std::chrono::milliseconds( 2 ); auto scanInterval = std::chrono::seconds( 1 ); auto pollDeadline = std::chrono::steady_clock::now(); auto scanDeadline = std::chrono::steady_clock::now() + scanInterval; #ifdef _WIN32 // Request at least 2ms timing granularity for the life of this process timeBeginPeriod( 2 ); #endif while ( !m_bStopRequested ) { // Check for new controllers here because sixense API is modal // (e.g. sixenseSetActiveBase()) so it can't happen in parallel with pose updates if ( pollDeadline > scanDeadline ) { ScanForNewControllers( true ); scanDeadline += scanInterval; } bool bAnyActivated = false; bool bAllUpdated = true; for ( int base = 0; base < sixenseGetMaxBases(); ++base ) { if ( !sixenseIsBaseConnected( base ) ) continue; sixenseAllControllerData acd; sixenseSetActiveBase( base ); if ( sixenseGetAllNewestData( &acd ) != SIXENSE_SUCCESS ) continue; for ( int id = 0; id < sixenseGetMaxControllers(); ++id ) { for ( auto it = m_vecControllers.begin(); it != m_vecControllers.end(); ++it ) { CHydraHmdLatest *pHydra = *it; if ( pHydra->IsActivated() && pHydra->HasControllerId( base, id ) ) { bAnyActivated = true; // Returns true if this is new data (so we can sleep for long interval) if ( !pHydra->Update( acd.controllers[id] ) ) { bAllUpdated = false; } break; } } } } CheckForChordedSystemButtons(); // If everyone just got new data, we can wait about 1/60s, else try again soon pollDeadline += !bAnyActivated ? scanInterval : bAllUpdated ? longInterval : retryInterval; std::this_thread::sleep_until( pollDeadline ); } #ifdef _WIN32 timeEndPeriod( 2 ); #endif }