Last active
July 14, 2022 02:15
-
-
Save mcorrigan/4b8ff830122d1a31bf99ccc4bd1aeba4 to your computer and use it in GitHub Desktop.
SteamVR Headless Mode Toggle Python Script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!python | |
# coding: utf-8 | |
# This is a simple script to quickly switch between HMD mode and headless mode with Vive in SteamVR | |
# It uses symlinks to ensure that SteamVR will continue to run and always preserves the original files, | |
# This should be able to be rerun following updates (assuming the configs haven't structurally changes | |
# along with anything else) -- symlinks require running with elevated priviledges | |
import sys, os, ctypes, time, json, shutil | |
from winreg import QueryValueEx, HKEY_CURRENT_USER, OpenKey | |
kdll = ctypes.windll.LoadLibrary("kernel32.dll") | |
steamVR_launch = r"steam://rungameid/250820" | |
steamVRRegEntry = r"SOFTWARE\Valve\Steam\Apps\250820" | |
steam_root = U"C:\\Program Files (x86)\\Steam" | |
steamvr_null_driver_settings = U"\\steamapps\\common\\SteamVR\\drivers\\null\\resources\\settings\\default.vrsettings" | |
steamvr_resource_settings = U"\\steamapps\\common\\SteamVR\\resources\\settings\\default.vrsettings" | |
def runAsAdmin(argv=None, debug=False): | |
shell32 = ctypes.windll.shell32 | |
if argv is None and shell32.IsUserAnAdmin(): | |
return True | |
if argv is None: | |
argv = sys.argv | |
if hasattr(sys, '_MEIPASS'): | |
# Support pyinstaller wrapped program. | |
arguments = map(str, argv[1:]) | |
else: | |
arguments = map(str, argv) | |
argument_line = u' '.join(arguments) | |
executable = str(sys.executable) | |
if debug: | |
print ('Command line: ', executable, argument_line) | |
ret = shell32.ShellExecuteW(None, u"runas", executable, argument_line, None, 1) | |
if int(ret) <= 32: | |
return False | |
return None | |
if __name__ == '__main__': | |
ret = runAsAdmin() | |
if ret is True: | |
# we have elevated permissions | |
# verify steam is installed installation | |
if not os.path.exists(steam_root): | |
print(f'\n Steam does not seem to be installed ({steam_root})\n') | |
time.sleep(2) | |
exit | |
# check if steamvr is running, if so, wait for them to close steamvr | |
isRunning = False | |
with OpenKey(HKEY_CURRENT_USER, steamVRRegEntry) as key: | |
(value, type) = QueryValueEx(key, 'Running') | |
isRunning = value == 1 # Running: 1 yes, 0 no | |
if isRunning: | |
print(f'\n Please exit SteamVR to continue... ') | |
while isRunning: | |
with OpenKey(HKEY_CURRENT_USER, steamVRRegEntry) as key: | |
(value, type) = QueryValueEx(key, 'Running') | |
isRunning = value == 1 | |
time.sleep(1) | |
print(f'ready.') | |
# FIRST FILE | |
sourceFile = f"{steam_root}{steamvr_null_driver_settings}" | |
if not os.path.islink(sourceFile): | |
# if the symlink was not there, we may are being first-time run or there was an update | |
if os.path.exists(f"{sourceFile}.headless"): | |
os.rename(f"{sourceFile}.headless", f"{sourceFile}.headless_{time.time()}") | |
# create a copy of the file | |
shutil.copy(sourceFile, f"{sourceFile}.headless") | |
# edit the copy to be how we want it | |
# In the driver_null object, change the enable property value from false to true. | |
file_data = {} | |
with open(f"{sourceFile}.headless", 'r+') as f: | |
data = json.load(f) | |
null_body = data['driver_null'] | |
null_body['enable'] = True | |
data['driver_null'] = null_body | |
json.dump(data, f, indent=4) | |
f.truncate() # remove remaining part | |
if os.path.exists(f"{sourceFile}.original"): | |
os.rename(f"{sourceFile}.original", f"{sourceFile}.original_{time.time()}") | |
# rename the original file if it does not already exist | |
os.rename (sourceFile, f"{sourceFile}.original") | |
# symlink the original | |
kdll.CreateSymbolicLinkW(sourceFile, f"{sourceFile}.original", 0) | |
# SECOND FILE | |
sourceFile = f"{steam_root}{steamvr_resource_settings}" | |
if not os.path.islink(sourceFile): | |
# if the symlink was not there, we may are being first-time run or there was an update | |
if os.path.exists(f"{sourceFile}.headless"): | |
os.rename(f"{sourceFile}.headless", f"{sourceFile}.headless_{time.time()}") | |
shutil.copy(sourceFile, f"{sourceFile}.headless") | |
# edit the copy to be how we want it | |
# In the driver_null object, change the enable property value from false to true. | |
file_data = {} | |
with open(f"{sourceFile}.headless", 'r+') as f: | |
data = json.load(f) | |
section_body = data['steamvr'] | |
section_body['requireHmd'] = False | |
section_body['forcedDriver'] = "null" | |
section_body['activateMultipleDrivers'] = True | |
data['steamvr'] = section_body | |
json.dump(data, f, indent=4) | |
f.truncate() # remove remaining part | |
if os.path.exists(f"{sourceFile}.original"): | |
os.rename(f"{sourceFile}.original", f"{sourceFile}.original_{time.time()}") | |
# rename the original file if it does not already exist | |
os.rename (sourceFile, f"{sourceFile}.original") | |
# symlink the original | |
kdll.CreateSymbolicLinkW(sourceFile, f"{sourceFile}.original", 0) | |
# which way are we switching? headless => HMD, HMD => headless | |
driverSrcFile = f"{steam_root}{steamvr_null_driver_settings}" | |
resourceSrcFile = f"{steam_root}{steamvr_resource_settings}" | |
if os.readlink(driverSrcFile).endswith('.original'): | |
print ('\n Switching to HEADLESS mode...\n') | |
os.remove(driverSrcFile) | |
kdll.CreateSymbolicLinkW(driverSrcFile, f"{driverSrcFile}.headless", 0) | |
os.remove(resourceSrcFile) | |
kdll.CreateSymbolicLinkW(resourceSrcFile, f"{resourceSrcFile}.headless", 0) | |
else: | |
print ('\n Switching to HMD mode...\n') | |
os.remove(driverSrcFile) | |
kdll.CreateSymbolicLinkW(driverSrcFile, f"{driverSrcFile}.original", 0) | |
os.remove(resourceSrcFile) | |
kdll.CreateSymbolicLinkW(resourceSrcFile, f"{resourceSrcFile}.original", 0) | |
print('Complete.\n') | |
print ("(You may be required to calibrate your setup again)\n") | |
print('Restarting SteamVR...\n') | |
os.system(f"start {steamVR_launch}") | |
time.sleep(10) | |
elif ret is None: | |
# allowed to enter elevated priviledge mode | |
pass | |
else: | |
# note elevated and elevation request denied | |
print ('\n Elevated permissions are required for this tool for work properly.\n') | |
# Notes: | |
# symlinks -- https://stackoverflow.com/questions/1447575/symlinks-on-windows | |
# steam registry -- https://steamcommunity.com/discussions/forum/1/1621726179573666840/ | |
# files to change -- https://docs.unrealengine.com/4.26/en-US/AnimatingObjects/SkeletalMeshAnimation/LiveLinkPlugin/Livelinkxr/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment