@@ -40,6 +40,11 @@ public List<IDependency> ListDependencies()
4040 {
4141 Host = Host ,
4242 Name = Host ? . RequestLocalizedString ( "/Dependencies/Driver" ) ?? "OpenVR Driver"
43+ } ,
44+ new NullDriver
45+ {
46+ Host = Host ,
47+ Name = Host ? . RequestLocalizedString ( "/Dependencies/Null" ) ?? "Null Driver"
4348 }
4449 ] ;
4550 }
@@ -110,7 +115,15 @@ public async Task<bool> Install(IProgress<InstallationProgress> progress, Cancel
110115
111116 /* 1 */
112117
113- await PathsHandler . Setup ( ) ;
118+ try
119+ {
120+ await PathsHandler . Setup ( ) ;
121+ SteamVR . Instance ? . Shutdown ( ) ;
122+ }
123+ catch ( Exception )
124+ {
125+ // Ignored
126+ }
114127
115128 /* 2 */
116129
@@ -320,6 +333,131 @@ await File.WriteAllTextAsync(resultPaths.Path.VrSettingsPath, steamVrSettings.To
320333 // Not critical
321334 }
322335
336+ // Winning it!
337+ return true ;
338+ }
339+ }
340+
341+ internal class NullDriver : IDependency
342+ {
343+ public IDependencyInstaller . ILocalizationHost Host { get ; set ; }
344+
345+ public string Name { get ; set ; }
346+ public bool IsMandatory => false ;
347+ public bool IsInstalled => false ;
348+ public string InstallerEula => string . Empty ;
349+
350+ public async Task < bool > Install ( IProgress < InstallationProgress > progress , CancellationToken cancellationToken )
351+ {
352+ // Amethyst will handle this exception for us anyway
353+ cancellationToken . ThrowIfCancellationRequested ( ) ;
354+
355+ VrHelper helper = new ( ) ;
356+ var resultPaths = helper . UpdateSteamPaths ( ) ;
357+
358+ try // Try-Catch it
359+ {
360+ // Check if SteamVR was found
361+ if ( ! resultPaths . Exists . SteamExists )
362+ {
363+ Directory . CreateDirectory ( Directory . GetParent ( OpenVrPaths . Path ) ! . FullName ) ;
364+ File . Create ( OpenVrPaths . Path ) ;
365+ }
366+ }
367+ catch ( Exception )
368+ {
369+ progress . Report ( new InstallationProgress
370+ {
371+ IsIndeterminate = true ,
372+ StageTitle = Host ? . RequestLocalizedString ( "/CrashHandler/ReRegister/OpenVRPathsError" ) !
373+ } ) ;
374+ return false ;
375+ }
376+
377+ /* 1 */
378+
379+ try
380+ {
381+ await PathsHandler . Setup ( ) ;
382+ SteamVR . Instance ? . Shutdown ( ) ;
383+ }
384+ catch ( Exception )
385+ {
386+ // Ignored
387+ }
388+
389+ /* 2 */
390+
391+ // Force exit (kill) SteamVR
392+ if ( Process . GetProcesses ( ) . FirstOrDefault ( proc => proc . ProcessName is "vrserver" or "vrmonitor" ) != null )
393+ {
394+ // Check for privilege mismatches
395+ if ( VrHelper . IsOpenVrElevated ( ) && ! VrHelper . IsCurrentProcessElevated ( ) )
396+ {
397+ progress . Report ( new InstallationProgress
398+ {
399+ IsIndeterminate = true ,
400+ StageTitle = Host ? . RequestLocalizedString ( "/CrashHandler/ReRegister/Elevation" ) !
401+ } ) ;
402+
403+ return false ; // Hide and exit the handler
404+ }
405+
406+ // Finally kill
407+ await Task . Factory . StartNew ( helper . CloseSteamVr , cancellationToken ) ;
408+ }
409+
410+ /* 3 */
411+
412+ // Try-Catch it
413+ try
414+ {
415+ // Read the vr settings
416+ var steamVrSettings =
417+ JsonObject . Parse ( await File . ReadAllTextAsync ( resultPaths . Path . VrSettingsPath , cancellationToken ) ) ;
418+
419+ // Enable & unblock the Null Driver
420+ steamVrSettings . Remove ( "driver_null" ) ;
421+ steamVrSettings . Add ( "driver_null" ,
422+ new JsonObject
423+ {
424+ new KeyValuePair < string , IJsonValue > ( "displayFrequency" , JsonValue . CreateNumberValue ( 60 ) ) ,
425+ new KeyValuePair < string , IJsonValue > ( "enable" , JsonValue . CreateBooleanValue ( true ) ) ,
426+ new KeyValuePair < string , IJsonValue > ( "id" , JsonValue . CreateStringValue ( "Null Driver" ) ) ,
427+ new KeyValuePair < string , IJsonValue > ( "renderHeight" , JsonValue . CreateNumberValue ( 0 ) ) ,
428+ new KeyValuePair < string , IJsonValue > ( "renderWidth" , JsonValue . CreateNumberValue ( 0 ) ) ,
429+ new KeyValuePair < string , IJsonValue > ( "secondsFromVsyncToPhotons" , JsonValue . CreateNumberValue ( 0.10000000149011612 ) ) ,
430+ new KeyValuePair < string , IJsonValue > ( "serialNumber" , JsonValue . CreateStringValue ( "Null 4711" ) ) ,
431+ new KeyValuePair < string , IJsonValue > ( "windowHeight" , JsonValue . CreateNumberValue ( 0 ) ) ,
432+ new KeyValuePair < string , IJsonValue > ( "windowWidth" , JsonValue . CreateNumberValue ( 0 ) ) ,
433+ new KeyValuePair < string , IJsonValue > ( "windowX" , JsonValue . CreateNumberValue ( 0 ) ) ,
434+ new KeyValuePair < string , IJsonValue > ( "windowY" , JsonValue . CreateNumberValue ( 0 ) )
435+ } ) ;
436+
437+ steamVrSettings . Remove ( "steamvr" ) ;
438+ steamVrSettings . Add ( "steamvr" ,
439+ new JsonObject
440+ {
441+ new KeyValuePair < string , IJsonValue > ( "activateMultipleDrivers" , JsonValue . CreateBooleanValue ( true ) ) ,
442+ new KeyValuePair < string , IJsonValue > ( "enableHomeApp" , JsonValue . CreateBooleanValue ( false ) ) ,
443+ new KeyValuePair < string , IJsonValue > ( "forcedDriver" , JsonValue . CreateStringValue ( "null" ) ) ,
444+ new KeyValuePair < string , IJsonValue > ( "mirrorViewGeometry" , JsonValue . CreateStringValue ( "0 0 960 540" ) )
445+ } ) ;
446+
447+ await File . WriteAllTextAsync ( resultPaths . Path . VrSettingsPath , steamVrSettings . ToString ( ) ,
448+ cancellationToken ) ;
449+ }
450+ catch ( Exception ex )
451+ {
452+ progress . Report ( new InstallationProgress
453+ {
454+ IsIndeterminate = true ,
455+ StageTitle = ex . Message
456+ } ) ;
457+
458+ return false ; // Hide and exit the handler
459+ }
460+
323461 // Winning it!
324462 return true ;
325463 }
0 commit comments