[{"ts":1744499577717,"type":"say","say":"text","text":"Based on the analysis of the OpenVR modifications project, we need to design a custom driver that can access raw IMU data when optical tracking is lost. \n\nPlease analyze the OpenVR driver architecture by examining:\n1. The headers/openvr_driver.h file to understand the driver interface\n2. The docs/Driver_API_Documentation.md file for implementation guidelines\n3. Any sample drivers in the codebase that might serve as references\n\nThen, design a custom driver solution that:\n1. Wraps the existing lighthouse driver\n2. Accesses raw IMU data from the underlying hardware\n3. Exposes this data through a custom interface that applications can use\n4. Ensures IMU data is available even when optical tracking is lost\n\nYour design should include:\n- The overall architecture of the custom driver\n- Key classes and interfaces to implement\n- How the driver will be loaded and initialized\n- How it will interact with the existing lighthouse driver\n- How it will expose the IMU data to applications\n\nThese specific instructions supersede any conflicting general instructions you might have. When you're done, please use the attempt_completion tool to provide a concise yet thorough summary of your design."},{"ts":1744499577762,"type":"say","say":"api_req_started","text":"{\"request\":\"<task>\\nBased on the analysis of the OpenVR modifications project, we need to design a custom driver that can access raw IMU data when optical tracking is lost. \\n\\nPlease analyze the OpenVR driver architecture by examining:\\n1. The headers/openvr_driver.h file to understand the driver interface\\n2. The docs/Driver_API_Documentation.md file for implementation guidelines\\n3. Any sample drivers in the codebase that might serve as references\\n\\nThen, design a custom driver solution that:\\n1. Wraps the existing lighthouse driver\\n2. Accesses raw IMU data from the underlying hardware\\n3. Exposes this data through a custom interface that applications can use\\n4. Ensures IMU data is available even when optical tracking is lost\\n\\nYour design should include:\\n- The overall architecture of the custom driver\\n- Key classes and interfaces to implement\\n- How the driver will be loaded and initialized\\n- How it will interact with the existing lighthouse driver\\n- How it will expose the IMU data to applications\\n\\nThese specific instructions supersede any conflicting general instructions you might have. When you're done, please use the attempt_completion tool to provide a concise yet thorough summary of your design.\\n</task>\\n\\n<environment_details>\\n# VSCode Visible Files\\ndocs\\\\Driver_API_Documentation.md\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:12:57 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n(Not available)\\n\\n# Current Cost\\n$0.00\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n\\n\\n# Current Workspace Directory (c:/Users/decid/Documents/projects/openvr-resilient) Files\\n.gitattributes\\n.gitignore\\n.roomodes\\nbuild.bat\\nCMakeLists.txt\\nLICENSE\\nopenvr_api.vcxproj\\nOpenVR_Modifications.md\\nREADME.md\\nToolchain-clang.cmake\\n.git/\\n.git/COMMIT_EDITMSG\\n.git/config\\n.git/description\\n.git/FETCH_HEAD\\n.git/HEAD\\n.git/index\\n.git/packed-refs\\n.git/hooks/\\n.git/hooks/applypatch-msg.sample\\n.git/hooks/commit-msg.sample\\n.git/hooks/fsmonitor-watchman.sample\\n.git/hooks/post-update.sample\\n.git/hooks/pre-applypatch.sample\\n.git/hooks/pre-commit.sample\\n.git/hooks/pre-merge-commit.sample\\n.git/hooks/pre-push.sample\\n.git/hooks/pre-rebase.sample\\n.git/hooks/pre-receive.sample\\n.git/hooks/prepare-commit-msg.sample\\n.git/hooks/push-to-checkout.sample\\n.git/hooks/sendemail-validate.sample\\n.git/hooks/update.sample\\n.git/info/\\n.git/info/exclude\\n.git/logs/\\n.git/logs/HEAD\\n.git/logs/refs/\\n.git/objects/\\n.git/objects/0d/\\n.git/objects/0f/\\n.git/objects/1d/\\n.git/objects/2c/\\n.git/objects/2d/\\n.git/objects/4c/\\n.git/objects/4f/\\n.git/objects/5d/\\n.git/objects/6c/\\n.git/objects/6e/\\n.git/objects/8b/\\n.git/objects/8c/\\n.git/objects/8e/\\n.git/objects/9b/\\n.git/objects/9d/\\n.git/objects/19/\\n.git/objects/22/\\n.git/objects/23/\\n.git/objects/37/\\n.git/objects/42/\\n.git/objects/44/\\n.git/objects/47/\\n.git/objects/52/\\n.git/objects/54/\\n.git/objects/66/\\n.git/objects/68/\\n.git/objects/74/\\n.git/objects/77/\\n.git/objects/78/\\n.git/objects/80/\\n.git/objects/88/\\n.git/objects/97/\\n.git/objects/a2/\\n.git/objects/a9/\\n.git/objects/ae/\\n.git/objects/b3/\\n.git/objects/b4/\\n.git/objects/b6/\\n.git/objects/c0/\\n.git/objects/c3/\\n.git/objects/c4/\\n.git/objects/c6/\\n.git/objects/c8/\\n.git/objects/cc/\\n.git/objects/cf/\\n.git/objects/d0/\\n.git/objects/d5/\\n.git/objects/e0/\\n.git/objects/e4/\\n.git/objects/e8/\\n.git/objects/eb/\\n.git/objects/ed/\\n.git/objects/f4/\\n.git/objects/f9/\\n.git/objects/fc/\\n.git/objects/fd/\\n.git/objects/fe/\\n.git/objects/info/\\n.git/objects/pack/\\n.git/refs/\\n.git/refs/heads/\\n.git/refs/remotes/\\n.git/refs/tags/\\nbin/\\nbin/androidarm64/\\nbin/androidarm64/libopenvr_api.so\\nbin/linux32/\\nbin/linux32/empty.dir\\nbin/linux32/libopenvr_api.so\\nbin/linux32/libopenvr_api.so.dbg\\nbin/linux64/\\nbin/linux64/empty.dir\\nbin/linux64/libopenvr_api.so\\nbin/linux64/libopenvr_api.so.dbg\\nbin/linuxarm64/\\nbin/linuxarm64/libopenvr_api_unity.so\\nbin/linuxarm64/libopenvr_api_unity.so.dbg\\nbin/linuxarm64/libopenvr_api.so\\nbin/linuxarm64/libopenvr_api.so.dbg\\nbin/osx32/\\nbin/osx32/libopenvr_api.dylib\\nbin/osx32/libopenvr_api.dylib.dSYM/\\nbin/win32/\\nbin/win32/openvr_api.dll\\nbin/win32/openvr_api.dll.sig\\nbin/win64/\\nbin/win64/openvr_api.dll\\nbin/win64/openvr_api.dll.sig\\nbin/win64/openvr_api.exp\\nbin/win64/openvr_api.lib\\nbuild/\\nbuild/ALL_BUILD.vcxproj\\nbuild/ALL_BUILD.vcxproj.filters\\nbuild/cmake_install.cmake\\nbuild/CMakeCache.txt\\nbuild/INSTALL.vcxproj\\nbuild/INSTALL.vcxproj.filters\\nbuild/OpenVRSDK.sln\\nbuild/ZERO_CHECK.vcxproj\\nbuild/ZERO_CHECK.vcxproj.filters\\nbuild/.cmake/\\nbuild/.cmake/api/\\nbuild/CMakeFiles/\\nbuild/CMakeFiles/cmake.check_cache\\nbuild/CMakeFiles/CMakeConfigureLog.yaml\\nbuild/CMakeFiles/3.30.5-msvc23/\\nbuild/CMakeFiles/826cdf6b60e76cf7c71e70cf82f8e109/\\nbuild/CMakeFiles/e9202e66a011c77a76fd29845a49771c/\\nbuild/src/\\ncodegen/\\ncodegen/api_shared.py\\ncodegen/openvr_capi.cpp.py\\ncodegen/openvr_capi.h.py\\ncodegen/openvr_interop.cs.py\\ncodegen/README.md\\ncontroller_callouts/\\ncontroller_callouts/Callouts.eps\\ncontroller_callouts/Callouts.pdf\\ndocs/\\ndocs/Driver_API_Documentation.md\\nheaders/\\nheaders/openvr_api.cs\\nheaders/openvr_api.json\\nheaders/openvr_capi.h\\nheaders/openvr_driver.h\\nheaders/openvr.h\\nlib/\\nlib/androidarm64/\\nlib/linux32/\\nlib/linux64/\\nlib/linuxarm64/\\nlib/osx32/\\nlib/win32/\\nlib/win64/\\nsamples/\\nsamples/CMakeLists.txt\\nsamples/README.md\\nsamples/samples_vs2017.sln\\nsamples/bin/\\nsamples/drivers/\\nsamples/hellovr_dx12/\\nsamples/hellovr_opengl/\\nsamples/hellovr_vulkan/\\nsamples/helloworldoverlay/\\nsamples/hmd_opencv_sandbox/\\nsamples/shared/\\nsamples/thirdparty/\\nsamples/tracked_camera_openvr_sample/\\nsamples/unity_keyboard_sample/\\nsamples/unity_teleport_sample/\\nsrc/\\nsrc/CMakeLists.txt\\nsrc/Info.plist\\nsrc/ivrclientcore.h\\nsrc/jsoncpp.cpp\\nsrc/openvr_api_public.cpp\\nsrc/openvr.pc.in\\nsrc/README\\nsrc/json/\\nsrc/vrcore/\\nx64/\\n\\n(File list truncated. Use list_files on specific subdirectories if you need to explore further.)\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":147,\"cacheWrites\":12989,\"cacheReads\":0,\"cost\":0.05092575}"},{"ts":1744499579885,"type":"say","say":"text","text":"I need to analyze the OpenVR driver architecture to design a custom driver that can access raw IMU data when optical tracking is lost. Let me start by gathering information about the OpenVR driver interface and implementation guidelines.\n\nFirst, I'll examine the headers/openvr_driver.h file to understand the driver interface:\n\nI'll help you design a custom OpenVR driver that can access raw IMU data when optical tracking is lost. Let's start by gathering information about the OpenVR driver architecture.","partial":false},{"ts":1744499581811,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"headers/openvr_driver.h\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\headers\\\\openvr_driver.h\",\"reason\":\" (max 500 lines)\"}","partial":false},{"ts":1744499606859,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'headers/openvr_driver.h'] Result:\\n\\n<file><path>headers/openvr_driver.h</path>\\n<content lines=\\\"1-500\\\">\\n  1 | #pragma once\\r\\n  2 | \\r\\n  3 | // openvr_driver.h\\r\\n  4 | //========= Copyright Valve Corporation ============//\\r\\n  5 | // Dynamically generated file. Do not modify this file directly.\\r\\n  6 | \\r\\n  7 | #ifndef _OPENVR_DRIVER_API\\r\\n  8 | #define _OPENVR_DRIVER_API\\r\\n  9 | \\r\\n 10 | #include <stdint.h>\\r\\n 11 | \\r\\n 12 | \\r\\n 13 | \\r\\n 14 | // version.h\\r\\n 15 | \\r\\n 16 | namespace vr\\r\\n 17 | {\\r\\n 18 | \\tstatic const uint32_t k_nSteamVRVersionMajor = 2;\\r\\n 19 | \\tstatic const uint32_t k_nSteamVRVersionMinor = 5;\\r\\n 20 | \\tstatic const uint32_t k_nSteamVRVersionBuild = 1;\\r\\n 21 | } // namespace vr\\r\\n 22 | \\r\\n 23 | // public_vrtypes.h\\r\\n 24 | \\r\\n 25 | #ifndef _INCLUDE_CORE_VRTYPES_PUBLIC_H\\r\\n 26 | #define _INCLUDE_CORE_VRTYPES_PUBLIC_H\\r\\n 27 | \\r\\n 28 | namespace vr\\r\\n 29 | {\\r\\n 30 | #pragma pack( push, 8 )\\r\\n 31 | \\r\\n 32 | typedef uint32_t PropertyTypeTag_t;\\r\\n 33 | \\r\\n 34 | // right-handed system\\r\\n 35 | // +y is up\\r\\n 36 | // +x is to the right\\r\\n 37 | // -z is forward\\r\\n 38 | // Distance unit is  meters\\r\\n 39 | struct HmdMatrix34_t\\r\\n 40 | {\\r\\n 41 | \\tfloat m[3][4];\\r\\n 42 | };\\r\\n 43 | \\r\\n 44 | struct HmdMatrix33_t\\r\\n 45 | {\\r\\n 46 | \\tfloat m[3][3];\\r\\n 47 | };\\r\\n 48 | \\r\\n 49 | struct HmdMatrix44_t\\r\\n 50 | {\\r\\n 51 | \\tfloat m[4][4];\\r\\n 52 | };\\r\\n 53 | \\r\\n 54 | struct HmdVector3_t\\r\\n 55 | {\\r\\n 56 | \\tfloat v[3];\\r\\n 57 | };\\r\\n 58 | \\r\\n 59 | struct HmdVector4_t\\r\\n 60 | {\\r\\n 61 | \\tfloat v[4];\\r\\n 62 | };\\r\\n 63 | \\r\\n 64 | struct HmdVector3d_t\\r\\n 65 | {\\r\\n 66 | \\tdouble v[3];\\r\\n 67 | };\\r\\n 68 | \\r\\n 69 | struct HmdVector2_t\\r\\n 70 | {\\r\\n 71 | \\tfloat v[2];\\r\\n 72 | };\\r\\n 73 | \\r\\n 74 | struct HmdQuaternion_t\\r\\n 75 | {\\r\\n 76 | \\tdouble w, x, y, z;\\r\\n 77 | };\\r\\n 78 | \\r\\n 79 | struct HmdQuaternionf_t\\r\\n 80 | {\\r\\n 81 | \\tfloat w, x, y, z;\\r\\n 82 | };\\r\\n 83 | \\r\\n 84 | struct HmdColor_t\\r\\n 85 | {\\r\\n 86 | \\tfloat r, g, b, a;\\r\\n 87 | };\\r\\n 88 | \\r\\n 89 | struct HmdQuad_t\\r\\n 90 | {\\r\\n 91 | \\tHmdVector3_t vCorners[ 4 ];\\r\\n 92 | };\\r\\n 93 | \\r\\n 94 | struct HmdRect2_t\\r\\n 95 | {\\r\\n 96 | \\tHmdVector2_t vTopLeft;\\r\\n 97 | \\tHmdVector2_t vBottomRight;\\r\\n 98 | };\\r\\n 99 | \\r\\n100 | /** Holds the transform for a single bone */\\r\\n101 | struct VRBoneTransform_t\\r\\n102 | {\\r\\n103 | \\tHmdVector4_t position;\\r\\n104 | \\tHmdQuaternionf_t orientation;\\r\\n105 | };\\r\\n106 | \\r\\n107 | /** Used to return the post-distortion UVs for each color channel.\\r\\n108 | * UVs range from 0 to 1 with 0,0 in the upper left corner of the\\r\\n109 | * source render target. The 0,0 to 1,1 range covers a single eye. */\\r\\n110 | struct DistortionCoordinates_t\\r\\n111 | {\\r\\n112 | \\tfloat rfRed[2];\\r\\n113 | \\tfloat rfGreen[2];\\r\\n114 | \\tfloat rfBlue[2];\\r\\n115 | };\\r\\n116 | \\r\\n117 | enum EVREye\\r\\n118 | {\\r\\n119 | \\tEye_Left = 0,\\r\\n120 | \\tEye_Right = 1\\r\\n121 | };\\r\\n122 | \\r\\n123 | enum ETextureType\\r\\n124 | {\\r\\n125 | \\tTextureType_Invalid = -1, // Handle has been invalidated\\r\\n126 | \\tTextureType_DirectX = 0, // Handle is an ID3D11Texture\\r\\n127 | \\tTextureType_OpenGL = 1,  // Handle is an OpenGL texture name or an OpenGL render buffer name, depending on submit flags\\r\\n128 | \\tTextureType_Vulkan = 2, // Handle is a pointer to a VRVulkanTextureData_t structure\\r\\n129 | \\tTextureType_IOSurface = 3, // Handle is a macOS cross-process-sharable IOSurfaceRef, deprecated in favor of TextureType_Metal on supported platforms\\r\\n130 | \\tTextureType_DirectX12 = 4, // Handle is a pointer to a D3D12TextureData_t structure\\r\\n131 | \\tTextureType_DXGISharedHandle = 5, // Handle is a HANDLE DXGI share handle, only supported for Overlay render targets.\\r\\n132 | \\t\\t\\t\\t\\t\\t\\t\\t\\t  // this texture is used directly by our renderer, so only perform atomic (copyresource or resolve) on it\\r\\n133 | \\tTextureType_Metal = 6,\\t// Handle is a MTLTexture conforming to the MTLSharedTexture protocol. Textures submitted to IVRCompositor::Submit which\\r\\n134 | \\t\\t\\t\\t\\t\\t\\t// are of type MTLTextureType2DArray assume layer 0 is the left eye texture (vr::EVREye::Eye_left), layer 1 is the right\\r\\n135 | \\t\\t\\t\\t\\t\\t\\t// eye texture (vr::EVREye::Eye_Right)\\r\\n136 | \\r\\n137 | \\tTextureType_Reserved = 7,\\r\\n138 | };\\r\\n139 | \\r\\n140 | enum EColorSpace\\r\\n141 | {\\r\\n142 | \\tColorSpace_Auto = 0,\\t// Assumes 'gamma' for 8-bit per component formats, otherwise 'linear'.  This mirrors the DXGI formats which have _SRGB variants.\\r\\n143 | \\tColorSpace_Gamma = 1,\\t// Texture data can be displayed directly on the display without any conversion (a.k.a. display native format).\\r\\n144 | \\tColorSpace_Linear = 2,\\t// Same as gamma but has been converted to a linear representation using DXGI's sRGB conversion algorithm.\\r\\n145 | };\\r\\n146 | \\r\\n147 | struct Texture_t\\r\\n148 | {\\r\\n149 | \\tvoid* handle; // See ETextureType definition above\\r\\n150 | \\tETextureType eType;\\r\\n151 | \\tEColorSpace eColorSpace;\\r\\n152 | };\\r\\n153 | \\r\\n154 | /** Allows the application to control what part of the provided texture will be used in the\\r\\n155 | * frame buffer. */\\r\\n156 | struct VRTextureBounds_t\\r\\n157 | {\\r\\n158 | \\tfloat uMin, vMin;\\r\\n159 | \\tfloat uMax, vMax;\\r\\n160 | };\\r\\n161 | \\r\\n162 | /** Allows specifying pose used to render provided scene texture (if different from value returned by WaitGetPoses). */\\r\\n163 | struct VRTextureWithPose_t : public Texture_t\\r\\n164 | {\\r\\n165 | \\tHmdMatrix34_t mDeviceToAbsoluteTracking; // Actual pose used to render scene textures.\\r\\n166 | };\\r\\n167 | \\r\\n168 | struct VRTextureDepthInfo_t\\r\\n169 | {\\r\\n170 | \\tvoid* handle; // See ETextureType definition above\\r\\n171 | \\tHmdMatrix44_t mProjection;\\r\\n172 | \\tHmdVector2_t vRange; // 0..1\\r\\n173 | };\\r\\n174 | \\r\\n175 | struct VRTextureWithDepth_t : public Texture_t\\r\\n176 | {\\r\\n177 | \\tVRTextureDepthInfo_t depth;\\r\\n178 | };\\r\\n179 | \\r\\n180 | struct VRTextureWithPoseAndDepth_t : public VRTextureWithPose_t\\r\\n181 | {\\r\\n182 | \\tVRTextureDepthInfo_t depth;\\r\\n183 | };\\r\\n184 | \\r\\n185 | // 64-bit types that are part of public structures\\r\\n186 | // that are replicated in shared memory.\\r\\n187 | #if defined(__linux__) || defined(__APPLE__)\\r\\n188 | typedef uint64_t vrshared_uint64_t __attribute__ ((aligned(8)));\\r\\n189 | typedef double vrshared_double __attribute__ ((aligned(8)));\\r\\n190 | #else\\r\\n191 | typedef uint64_t vrshared_uint64_t;\\r\\n192 | typedef double vrshared_double;\\r\\n193 | #endif\\r\\n194 | \\r\\n195 | #pragma pack( pop )\\r\\n196 | \\r\\n197 | } // namespace vr\\r\\n198 | \\r\\n199 | #endif\\r\\n200 | \\r\\n201 | // vrtypes.h\\r\\n202 | \\r\\n203 | #ifndef _INCLUDE_VRTYPES_H\\r\\n204 | #define _INCLUDE_VRTYPES_H\\r\\n205 | \\r\\n206 | // Forward declarations to avoid requiring vulkan.h\\r\\n207 | struct VkDevice_T;\\r\\n208 | struct VkPhysicalDevice_T;\\r\\n209 | struct VkInstance_T;\\r\\n210 | struct VkQueue_T;\\r\\n211 | \\r\\n212 | // Forward declarations to avoid requiring d3d12.h\\r\\n213 | struct ID3D12Resource;\\r\\n214 | struct ID3D12CommandQueue;\\r\\n215 | \\r\\n216 | namespace vr\\r\\n217 | {\\r\\n218 | #pragma pack( push, 8 )\\r\\n219 | \\r\\n220 | /** A handle for a spatial anchor.  This handle is only valid during the session it was created in.\\r\\n221 | * Anchors that live beyond one session should be saved by their string descriptors. */\\r\\n222 | typedef uint32_t SpatialAnchorHandle_t;\\r\\n223 | \\r\\n224 | typedef void* glSharedTextureHandle_t;\\r\\n225 | typedef int32_t glInt_t;\\r\\n226 | typedef uint32_t glUInt_t;\\r\\n227 | \\r\\n228 | \\r\\n229 | // Handle to a shared texture (HANDLE on Windows obtained using OpenSharedResource).\\r\\n230 | typedef uint64_t SharedTextureHandle_t;\\r\\n231 | #define INVALID_SHARED_TEXTURE_HANDLE\\t((vr::SharedTextureHandle_t)0)\\r\\n232 | \\r\\n233 | enum ETrackingResult\\r\\n234 | {\\r\\n235 | \\tTrackingResult_Uninitialized\\t\\t\\t= 1,\\r\\n236 | \\r\\n237 | \\tTrackingResult_Calibrating_InProgress\\t= 100,\\r\\n238 | \\tTrackingResult_Calibrating_OutOfRange\\t= 101,\\r\\n239 | \\r\\n240 | \\tTrackingResult_Running_OK\\t\\t\\t\\t= 200,\\r\\n241 | \\tTrackingResult_Running_OutOfRange\\t\\t= 201,\\r\\n242 | \\r\\n243 | \\tTrackingResult_Fallback_RotationOnly\\t= 300,\\r\\n244 | };\\r\\n245 | \\r\\n246 | typedef uint32_t DriverId_t;\\r\\n247 | static const uint32_t k_nDriverNone = 0xFFFFFFFF;\\r\\n248 | \\r\\n249 | static const uint32_t k_unMaxDriverDebugResponseSize = 32768;\\r\\n250 | \\r\\n251 | /** Used to pass device IDs to API calls */\\r\\n252 | typedef uint32_t TrackedDeviceIndex_t;\\r\\n253 | static const uint32_t k_unTrackedDeviceIndex_Hmd = 0;\\r\\n254 | static const uint32_t k_unMaxTrackedDeviceCount = 64;\\r\\n255 | static const uint32_t k_unTrackedDeviceIndexOther = 0xFFFFFFFE;\\r\\n256 | static const uint32_t k_unTrackedDeviceIndexInvalid = 0xFFFFFFFF;\\r\\n257 | \\r\\n258 | /** Describes what kind of object is being tracked at a given ID */\\r\\n259 | enum ETrackedDeviceClass\\r\\n260 | {\\r\\n261 | \\tTrackedDeviceClass_Invalid = 0,\\t\\t\\t\\t// the ID was not valid.\\r\\n262 | \\tTrackedDeviceClass_HMD = 1,\\t\\t\\t\\t\\t// Head-Mounted Displays\\r\\n263 | \\tTrackedDeviceClass_Controller = 2,\\t\\t\\t// Tracked controllers\\r\\n264 | \\tTrackedDeviceClass_GenericTracker = 3,\\t\\t// Generic trackers, similar to controllers\\r\\n265 | \\tTrackedDeviceClass_TrackingReference = 4,\\t// Camera and base stations that serve as tracking reference points\\r\\n266 | \\tTrackedDeviceClass_DisplayRedirect = 5,\\t\\t// Accessories that aren't necessarily tracked themselves, but may redirect video output from other tracked devices\\r\\n267 | \\r\\n268 | \\tTrackedDeviceClass_Max\\r\\n269 | };\\r\\n270 | \\r\\n271 | \\r\\n272 | /** Describes what specific role associated with a tracked device */\\r\\n273 | enum ETrackedControllerRole\\r\\n274 | {\\r\\n275 | \\tTrackedControllerRole_Invalid = 0,\\t\\t\\t\\t\\t// Invalid value for controller type\\r\\n276 | \\tTrackedControllerRole_LeftHand = 1,\\t\\t\\t\\t\\t// Tracked device associated with the left hand\\r\\n277 | \\tTrackedControllerRole_RightHand = 2,\\t\\t\\t\\t// Tracked device associated with the right hand\\r\\n278 | \\tTrackedControllerRole_OptOut = 3,\\t\\t\\t\\t\\t// Tracked device is opting out of left/right hand selection\\r\\n279 | \\tTrackedControllerRole_Treadmill = 4,\\t\\t\\t\\t// Tracked device is a treadmill or other locomotion device\\r\\n280 | \\tTrackedControllerRole_Stylus = 5,\\t\\t\\t\\t\\t// Tracked device is a stylus\\r\\n281 | \\tTrackedControllerRole_Max = 5\\r\\n282 | };\\r\\n283 | \\r\\n284 | \\r\\n285 | /** Returns true if the tracked controller role is allowed to be a hand */\\r\\n286 | inline bool IsRoleAllowedAsHand( ETrackedControllerRole eRole )\\r\\n287 | {\\r\\n288 | \\tswitch ( eRole )\\r\\n289 | \\t{\\r\\n290 | \\tcase TrackedControllerRole_Invalid:\\r\\n291 | \\tcase TrackedControllerRole_LeftHand:\\r\\n292 | \\tcase TrackedControllerRole_RightHand:\\r\\n293 | \\t\\treturn true;\\r\\n294 | \\tdefault:\\r\\n295 | \\t\\treturn false;\\r\\n296 | \\t}\\r\\n297 | }\\r\\n298 | \\r\\n299 | \\r\\n300 | /** describes a single pose for a tracked object */\\r\\n301 | struct TrackedDevicePose_t\\r\\n302 | {\\r\\n303 | \\tHmdMatrix34_t mDeviceToAbsoluteTracking;\\r\\n304 | \\tHmdVector3_t vVelocity;\\t\\t\\t\\t// velocity in tracker space in m/s\\r\\n305 | \\tHmdVector3_t vAngularVelocity;\\t\\t// angular velocity in radians/s (?)\\r\\n306 | \\tETrackingResult eTrackingResult;\\r\\n307 | \\tbool bPoseIsValid;\\r\\n308 | \\r\\n309 | \\t// This indicates that there is a device connected for this spot in the pose array.\\r\\n310 | \\t// It could go from true to false if the user unplugs the device.\\r\\n311 | \\tbool bDeviceIsConnected;\\r\\n312 | };\\r\\n313 | \\r\\n314 | /** Identifies which style of tracking origin the application wants to use\\r\\n315 | * for the poses it is requesting */\\r\\n316 | enum ETrackingUniverseOrigin\\r\\n317 | {\\r\\n318 | \\tTrackingUniverseSeated = 0,\\t\\t// Poses are provided relative to the seated zero pose\\r\\n319 | \\tTrackingUniverseStanding = 1,\\t// Poses are provided relative to the safe bounds configured by the user\\r\\n320 | \\tTrackingUniverseRawAndUncalibrated = 2,\\t// Poses are provided in the coordinate system defined by the driver.  It has Y up and is unified for devices of the same driver. You usually don't want this one.\\r\\n321 | };\\r\\n322 | \\r\\n323 | enum EAdditionalRadioFeatures\\r\\n324 | {\\r\\n325 | \\tAdditionalRadioFeatures_None           = 0x00000000,\\r\\n326 | \\tAdditionalRadioFeatures_HTCLinkBox     = 0x00000001,\\r\\n327 | \\tAdditionalRadioFeatures_InternalDongle = 0x00000002,\\r\\n328 | \\tAdditionalRadioFeatures_ExternalDongle = 0x00000004,\\r\\n329 | };\\r\\n330 | \\r\\n331 | typedef uint64_t WebConsoleHandle_t;\\r\\n332 | #define INVALID_WEB_CONSOLE_HANDLE\\t((vr::WebConsoleHandle_t)0)\\r\\n333 | \\r\\n334 | // Refers to a single container of properties\\r\\n335 | typedef uint64_t PropertyContainerHandle_t;\\r\\n336 | typedef uint32_t PropertyTypeTag_t;\\r\\n337 | \\r\\n338 | static const PropertyContainerHandle_t k_ulInvalidPropertyContainer = 0;\\r\\n339 | static const PropertyTypeTag_t k_unInvalidPropertyTag = 0;\\r\\n340 | \\r\\n341 | typedef PropertyContainerHandle_t DriverHandle_t;\\r\\n342 | static const PropertyContainerHandle_t k_ulInvalidDriverHandle = 0;\\r\\n343 | \\r\\n344 | // Use these tags to set/get common types as struct properties\\r\\n345 | static const PropertyTypeTag_t k_unFloatPropertyTag = 1;\\r\\n346 | static const PropertyTypeTag_t k_unInt32PropertyTag = 2;\\r\\n347 | static const PropertyTypeTag_t k_unUint64PropertyTag = 3;\\r\\n348 | static const PropertyTypeTag_t k_unBoolPropertyTag = 4;\\r\\n349 | static const PropertyTypeTag_t k_unStringPropertyTag = 5;\\r\\n350 | static const PropertyTypeTag_t k_unErrorPropertyTag = 6;\\r\\n351 | static const PropertyTypeTag_t k_unDoublePropertyTag = 7;\\r\\n352 | \\r\\n353 | static const PropertyTypeTag_t k_unHmdMatrix34PropertyTag = 20;\\r\\n354 | static const PropertyTypeTag_t k_unHmdMatrix44PropertyTag = 21;\\r\\n355 | static const PropertyTypeTag_t k_unHmdVector3PropertyTag = 22;\\r\\n356 | static const PropertyTypeTag_t k_unHmdVector4PropertyTag = 23;\\r\\n357 | static const PropertyTypeTag_t k_unHmdVector2PropertyTag = 24;\\r\\n358 | static const PropertyTypeTag_t k_unHmdQuadPropertyTag = 25;\\r\\n359 | \\r\\n360 | static const PropertyTypeTag_t k_unHiddenAreaPropertyTag = 30;\\r\\n361 | static const PropertyTypeTag_t k_unPathHandleInfoTag = 31;\\r\\n362 | static const PropertyTypeTag_t k_unActionPropertyTag = 32;\\r\\n363 | static const PropertyTypeTag_t k_unInputValuePropertyTag = 33;\\r\\n364 | static const PropertyTypeTag_t k_unWildcardPropertyTag = 34;\\r\\n365 | static const PropertyTypeTag_t k_unHapticVibrationPropertyTag = 35;\\r\\n366 | static const PropertyTypeTag_t k_unSkeletonPropertyTag = 36;\\r\\n367 | \\r\\n368 | static const PropertyTypeTag_t k_unSpatialAnchorPosePropertyTag = 40;\\r\\n369 | static const PropertyTypeTag_t k_unJsonPropertyTag = 41;\\r\\n370 | static const PropertyTypeTag_t k_unActiveActionSetPropertyTag = 42;\\r\\n371 | \\r\\n372 | static const PropertyTypeTag_t k_unOpenVRInternalReserved_Start = 1000;\\r\\n373 | static const PropertyTypeTag_t k_unOpenVRInternalReserved_End = 10000;\\r\\n374 | \\r\\n375 | \\r\\n376 | /** Each entry in this enum represents a property that can be retrieved about a\\r\\n377 | * tracked device. Many fields are only valid for one ETrackedDeviceClass. */\\r\\n378 | enum ETrackedDeviceProperty\\r\\n379 | {\\r\\n380 | \\tProp_Invalid\\t\\t\\t\\t\\t\\t\\t\\t= 0,\\r\\n381 | \\r\\n382 | \\t// general properties that apply to all device classes\\r\\n383 | \\tProp_TrackingSystemName_String\\t\\t\\t\\t= 1000,\\r\\n384 | \\tProp_ModelNumber_String\\t\\t\\t\\t\\t\\t= 1001,\\r\\n385 | \\tProp_SerialNumber_String\\t\\t\\t\\t\\t= 1002,\\r\\n386 | \\tProp_RenderModelName_String\\t\\t\\t\\t\\t= 1003,\\r\\n387 | \\tProp_WillDriftInYaw_Bool\\t\\t\\t\\t\\t= 1004,\\r\\n388 | \\tProp_ManufacturerName_String\\t\\t\\t\\t= 1005,\\r\\n389 | \\tProp_TrackingFirmwareVersion_String\\t\\t\\t= 1006,\\r\\n390 | \\tProp_HardwareRevision_String\\t\\t\\t\\t= 1007,\\r\\n391 | \\tProp_AllWirelessDongleDescriptions_String\\t= 1008,\\r\\n392 | \\tProp_ConnectedWirelessDongle_String\\t\\t\\t= 1009,\\r\\n393 | \\tProp_DeviceIsWireless_Bool\\t\\t\\t\\t\\t= 1010,\\r\\n394 | \\tProp_DeviceIsCharging_Bool\\t\\t\\t\\t\\t= 1011,\\r\\n395 | \\tProp_DeviceBatteryPercentage_Float\\t\\t\\t= 1012, // 0 is empty, 1 is full\\r\\n396 | \\tProp_StatusDisplayTransform_Matrix34\\t\\t= 1013,\\r\\n397 | \\tProp_Firmware_UpdateAvailable_Bool\\t\\t\\t= 1014,\\r\\n398 | \\tProp_Firmware_ManualUpdate_Bool\\t\\t\\t\\t= 1015,\\r\\n399 | \\tProp_Firmware_ManualUpdateURL_String\\t\\t= 1016,\\r\\n400 | \\tProp_HardwareRevision_Uint64\\t\\t\\t\\t= 1017,\\r\\n401 | \\tProp_FirmwareVersion_Uint64\\t\\t\\t\\t\\t= 1018,\\r\\n402 | \\tProp_FPGAVersion_Uint64\\t\\t\\t\\t\\t\\t= 1019,\\r\\n403 | \\tProp_VRCVersion_Uint64\\t\\t\\t\\t\\t\\t= 1020,\\r\\n404 | \\tProp_RadioVersion_Uint64\\t\\t\\t\\t\\t= 1021,\\r\\n405 | \\tProp_DongleVersion_Uint64\\t\\t\\t\\t\\t= 1022,\\r\\n406 | \\tProp_BlockServerShutdown_Bool\\t\\t\\t\\t= 1023,\\r\\n407 | \\tProp_CanUnifyCoordinateSystemWithHmd_Bool\\t= 1024,\\r\\n408 | \\tProp_ContainsProximitySensor_Bool\\t\\t\\t= 1025,\\r\\n409 | \\tProp_DeviceProvidesBatteryStatus_Bool\\t\\t= 1026,\\r\\n410 | \\tProp_DeviceCanPowerOff_Bool\\t\\t\\t\\t\\t= 1027,\\r\\n411 | \\tProp_Firmware_ProgrammingTarget_String\\t\\t= 1028,\\r\\n412 | \\tProp_DeviceClass_Int32\\t\\t\\t\\t\\t\\t= 1029,\\r\\n413 | \\tProp_HasCamera_Bool\\t\\t\\t\\t\\t\\t\\t= 1030,\\r\\n414 | \\tProp_DriverVersion_String                   = 1031,\\r\\n415 | \\tProp_Firmware_ForceUpdateRequired_Bool      = 1032,\\r\\n416 | \\tProp_ViveSystemButtonFixRequired_Bool\\t\\t= 1033,\\r\\n417 | \\tProp_ParentDriver_Uint64\\t\\t\\t\\t\\t= 1034,\\r\\n418 | \\tProp_ResourceRoot_String\\t\\t\\t\\t\\t= 1035,\\r\\n419 | \\tProp_RegisteredDeviceType_String\\t\\t\\t= 1036,\\r\\n420 | \\tProp_InputProfilePath_String\\t\\t\\t\\t= 1037, // input profile to use for this device in the input system. Will default to tracking system name if this isn't provided\\r\\n421 | \\tProp_NeverTracked_Bool\\t\\t\\t\\t\\t\\t= 1038, // Used for devices that will never have a valid pose by design\\r\\n422 | \\tProp_NumCameras_Int32\\t\\t\\t\\t\\t\\t= 1039,\\r\\n423 | \\tProp_CameraFrameLayout_Int32\\t\\t\\t\\t= 1040, // EVRTrackedCameraFrameLayout value\\r\\n424 | \\tProp_CameraStreamFormat_Int32\\t\\t\\t\\t= 1041, // ECameraVideoStreamFormat value\\r\\n425 | \\tProp_AdditionalDeviceSettingsPath_String\\t= 1042, // driver-relative path to additional device and global configuration settings\\r\\n426 | \\tProp_Identifiable_Bool\\t\\t\\t\\t\\t\\t= 1043, // Whether device supports being identified from vrmonitor (e.g. blink LED, vibrate haptics, etc)\\r\\n427 | \\tProp_BootloaderVersion_Uint64\\t\\t\\t    = 1044,\\r\\n428 | \\tProp_AdditionalSystemReportData_String\\t\\t= 1045, // additional string to include in system reports about a tracked device\\r\\n429 | \\tProp_CompositeFirmwareVersion_String        = 1046, // additional FW components from a device that gets propagated into reports\\r\\n430 | \\tProp_Firmware_RemindUpdate_Bool             = 1047,\\r\\n431 | \\tProp_PeripheralApplicationVersion_Uint64\\t= 1048,\\r\\n432 | \\tProp_ManufacturerSerialNumber_String\\t\\t= 1049,\\r\\n433 | \\tProp_ComputedSerialNumber_String\\t\\t\\t= 1050,\\r\\n434 | \\tProp_EstimatedDeviceFirstUseTime_Int32\\t\\t= 1051,\\r\\n435 | \\tProp_DevicePowerUsage_Float\\t\\t\\t\\t\\t= 1052,\\r\\n436 | \\tProp_IgnoreMotionForStandby_Bool\\t\\t\\t= 1053,\\r\\n437 | \\tProp_ActualTrackingSystemName_String\\t\\t= 1054, // the literal local driver name in case someone is playing games with prop 1000\\r\\n438 | \\r\\n439 | \\t// Properties that are unique to TrackedDeviceClass_HMD\\r\\n440 | \\tProp_ReportsTimeSinceVSync_Bool\\t\\t\\t\\t= 2000,\\r\\n441 | \\tProp_SecondsFromVsyncToPhotons_Float\\t\\t= 2001,\\r\\n442 | \\tProp_DisplayFrequency_Float\\t\\t\\t\\t\\t= 2002,\\r\\n443 | \\tProp_UserIpdMeters_Float\\t\\t\\t\\t\\t= 2003,\\r\\n444 | \\tProp_CurrentUniverseId_Uint64\\t\\t\\t\\t= 2004,\\r\\n445 | \\tProp_PreviousUniverseId_Uint64\\t\\t\\t\\t= 2005,\\r\\n446 | \\tProp_DisplayFirmwareVersion_Uint64\\t\\t\\t= 2006,\\r\\n447 | \\tProp_IsOnDesktop_Bool\\t\\t\\t\\t\\t\\t= 2007,\\r\\n448 | \\tProp_DisplayMCType_Int32\\t\\t\\t\\t\\t= 2008,\\r\\n449 | \\tProp_DisplayMCOffset_Float\\t\\t\\t\\t\\t= 2009,\\r\\n450 | \\tProp_DisplayMCScale_Float\\t\\t\\t\\t\\t= 2010,\\r\\n451 | \\tProp_EdidVendorID_Int32\\t\\t\\t\\t\\t\\t= 2011,\\r\\n452 | \\tProp_DisplayMCImageLeft_String              = 2012,\\r\\n453 | \\tProp_DisplayMCImageRight_String             = 2013,\\r\\n454 | \\tProp_DisplayGCBlackClamp_Float\\t\\t\\t\\t= 2014,\\r\\n455 | \\tProp_EdidProductID_Int32\\t\\t\\t\\t\\t= 2015,\\r\\n456 | \\tProp_CameraToHeadTransform_Matrix34\\t\\t\\t= 2016,\\r\\n457 | \\tProp_DisplayGCType_Int32\\t\\t\\t\\t\\t= 2017,\\r\\n458 | \\tProp_DisplayGCOffset_Float\\t\\t\\t\\t\\t= 2018,\\r\\n459 | \\tProp_DisplayGCScale_Float\\t\\t\\t\\t\\t= 2019,\\r\\n460 | \\tProp_DisplayGCPrescale_Float\\t\\t\\t\\t= 2020,\\r\\n461 | \\tProp_DisplayGCImage_String\\t\\t\\t\\t\\t= 2021,\\r\\n462 | \\tProp_LensCenterLeftU_Float\\t\\t\\t\\t\\t= 2022,\\r\\n463 | \\tProp_LensCenterLeftV_Float\\t\\t\\t\\t\\t= 2023,\\r\\n464 | \\tProp_LensCenterRightU_Float\\t\\t\\t\\t\\t= 2024,\\r\\n465 | \\tProp_LensCenterRightV_Float\\t\\t\\t\\t\\t= 2025,\\r\\n466 | \\tProp_UserHeadToEyeDepthMeters_Float\\t\\t\\t= 2026,\\r\\n467 | \\tProp_CameraFirmwareVersion_Uint64\\t\\t\\t= 2027,\\r\\n468 | \\tProp_CameraFirmwareDescription_String\\t\\t= 2028,\\r\\n469 | \\tProp_DisplayFPGAVersion_Uint64\\t\\t\\t\\t= 2029,\\r\\n470 | \\tProp_DisplayBootloaderVersion_Uint64\\t\\t= 2030,\\r\\n471 | \\tProp_DisplayHardwareVersion_Uint64\\t\\t\\t= 2031,\\r\\n472 | \\tProp_AudioFirmwareVersion_Uint64\\t\\t\\t= 2032,\\r\\n473 | \\tProp_CameraCompatibilityMode_Int32\\t\\t\\t= 2033,\\r\\n474 | \\tProp_ScreenshotHorizontalFieldOfViewDegrees_Float = 2034,\\r\\n475 | \\tProp_ScreenshotVerticalFieldOfViewDegrees_Float = 2035,\\r\\n476 | \\tProp_DisplaySuppressed_Bool\\t\\t\\t\\t\\t= 2036,\\r\\n477 | \\tProp_DisplayAllowNightMode_Bool\\t\\t\\t\\t= 2037,\\r\\n478 | \\tProp_DisplayMCImageWidth_Int32\\t\\t\\t\\t= 2038,\\r\\n479 | \\tProp_DisplayMCImageHeight_Int32\\t\\t\\t\\t= 2039,\\r\\n480 | \\tProp_DisplayMCImageNumChannels_Int32\\t\\t= 2040,\\r\\n481 | \\tProp_DisplayMCImageData_Binary\\t\\t\\t\\t= 2041,\\r\\n482 | \\tProp_SecondsFromPhotonsToVblank_Float\\t\\t= 2042,\\r\\n483 | \\tProp_DriverDirectModeSendsVsyncEvents_Bool\\t= 2043,\\r\\n484 | \\tProp_DisplayDebugMode_Bool\\t\\t\\t\\t\\t= 2044,\\r\\n485 | \\tProp_GraphicsAdapterLuid_Uint64\\t\\t\\t\\t= 2045,\\r\\n486 | \\tProp_DriverProvidedChaperonePath_String\\t\\t= 2048,\\r\\n487 | \\tProp_ExpectedTrackingReferenceCount_Int32\\t= 2049, // expected number of sensors or basestations to reserve UI space for\\r\\n488 | \\tProp_ExpectedControllerCount_Int32\\t\\t\\t= 2050, // expected number of tracked controllers to reserve UI space for\\r\\n489 | \\tProp_NamedIconPathControllerLeftDeviceOff_String\\t= 2051, // placeholder icon for \\\"left\\\" controller if not yet detected/loaded\\r\\n490 | \\tProp_NamedIconPathControllerRightDeviceOff_String\\t= 2052, // placeholder icon for \\\"right\\\" controller if not yet detected/loaded\\r\\n491 | \\tProp_NamedIconPathTrackingReferenceDeviceOff_String\\t= 2053, // placeholder icon for sensor/base if not yet detected/loaded\\r\\n492 | \\tProp_DoNotApplyPrediction_Bool\\t\\t\\t\\t= 2054, // currently no effect. was used to disable HMD pose prediction on MR, which is now done by MR driver setting velocity=0\\r\\n493 | \\tProp_CameraToHeadTransforms_Matrix34_Array\\t= 2055,\\r\\n494 | \\tProp_DistortionMeshResolution_Int32\\t\\t\\t= 2056, // custom resolution of compositor calls to IVRSystem::ComputeDistortion\\r\\n495 | \\tProp_DriverIsDrawingControllers_Bool\\t\\t= 2057,\\r\\n496 | \\tProp_DriverRequestsApplicationPause_Bool\\t= 2058,\\r\\n497 | \\tProp_DriverRequestsReducedRendering_Bool\\t= 2059,\\r\\n498 | \\tProp_MinimumIpdStepMeters_Float\\t\\t\\t\\t= 2060,\\r\\n499 | \\tProp_AudioBridgeFirmwareVersion_Uint64\\t\\t= 2061,\\r\\n500 | \\tProp_ImageBridgeFirmwareVersion_Uint64\\t\\t= 2062,\\r\\n</content>\\n<notice>Showing only 500 of 4576 total lines. Use start_line and end_line if you need to read more</notice>\\n<list_code_definition_names># openvr_driver.h\\n39--42 | struct HmdMatrix34_t\\r\\n29--197 | {\\r\\n44--47 | struct HmdMatrix33_t\\r\\n49--52 | struct HmdMatrix44_t\\r\\n54--57 | struct HmdVector3_t\\r\\n59--62 | struct HmdVector4_t\\r\\n64--67 | struct HmdVector3d_t\\r\\n69--72 | struct HmdVector2_t\\r\\n74--77 | struct HmdQuaternion_t\\r\\n79--82 | struct HmdQuaternionf_t\\r\\n84--87 | struct HmdColor_t\\r\\n89--92 | struct HmdQuad_t\\r\\n94--98 | struct HmdRect2_t\\r\\n101--105 | struct VRBoneTransform_t\\r\\n110--115 | struct DistortionCoordinates_t\\r\\n147--152 | struct Texture_t\\r\\n156--160 | struct VRTextureBounds_t\\r\\n168--173 | struct VRTextureDepthInfo_t\\r\\n301--312 | struct TrackedDevicePose_t\\r\\n217--2186 | {\\r\\n729--738 | struct VRVulkanTextureData_t\\r\\n751--756 | struct D3D12TextureData_t\\r\\n1079--1082 | struct VREvent_Controller_t\\r\\n1095--1103 | struct VREvent_Mouse_t\\r\\n1106--1115 | struct VREvent_Scroll_t\\r\\n1121--1136 | struct VREvent_TouchPadMove_t\\r\\n1139--1143 | struct VREvent_Notification_t\\r\\n1146--1153 | struct VREvent_Process_t\\r\\n1157--1166 | struct VREvent_Overlay_t\\r\\n1170--1173 | struct VREvent_Status_t\\r\\n1176--1181 | struct VREvent_Keyboard_t\\r\\n1183--1186 | struct VREvent_Ipd_t\\r\\n1188--1192 | struct VREvent_Chaperone_t\\r\\n1195--1203 | struct VREvent_Reserved_t\\r\\n1205--1208 | struct VREvent_PerformanceTest_t\\r\\n1210--1213 | struct VREvent_SeatedZeroPoseReset_t\\r\\n1215--1219 | struct VREvent_Screenshot_t\\r\\n1221--1224 | struct VREvent_ScreenshotProgress_t\\r\\n1226--1230 | struct VREvent_ApplicationLaunch_t\\r\\n1232--1236 | struct VREvent_EditingCameraSurface_t\\r\\n1238--1241 | struct VREvent_MessageOverlay_t\\r\\n1243--1247 | struct VREvent_Property_t\\r\\n1249--1256 | struct VREvent_HapticVibration_t\\r\\n1258--1261 | struct VREvent_WebConsole_t\\r\\n1263--1269 | struct VREvent_InputBindingLoad_t\\r\\n1271--1277 | struct VREvent_InputActionManifestLoad_t\\r\\n1279--1282 | struct VREvent_SpatialAnchor_t\\r\\n1284--1292 | struct VREvent_ProgressUpdate_t\\r\\n1306--1309 | struct VREvent_ShowUI_t\\r\\n1311--1314 | struct VREvent_ShowDevTools_t\\r\\n1325--1328 | struct VREvent_HDCPError_t\\r\\n1330--1333 | struct VREvent_AudioVolumeControl_t\\r\\n1335--1338 | struct VREvent_AudioMuteControl_t\\r\\n1340--1374 | typedef union\\r\\n1384--1391 | struct VREvent_t\\r\\n1411--1416 | struct RenderModel_ComponentState_t\\r\\n1468--1472 | struct HiddenAreaMesh_t\\r\\n1498--1502 | struct VRControllerAxis_t\\r\\n1516--1528 | struct VRControllerState001_t\\r\\n2000--2013 | struct CameraVideoStreamFrameHeader_t\\r\\n2049--2092 | struct Compositor_FrameTiming\\r\\n2098--2102 | struct Compositor_BenchmarkResults\\r\\n2105--2112 | struct DriverDirectMode_FrameTiming\\r\\n2144--2150 | struct ImuSample_t\\r\\n2271--2309 | VR_CAMERA_DECL_ALIGN( 8 ) struct CameraVideoStreamFrame_t\\r\\n2215--2313 | {\\r\\n2752--2755 | struct DriverPoseQuaternion_t\\r\\n2749--2868 | {\\r\\n2757--2821 | struct DriverPose_t\\r\\n2949--2953 | \\t\\tstruct SwapTextureSet_t\\r\\n2934--3007 | \\t{\\r\\n2969--2985 | \\t\\tstruct SubmitLayerPerEye_t\\r\\n2993--2997 | \\t\\tstruct Throttling_t\\r\\n3189--3198 | \\tstruct PropertyWrite_t\\r\\n3175--3628 | {\\r\\n3200--3208 | \\tstruct PropertyRead_t\\r\\n3919--3925 | \\tstruct PresentInfo_t\\r\\n3918--3945 | {\\r\\n4058--4086 | \\tstruct SpatialAnchorDriverPose_t\\r\\n4057--4145 | {\\r\\n</list_code_definition_names>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\ndocs\\\\Driver_API_Documentation.md\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:13:26 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n13,140 (7%)\\n\\n# Current Cost\\n$0.05\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":158,\"cacheWrites\":10262,\"cacheReads\":12989,\"cost\":0.0447612}"},{"ts":1744499609926,"type":"say","say":"text","text":"I've examined the first part of the openvr_driver.h file, which gives me some insight into the OpenVR driver interface. Let me continue reading more of this file to understand the driver architecture better, particularly focusing on the parts related to drivers and IMU data.\n\nLet me continue reading the openvr_driver.h file to understand more about the driver interface, particularly focusing on the parts related to drivers and IMU data:","partial":false},{"ts":1744499611550,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"headers/openvr_driver.h\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\headers\\\\openvr_driver.h\",\"reason\":\" (lines 500-1000)\"}","partial":false},{"ts":1744499805269,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'headers/openvr_driver.h'] Result:\\n\\n<file><path>headers/openvr_driver.h</path>\\n<content lines=\\\"500-1000\\\">\\n 500 | \\tProp_ImageBridgeFirmwareVersion_Uint64\\t\\t= 2062,\\r\\n 501 | \\tProp_ImuToHeadTransform_Matrix34\\t\\t\\t= 2063,\\r\\n 502 | \\tProp_ImuFactoryGyroBias_Vector3\\t\\t\\t\\t= 2064,\\r\\n 503 | \\tProp_ImuFactoryGyroScale_Vector3\\t\\t\\t= 2065,\\r\\n 504 | \\tProp_ImuFactoryAccelerometerBias_Vector3\\t= 2066,\\r\\n 505 | \\tProp_ImuFactoryAccelerometerScale_Vector3\\t= 2067,\\r\\n 506 | \\t// reserved 2068\\r\\n 507 | \\tProp_ConfigurationIncludesLighthouse20Features_Bool = 2069,\\r\\n 508 | \\tProp_AdditionalRadioFeatures_Uint64         = 2070,\\r\\n 509 | \\tProp_CameraWhiteBalance_Vector4_Array\\t\\t= 2071, // Prop_NumCameras_Int32-sized array of float[4] RGBG white balance calibration data (max size is vr::k_unMaxCameras)\\r\\n 510 | \\tProp_CameraDistortionFunction_Int32_Array\\t= 2072, // Prop_NumCameras_Int32-sized array of vr::EVRDistortionFunctionType values (max size is vr::k_unMaxCameras)\\r\\n 511 | \\tProp_CameraDistortionCoefficients_Float_Array = 2073, // Prop_NumCameras_Int32-sized array of double[vr::k_unMaxDistortionFunctionParameters] (max size is vr::k_unMaxCameras)\\r\\n 512 | \\tProp_ExpectedControllerType_String\\t\\t\\t= 2074,\\r\\n 513 | \\tProp_HmdTrackingStyle_Int32\\t\\t\\t\\t\\t= 2075, // one of EHmdTrackingStyle\\r\\n 514 | \\tProp_DriverProvidedChaperoneVisibility_Bool = 2076,\\r\\n 515 | \\tProp_HmdColumnCorrectionSettingPrefix_String = 2077,\\r\\n 516 | \\tProp_CameraSupportsCompatibilityModes_Bool\\t= 2078,\\r\\n 517 | \\tProp_SupportsRoomViewDepthProjection_Bool\\t= 2079,\\r\\n 518 | \\tProp_DisplayAvailableFrameRates_Float_Array = 2080, // populated by compositor from actual EDID list when available from GPU driver\\r\\n 519 | \\tProp_DisplaySupportsMultipleFramerates_Bool = 2081, // if this is true but Prop_DisplayAvailableFrameRates_Float_Array is empty, explain to user\\r\\n 520 | \\tProp_DisplayColorMultLeft_Vector3\\t\\t\\t= 2082,\\r\\n 521 | \\tProp_DisplayColorMultRight_Vector3\\t\\t\\t= 2083,\\r\\n 522 | \\tProp_DisplaySupportsRuntimeFramerateChange_Bool = 2084,\\r\\n 523 | \\tProp_DisplaySupportsAnalogGain_Bool \\t\\t= 2085,\\r\\n 524 | \\tProp_DisplayMinAnalogGain_Float \\t\\t\\t= 2086,\\r\\n 525 | \\tProp_DisplayMaxAnalogGain_Float \\t\\t\\t= 2087,\\r\\n 526 |     Prop_CameraExposureTime_Float               = 2088,\\r\\n 527 |     Prop_CameraGlobalGain_Float                 = 2089,\\r\\n 528 | \\t// Prop_DashboardLayoutPathName_String \\t\\t= 2090, // DELETED\\r\\n 529 | \\tProp_DashboardScale_Float \\t\\t\\t\\t\\t= 2091,\\r\\n 530 | \\tProp_PeerButtonInfo_String\\t\\t\\t\\t\\t= 2092,\\r\\n 531 | \\tProp_Hmd_SupportsHDR10_Bool\\t\\t\\t\\t\\t= 2093,\\r\\n 532 | \\tProp_Hmd_EnableParallelRenderCameras_Bool\\t= 2094,\\r\\n 533 | \\tProp_DriverProvidedChaperoneJson_String\\t\\t= 2095, // higher priority than Prop_DriverProvidedChaperonePath_String\\r\\n 534 | \\tProp_ForceSystemLayerUseAppPoses_Bool\\t\\t= 2096,\\r\\n 535 | \\r\\n 536 | \\tProp_IpdUIRangeMinMeters_Float \\t\\t\\t\\t= 2100,\\r\\n 537 | \\tProp_IpdUIRangeMaxMeters_Float \\t\\t\\t\\t= 2101,\\r\\n 538 | \\tProp_Hmd_SupportsHDCP14LegacyCompat_Bool\\t= 2102,\\r\\n 539 | \\tProp_Hmd_SupportsMicMonitoring_Bool \\t\\t= 2103,\\r\\n 540 | \\tProp_Hmd_SupportsDisplayPortTrainingMode_Bool\\t= 2104,\\r\\n 541 | \\tProp_Hmd_SupportsRoomViewDirect_Bool \\t\\t= 2105,\\r\\n 542 | \\tProp_Hmd_SupportsAppThrottling_Bool\\t\\t\\t= 2106,\\r\\n 543 | \\tProp_Hmd_SupportsGpuBusMonitoring_Bool\\t\\t= 2107,\\r\\n 544 | \\tProp_DriverDisplaysIPDChanges_Bool\\t\\t\\t= 2108,\\r\\n 545 | \\tProp_Driver_Reserved_01\\t\\t\\t\\t\\t\\t= 2109,\\r\\n 546 | \\r\\n 547 | \\tProp_DSCVersion_Int32\\t\\t\\t\\t\\t\\t= 2110,\\r\\n 548 | \\tProp_DSCSliceCount_Int32\\t\\t\\t\\t\\t= 2111,\\r\\n 549 | \\tProp_DSCBPPx16_Int32\\t\\t\\t\\t\\t\\t= 2112,\\r\\n 550 | \\r\\n 551 | \\tProp_Hmd_MaxDistortedTextureWidth_Int32\\t\\t= 2113,\\r\\n 552 | \\tProp_Hmd_MaxDistortedTextureHeight_Int32\\t= 2114,\\r\\n 553 | \\tProp_Hmd_AllowSupersampleFiltering_Bool\\t\\t= 2115,\\r\\n 554 | \\r\\n 555 | \\t// Driver requested mura correction properties\\r\\n 556 | \\tProp_DriverRequestedMuraCorrectionMode_Int32\\t\\t= 2200,\\r\\n 557 | \\tProp_DriverRequestedMuraFeather_InnerLeft_Int32\\t\\t= 2201,\\r\\n 558 | \\tProp_DriverRequestedMuraFeather_InnerRight_Int32\\t= 2202,\\r\\n 559 | \\tProp_DriverRequestedMuraFeather_InnerTop_Int32\\t\\t= 2203,\\r\\n 560 | \\tProp_DriverRequestedMuraFeather_InnerBottom_Int32\\t= 2204,\\r\\n 561 | \\tProp_DriverRequestedMuraFeather_OuterLeft_Int32\\t\\t= 2205,\\r\\n 562 | \\tProp_DriverRequestedMuraFeather_OuterRight_Int32\\t= 2206,\\r\\n 563 | \\tProp_DriverRequestedMuraFeather_OuterTop_Int32\\t\\t= 2207,\\r\\n 564 | \\tProp_DriverRequestedMuraFeather_OuterBottom_Int32\\t= 2208,\\r\\n 565 | \\r\\n 566 | \\tProp_Audio_DefaultPlaybackDeviceId_String\\t\\t\\t\\t= 2300,\\r\\n 567 | \\tProp_Audio_DefaultRecordingDeviceId_String\\t\\t\\t\\t= 2301,\\r\\n 568 | \\tProp_Audio_DefaultPlaybackDeviceVolume_Float\\t\\t\\t= 2302,\\r\\n 569 | \\tProp_Audio_SupportsDualSpeakerAndJackOutput_Bool\\t\\t= 2303,\\r\\n 570 | \\tProp_Audio_DriverManagesPlaybackVolumeControl_Bool\\t\\t= 2304,\\r\\n 571 | \\tProp_Audio_DriverPlaybackVolume_Float\\t\\t\\t\\t\\t= 2305,\\r\\n 572 | \\tProp_Audio_DriverPlaybackMute_Bool\\t\\t\\t\\t\\t\\t= 2306,\\r\\n 573 | \\tProp_Audio_DriverManagesRecordingVolumeControl_Bool\\t\\t= 2307,\\r\\n 574 | \\tProp_Audio_DriverRecordingVolume_Float\\t\\t\\t\\t\\t= 2308,\\r\\n 575 | \\tProp_Audio_DriverRecordingMute_Bool\\t\\t\\t\\t\\t\\t= 2309,\\r\\n 576 | \\r\\n 577 | \\t// Properties that are unique to TrackedDeviceClass_Controller\\r\\n 578 | \\tProp_AttachedDeviceId_String\\t\\t\\t\\t= 3000,\\r\\n 579 | \\tProp_SupportedButtons_Uint64\\t\\t\\t\\t= 3001,\\r\\n 580 | \\tProp_Axis0Type_Int32\\t\\t\\t\\t\\t\\t= 3002, // Return value is of type EVRControllerAxisType\\r\\n 581 | \\tProp_Axis1Type_Int32\\t\\t\\t\\t\\t\\t= 3003, // Return value is of type EVRControllerAxisType\\r\\n 582 | \\tProp_Axis2Type_Int32\\t\\t\\t\\t\\t\\t= 3004, // Return value is of type EVRControllerAxisType\\r\\n 583 | \\tProp_Axis3Type_Int32\\t\\t\\t\\t\\t\\t= 3005, // Return value is of type EVRControllerAxisType\\r\\n 584 | \\tProp_Axis4Type_Int32\\t\\t\\t\\t\\t\\t= 3006, // Return value is of type EVRControllerAxisType\\r\\n 585 | \\tProp_ControllerRoleHint_Int32\\t\\t\\t\\t= 3007, // Return value is of type ETrackedControllerRole\\r\\n 586 | \\r\\n 587 | \\t// Properties that are unique to TrackedDeviceClass_TrackingReference\\r\\n 588 | \\tProp_FieldOfViewLeftDegrees_Float\\t\\t\\t= 4000,\\r\\n 589 | \\tProp_FieldOfViewRightDegrees_Float\\t\\t\\t= 4001,\\r\\n 590 | \\tProp_FieldOfViewTopDegrees_Float\\t\\t\\t= 4002,\\r\\n 591 | \\tProp_FieldOfViewBottomDegrees_Float\\t\\t\\t= 4003,\\r\\n 592 | \\tProp_TrackingRangeMinimumMeters_Float\\t\\t= 4004,\\r\\n 593 | \\tProp_TrackingRangeMaximumMeters_Float\\t\\t= 4005,\\r\\n 594 | \\tProp_ModeLabel_String\\t\\t\\t\\t\\t\\t= 4006,\\r\\n 595 | \\tProp_CanWirelessIdentify_Bool               = 4007, // volatile, based on radio presence and fw discovery\\r\\n 596 | \\tProp_Nonce_Int32                            = 4008,\\r\\n 597 | \\r\\n 598 | \\t// Properties that are used for user interface like icons names\\r\\n 599 | \\tProp_IconPathName_String\\t\\t\\t\\t\\t\\t= 5000, // DEPRECATED. Value not referenced. Now expected to be part of icon path properties.\\r\\n 600 | \\tProp_NamedIconPathDeviceOff_String\\t\\t\\t\\t= 5001, // {driver}/icons/icon_filename - PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others\\r\\n 601 | \\tProp_NamedIconPathDeviceSearching_String\\t\\t= 5002, // {driver}/icons/icon_filename - PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others\\r\\n 602 | \\tProp_NamedIconPathDeviceSearchingAlert_String\\t= 5003, // {driver}/icons/icon_filename - PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others\\r\\n 603 | \\tProp_NamedIconPathDeviceReady_String\\t\\t\\t= 5004, // {driver}/icons/icon_filename - PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others\\r\\n 604 | \\tProp_NamedIconPathDeviceReadyAlert_String\\t\\t= 5005, // {driver}/icons/icon_filename - PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others\\r\\n 605 | \\tProp_NamedIconPathDeviceNotReady_String\\t\\t\\t= 5006, // {driver}/icons/icon_filename - PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others\\r\\n 606 | \\tProp_NamedIconPathDeviceStandby_String\\t\\t\\t= 5007, // {driver}/icons/icon_filename - PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others\\r\\n 607 | \\tProp_NamedIconPathDeviceAlertLow_String\\t\\t\\t= 5008, // {driver}/icons/icon_filename - PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others\\r\\n 608 | \\tProp_NamedIconPathDeviceStandbyAlert_String\\t\\t= 5009, // {driver}/icons/icon_filename - PNG for static icon, or GIF for animation, 50x32 for headsets and 32x32 for others\\r\\n 609 | \\r\\n 610 | \\t// Properties that are used by helpers, but are opaque to applications\\r\\n 611 | \\tProp_DisplayHiddenArea_Binary_Start\\t\\t\\t\\t= 5100,\\r\\n 612 | \\tProp_DisplayHiddenArea_Binary_End\\t\\t\\t\\t= 5150,\\r\\n 613 | \\tProp_ParentContainer\\t\\t\\t\\t\\t\\t\\t= 5151,\\r\\n 614 | \\tProp_OverrideContainer_Uint64\\t\\t\\t\\t\\t= 5152,\\r\\n 615 | \\r\\n 616 | \\t// Properties that are unique to drivers\\r\\n 617 | \\tProp_UserConfigPath_String\\t\\t\\t\\t\\t= 6000,\\r\\n 618 | \\tProp_InstallPath_String\\t\\t\\t\\t\\t\\t= 6001,\\r\\n 619 | \\tProp_HasDisplayComponent_Bool\\t\\t\\t\\t= 6002,\\r\\n 620 | \\tProp_HasControllerComponent_Bool\\t\\t\\t= 6003,\\r\\n 621 | \\tProp_HasCameraComponent_Bool\\t\\t\\t\\t= 6004,\\r\\n 622 | \\tProp_HasDriverDirectModeComponent_Bool\\t\\t= 6005,\\r\\n 623 | \\tProp_HasVirtualDisplayComponent_Bool\\t\\t= 6006,\\r\\n 624 | \\tProp_HasSpatialAnchorsSupport_Bool\\t\\t\\t= 6007,\\r\\n 625 | \\tProp_SupportsXrTextureSets_Bool\\t\\t\\t\\t= 6008,\\r\\n 626 | \\r\\n 627 | \\t// Properties that are set internally based on other information provided by drivers\\r\\n 628 | \\tProp_ControllerType_String\\t\\t\\t\\t\\t= 7000,\\r\\n 629 | \\t//Prop_LegacyInputProfile_String\\t\\t\\t\\t= 7001, // This is no longer used. See \\\"legacy_binding\\\" in the input profile instead.\\r\\n 630 | \\tProp_ControllerHandSelectionPriority_Int32\\t= 7002, // Allows hand assignments to prefer some controllers over others. High numbers are selected over low numbers\\r\\n 631 | \\r\\n 632 | \\t// Vendors are free to expose private debug data in this reserved region\\r\\n 633 | \\tProp_VendorSpecific_Reserved_Start\\t\\t\\t= 10000,\\r\\n 634 | \\tProp_VendorSpecific_Reserved_End\\t\\t\\t= 10999,\\r\\n 635 | \\r\\n 636 | \\tProp_TrackedDeviceProperty_Max\\t\\t\\t\\t= 1000000,\\r\\n 637 | };\\r\\n 638 | \\r\\n 639 | /** No string property will ever be longer than this length */\\r\\n 640 | static const uint32_t k_unMaxPropertyStringSize = 32 * 1024;\\r\\n 641 | \\r\\n 642 | /** Used to return errors that occur when reading properties. */\\r\\n 643 | enum ETrackedPropertyError\\r\\n 644 | {\\r\\n 645 | \\tTrackedProp_Success\\t\\t\\t\\t\\t\\t= 0,\\r\\n 646 | \\tTrackedProp_WrongDataType\\t\\t\\t\\t= 1,\\r\\n 647 | \\tTrackedProp_WrongDeviceClass\\t\\t\\t= 2,\\r\\n 648 | \\tTrackedProp_BufferTooSmall\\t\\t\\t\\t= 3,\\r\\n 649 | \\tTrackedProp_UnknownProperty\\t\\t\\t\\t= 4, // Driver has not set the property (and may not ever).\\r\\n 650 | \\tTrackedProp_InvalidDevice\\t\\t\\t\\t= 5,\\r\\n 651 | \\tTrackedProp_CouldNotContactServer\\t\\t= 6,\\r\\n 652 | \\tTrackedProp_ValueNotProvidedByDevice\\t= 7,\\r\\n 653 | \\tTrackedProp_StringExceedsMaximumLength\\t= 8,\\r\\n 654 | \\tTrackedProp_NotYetAvailable\\t\\t\\t\\t= 9, // The property value isn't known yet, but is expected soon. Call again later.\\r\\n 655 | \\tTrackedProp_PermissionDenied\\t\\t\\t= 10,\\r\\n 656 | \\tTrackedProp_InvalidOperation\\t\\t\\t= 11,\\r\\n 657 | \\tTrackedProp_CannotWriteToWildcards\\t\\t= 12,\\r\\n 658 | \\tTrackedProp_IPCReadFailure\\t\\t\\t\\t= 13,\\r\\n 659 | \\tTrackedProp_OutOfMemory\\t\\t\\t\\t\\t= 14,\\r\\n 660 | \\tTrackedProp_InvalidContainer\\t\\t\\t= 15,\\r\\n 661 | };\\r\\n 662 | \\r\\n 663 | /** Used to drive certain text in the UI when talking about the tracking system for the HMD */\\r\\n 664 | enum EHmdTrackingStyle\\r\\n 665 | {\\r\\n 666 | \\tHmdTrackingStyle_Unknown\\t\\t\\t\\t= 0,\\r\\n 667 | \\r\\n 668 | \\tHmdTrackingStyle_Lighthouse\\t\\t\\t\\t= 1, // base stations and lasers\\r\\n 669 | \\tHmdTrackingStyle_OutsideInCameras\\t\\t= 2, // Cameras and LED, Rift 1 style\\r\\n 670 | \\tHmdTrackingStyle_InsideOutCameras\\t\\t= 3, // Cameras on HMD looking at the world\\r\\n 671 | };\\r\\n 672 | \\r\\n 673 | typedef uint64_t VRActionHandle_t;\\r\\n 674 | typedef uint64_t VRActionSetHandle_t;\\r\\n 675 | typedef uint64_t VRInputValueHandle_t;\\r\\n 676 | \\r\\n 677 | static const VRActionHandle_t k_ulInvalidActionHandle = 0;\\r\\n 678 | static const VRActionSetHandle_t k_ulInvalidActionSetHandle = 0;\\r\\n 679 | static const VRInputValueHandle_t k_ulInvalidInputValueHandle = 0;\\r\\n 680 | \\r\\n 681 | \\r\\n 682 | /** Allows the application to control how scene textures are used by the compositor when calling Submit. */\\r\\n 683 | enum EVRSubmitFlags\\r\\n 684 | {\\r\\n 685 | \\t// Simple render path. App submits rendered left and right eye images with no lens distortion correction applied.\\r\\n 686 | \\tSubmit_Default = 0x00,\\r\\n 687 | \\r\\n 688 | \\t// App submits final left and right eye images with lens distortion already applied (lens distortion makes the images appear\\r\\n 689 | \\t// barrel distorted with chromatic aberration correction applied). The app would have used the data returned by\\r\\n 690 | \\t// vr::IVRSystem::ComputeDistortion() to apply the correct distortion to the rendered images before calling Submit().\\r\\n 691 | \\tSubmit_LensDistortionAlreadyApplied = 0x01,\\r\\n 692 | \\r\\n 693 | \\t// If the texture pointer passed in is actually a renderbuffer (e.g. for MSAA in OpenGL) then set this flag.\\r\\n 694 | \\tSubmit_GlRenderBuffer = 0x02,\\r\\n 695 | \\r\\n 696 | \\t// Do not use\\r\\n 697 | \\tSubmit_Reserved = 0x04,\\r\\n 698 | \\r\\n 699 | \\t// Set to indicate that pTexture is a pointer to a VRTextureWithPose_t.\\r\\n 700 | \\t// This flag can be combined with Submit_TextureWithDepth to pass a VRTextureWithPoseAndDepth_t.\\r\\n 701 | \\tSubmit_TextureWithPose = 0x08,\\r\\n 702 | \\r\\n 703 | \\t// Set to indicate that pTexture is a pointer to a VRTextureWithDepth_t.\\r\\n 704 | \\t// This flag can be combined with Submit_TextureWithPose to pass a VRTextureWithPoseAndDepth_t.\\r\\n 705 | \\tSubmit_TextureWithDepth = 0x10,\\r\\n 706 | \\r\\n 707 | \\t// Set to indicate a discontinuity between this and the last frame.\\r\\n 708 | \\t// This will prevent motion smoothing from attempting to extrapolate using the pair.\\r\\n 709 | \\tSubmit_FrameDiscontinuty = 0x20,\\r\\n 710 | \\r\\n 711 | \\t// Set to indicate that pTexture->handle is a contains VRVulkanTextureArrayData_t\\r\\n 712 | \\tSubmit_VulkanTextureWithArrayData = 0x40,\\r\\n 713 | \\r\\n 714 | \\t// If the texture pointer passed in is an OpenGL Array texture, set this flag\\r\\n 715 | \\tSubmit_GlArrayTexture = 0x80,\\r\\n 716 | \\r\\n 717 | \\t// If the texture is an EGL texture and not an glX/wGL texture (Linux only, currently)\\r\\n 718 | \\tSubmit_IsEgl = 0x100,\\r\\n 719 | \\r\\n 720 | \\t// Do not use\\r\\n 721 | \\tSubmit_Reserved2 = 0x08000,\\r\\n 722 | \\tSubmit_Reserved3 = 0x10000,\\r\\n 723 | \\r\\n 724 | };\\r\\n 725 | \\r\\n 726 | /** Data required for passing Vulkan textures to IVRCompositor::Submit.\\r\\n 727 | * Be sure to call OpenVR_Shutdown before destroying these resources.\\r\\n 728 | * Please see https://github.com/ValveSoftware/openvr/wiki/Vulkan for Vulkan-specific documentation */\\r\\n 729 | struct VRVulkanTextureData_t\\r\\n 730 | {\\r\\n 731 | \\tuint64_t m_nImage; // VkImage\\r\\n 732 | \\tVkDevice_T *m_pDevice;\\r\\n 733 | \\tVkPhysicalDevice_T *m_pPhysicalDevice;\\r\\n 734 | \\tVkInstance_T *m_pInstance;\\r\\n 735 | \\tVkQueue_T *m_pQueue;\\r\\n 736 | \\tuint32_t m_nQueueFamilyIndex;\\r\\n 737 | \\tuint32_t m_nWidth, m_nHeight, m_nFormat, m_nSampleCount;\\r\\n 738 | };\\r\\n 739 | \\r\\n 740 | /** Data required for passing Vulkan texture arrays to IVRCompositor::Submit.\\r\\n 741 | * Be sure to call OpenVR_Shutdown before destroying these resources.\\r\\n 742 | * Please see https://github.com/ValveSoftware/openvr/wiki/Vulkan for Vulkan-specific documentation */\\r\\n 743 | struct VRVulkanTextureArrayData_t : public VRVulkanTextureData_t\\r\\n 744 | {\\r\\n 745 | \\tuint32_t m_unArrayIndex;\\r\\n 746 | \\tuint32_t m_unArraySize;\\r\\n 747 | };\\r\\n 748 | \\r\\n 749 | /** Data required for passing D3D12 textures to IVRCompositor::Submit.\\r\\n 750 | * Be sure to call OpenVR_Shutdown before destroying these resources. */\\r\\n 751 | struct D3D12TextureData_t\\r\\n 752 | {\\r\\n 753 | \\tID3D12Resource *m_pResource;\\r\\n 754 | \\tID3D12CommandQueue *m_pCommandQueue;\\r\\n 755 | \\tuint32_t m_nNodeMask;\\r\\n 756 | };\\r\\n 757 | \\r\\n 758 | /** Status of the overall system or tracked objects */\\r\\n 759 | enum EVRState\\r\\n 760 | {\\r\\n 761 | \\tVRState_Undefined = -1,\\r\\n 762 | \\tVRState_Off = 0,\\r\\n 763 | \\tVRState_Searching = 1,\\r\\n 764 | \\tVRState_Searching_Alert = 2,\\r\\n 765 | \\tVRState_Ready = 3,\\r\\n 766 | \\tVRState_Ready_Alert = 4,\\r\\n 767 | \\tVRState_NotReady = 5,\\r\\n 768 | \\tVRState_Standby = 6,\\r\\n 769 | \\tVRState_Ready_Alert_Low = 7,\\r\\n 770 | };\\r\\n 771 | \\r\\n 772 | /** The types of events that could be posted (and what the parameters mean for each event type) */\\r\\n 773 | enum EVREventType\\r\\n 774 | {\\r\\n 775 | \\tVREvent_None = 0,\\r\\n 776 | \\r\\n 777 | \\tVREvent_TrackedDeviceActivated\\t\\t= 100,\\r\\n 778 | \\tVREvent_TrackedDeviceDeactivated\\t= 101,\\r\\n 779 | \\tVREvent_TrackedDeviceUpdated\\t\\t= 102,\\r\\n 780 | \\tVREvent_TrackedDeviceUserInteractionStarted\\t= 103,\\r\\n 781 | \\tVREvent_TrackedDeviceUserInteractionEnded\\t= 104,\\r\\n 782 | \\tVREvent_IpdChanged\\t\\t\\t\\t\\t= 105,\\r\\n 783 | \\tVREvent_EnterStandbyMode\\t\\t\\t= 106,\\r\\n 784 | \\tVREvent_LeaveStandbyMode\\t\\t\\t= 107,\\r\\n 785 | \\tVREvent_TrackedDeviceRoleChanged\\t= 108,\\r\\n 786 | \\tVREvent_WatchdogWakeUpRequested\\t\\t= 109,\\r\\n 787 | \\tVREvent_LensDistortionChanged\\t\\t= 110,\\r\\n 788 | \\tVREvent_PropertyChanged\\t\\t\\t\\t= 111,\\r\\n 789 | \\tVREvent_WirelessDisconnect\\t\\t\\t= 112,\\r\\n 790 | \\tVREvent_WirelessReconnect\\t\\t\\t= 113,\\r\\n 791 | \\tVREvent_Reserved_01\\t\\t\\t\\t\\t= 114,\\r\\n 792 | \\tVREvent_Reserved_02\\t\\t\\t\\t\\t= 115,\\r\\n 793 | \\r\\n 794 | \\tVREvent_ButtonPress\\t\\t\\t\\t\\t= 200, // data is controller\\r\\n 795 | \\tVREvent_ButtonUnpress\\t\\t\\t\\t= 201, // data is controller\\r\\n 796 | \\tVREvent_ButtonTouch\\t\\t\\t\\t\\t= 202, // data is controller\\r\\n 797 | \\tVREvent_ButtonUntouch\\t\\t\\t\\t= 203, // data is controller\\r\\n 798 | \\r\\n 799 | \\t// VREvent_DualAnalog_Press\\t\\t\\t= 250, // No longer sent\\r\\n 800 | \\t// VREvent_DualAnalog_Unpress\\t\\t= 251, // No longer sent\\r\\n 801 | \\t// VREvent_DualAnalog_Touch\\t\\t\\t= 252, // No longer sent\\r\\n 802 | \\t// VREvent_DualAnalog_Untouch\\t\\t= 253, // No longer sent\\r\\n 803 | \\t// VREvent_DualAnalog_Move\\t\\t\\t= 254, // No longer sent\\r\\n 804 | \\t// VREvent_DualAnalog_ModeSwitch1\\t= 255, // No longer sent\\r\\n 805 | \\t// VREvent_DualAnalog_ModeSwitch2\\t= 256, // No longer sent\\r\\n 806 | \\tVREvent_Modal_Cancel\\t\\t\\t\\t= 257, // Sent to overlays with the\\r\\n 807 | \\r\\n 808 | \\tVREvent_MouseMove\\t\\t\\t\\t\\t= 300, // data is mouse\\r\\n 809 | \\tVREvent_MouseButtonDown\\t\\t\\t\\t= 301, // data is mouse\\r\\n 810 | \\tVREvent_MouseButtonUp\\t\\t\\t\\t= 302, // data is mouse\\r\\n 811 | \\tVREvent_FocusEnter\\t\\t\\t\\t\\t= 303, // data is overlay\\r\\n 812 | \\tVREvent_FocusLeave\\t\\t\\t\\t\\t= 304, // data is overlay\\r\\n 813 | \\tVREvent_ScrollDiscrete\\t\\t\\t\\t= 305, // data is scroll\\r\\n 814 | \\tVREvent_TouchPadMove\\t\\t\\t\\t= 306, // data is mouse\\r\\n 815 | \\tVREvent_OverlayFocusChanged\\t\\t\\t= 307, // data is overlay, global event\\r\\n 816 | \\tVREvent_ReloadOverlays\\t\\t\\t\\t= 308,\\r\\n 817 | \\tVREvent_ScrollSmooth\\t\\t\\t\\t= 309, // data is scroll\\r\\n 818 | \\tVREvent_LockMousePosition\\t\\t\\t= 310, // data is mouse\\r\\n 819 | \\tVREvent_UnlockMousePosition\\t\\t\\t= 311, // data is mouse\\r\\n 820 | \\r\\n 821 | \\tVREvent_InputFocusCaptured\\t\\t\\t= 400, // data is process DEPRECATED\\r\\n 822 | \\tVREvent_InputFocusReleased\\t\\t\\t= 401, // data is process DEPRECATED\\r\\n 823 | \\t// VREvent_SceneFocusLost\\t\\t\\t= 402, // data is process\\r\\n 824 | \\t// VREvent_SceneFocusGained\\t\\t\\t= 403, // data is process\\r\\n 825 | \\tVREvent_SceneApplicationChanged\\t\\t= 404, // data is process - The App actually drawing the scene changed (usually to or from the compositor)\\r\\n 826 | \\t// VREvent_SceneFocusChanged\\t\\t= 405, // data is process - This is defunct and will not be called.\\r\\n 827 | \\tVREvent_InputFocusChanged\\t\\t\\t= 406, // data is process\\r\\n 828 | \\t// VREvent_SceneApplicationSecondaryRenderingStarted = 407,\\r\\n 829 | \\tVREvent_SceneApplicationUsingWrongGraphicsAdapter = 408, // data is process\\r\\n 830 | \\tVREvent_ActionBindingReloaded\\t\\t = 409, // data is process - The App that action binds reloaded for\\r\\n 831 | \\r\\n 832 | \\tVREvent_HideRenderModels\\t\\t\\t= 410, // Sent to the scene application to request hiding render models temporarily\\r\\n 833 | \\tVREvent_ShowRenderModels\\t\\t\\t= 411, // Sent to the scene application to request restoring render model visibility\\r\\n 834 | \\r\\n 835 | \\tVREvent_SceneApplicationStateChanged = 412, // No data; but query VRApplications()->GetSceneApplicationState();\\r\\n 836 | \\r\\n 837 | \\tVREvent_SceneAppPipeDisconnected    = 413, // data is process - Called when the scene app's pipe has been closed.\\r\\n 838 | \\r\\n 839 | \\tVREvent_ConsoleOpened               = 420,\\r\\n 840 | \\tVREvent_ConsoleClosed               = 421,\\r\\n 841 | \\r\\n 842 | \\tVREvent_OverlayShown\\t\\t\\t\\t= 500, // Indicates that an overlay is now visible to someone and should be rendering normally. Reflects IVROverlay::IsOverlayVisible() becoming true.\\r\\n 843 | \\tVREvent_OverlayHidden\\t\\t\\t\\t= 501, // Indicates that an overlay is no longer visible to someone and doesn't need to render frames. Reflects IVROverlay::IsOverlayVisible() becoming false.\\r\\n 844 | \\tVREvent_DashboardActivated\\t\\t\\t= 502,\\r\\n 845 | \\tVREvent_DashboardDeactivated\\t\\t= 503,\\r\\n 846 | \\t//VREvent_DashboardThumbSelected\\t\\t= 504, // Sent to the overlay manager - data is overlay - No longer sent\\r\\n 847 | \\tVREvent_DashboardRequested\\t\\t\\t= 505, // Sent to the overlay manager - data is overlay\\r\\n 848 | \\tVREvent_ResetDashboard\\t\\t\\t\\t= 506, // Send to the overlay manager\\r\\n 849 | \\t//VREvent_RenderToast\\t\\t\\t\\t\\t= 507, // Send to the dashboard to render a toast - data is the notification ID -- no longer sent\\r\\n 850 | \\tVREvent_ImageLoaded\\t\\t\\t\\t\\t= 508, // Sent to overlays when a SetOverlayRaw or SetOverlayFromFile call finishes loading\\r\\n 851 | \\tVREvent_ShowKeyboard\\t\\t\\t\\t= 509, // Sent to keyboard renderer in the dashboard to invoke it\\r\\n 852 | \\tVREvent_HideKeyboard\\t\\t\\t\\t= 510, // Sent to keyboard renderer in the dashboard to hide it\\r\\n 853 | \\tVREvent_OverlayGamepadFocusGained\\t= 511, // Sent to an overlay when IVROverlay::SetFocusOverlay is called on it\\r\\n 854 | \\tVREvent_OverlayGamepadFocusLost\\t\\t= 512, // Send to an overlay when it previously had focus and IVROverlay::SetFocusOverlay is called on something else\\r\\n 855 | \\tVREvent_OverlaySharedTextureChanged = 513,\\r\\n 856 | \\t//VREvent_DashboardGuideButtonDown\\t= 514, // These are no longer sent\\r\\n 857 | \\t//VREvent_DashboardGuideButtonUp\\t\\t= 515,\\r\\n 858 | \\tVREvent_ScreenshotTriggered\\t\\t\\t= 516, // Screenshot button combo was pressed, Dashboard should request a screenshot\\r\\n 859 | \\tVREvent_ImageFailed\\t\\t\\t\\t\\t= 517, // Sent to overlays when a SetOverlayRaw or SetOverlayfromFail fails to load\\r\\n 860 | \\tVREvent_DashboardOverlayCreated\\t\\t= 518,\\r\\n 861 | \\tVREvent_SwitchGamepadFocus\\t\\t\\t= 519,\\r\\n 862 | \\r\\n 863 | \\t// Screenshot API\\r\\n 864 | \\tVREvent_RequestScreenshot\\t\\t\\t\\t= 520, // Sent by vrclient application to compositor to take a screenshot\\r\\n 865 | \\tVREvent_ScreenshotTaken\\t\\t\\t\\t\\t= 521, // Sent by compositor to the application that the screenshot has been taken\\r\\n 866 | \\tVREvent_ScreenshotFailed\\t\\t\\t\\t= 522, // Sent by compositor to the application that the screenshot failed to be taken\\r\\n 867 | \\tVREvent_SubmitScreenshotToDashboard\\t\\t= 523, // Sent by compositor to the dashboard that a completed screenshot was submitted\\r\\n 868 | \\tVREvent_ScreenshotProgressToDashboard\\t= 524, // Sent by compositor to the dashboard that a completed screenshot was submitted\\r\\n 869 | \\r\\n 870 | \\tVREvent_PrimaryDashboardDeviceChanged\\t= 525,\\r\\n 871 | \\tVREvent_RoomViewShown\\t\\t\\t\\t\\t= 526, // Sent by compositor whenever room-view is enabled\\r\\n 872 | \\tVREvent_RoomViewHidden\\t\\t\\t\\t\\t= 527, // Sent by compositor whenever room-view is disabled\\r\\n 873 | \\tVREvent_ShowUI\\t\\t\\t\\t\\t\\t\\t= 528, // data is showUi\\r\\n 874 | \\tVREvent_ShowDevTools\\t\\t\\t\\t\\t= 529, // data is showDevTools\\r\\n 875 | \\tVREvent_DesktopViewUpdating\\t\\t\\t\\t= 530,\\r\\n 876 | \\tVREvent_DesktopViewReady\\t\\t\\t\\t= 531,\\r\\n 877 | \\r\\n 878 | \\tVREvent_StartDashboard\\t\\t\\t\\t\\t= 532,\\r\\n 879 | \\tVREvent_ElevatePrism\\t\\t\\t\\t\\t= 533,\\r\\n 880 | \\r\\n 881 | \\tVREvent_OverlayClosed\\t\\t\\t\\t\\t= 534,\\r\\n 882 | \\r\\n 883 | \\tVREvent_DashboardThumbChanged\\t\\t\\t= 535, // Sent when a dashboard thumbnail image changes\\r\\n 884 | \\r\\n 885 | \\tVREvent_DesktopMightBeVisible\\t\\t\\t= 536, // Sent when any known desktop related overlay is visible\\r\\n 886 | \\tVREvent_DesktopMightBeHidden\\t\\t\\t= 537, // Sent when all known desktop related overlays are hidden\\r\\n 887 | \\r\\n 888 | \\tVREvent_MutualSteamCapabilitiesChanged\\t= 538, // Sent when the set of capabilities common between both Steam and SteamVR have changed.\\r\\n 889 | \\r\\n 890 | \\tVREvent_OverlayCreated\\t\\t\\t\\t\\t= 539, // An OpenVR overlay of any sort was created. Data is overlay.\\r\\n 891 | \\tVREvent_OverlayDestroyed\\t\\t\\t\\t= 540, // An OpenVR overlay of any sort was destroyed. Data is overlay.\\r\\n 892 | \\r\\n 893 | \\tVREvent_Notification_Shown\\t\\t\\t\\t= 600,\\r\\n 894 | \\tVREvent_Notification_Hidden\\t\\t\\t\\t= 601,\\r\\n 895 | \\tVREvent_Notification_BeginInteraction\\t= 602,\\r\\n 896 | \\tVREvent_Notification_Destroyed\\t\\t\\t= 603,\\r\\n 897 | \\r\\n 898 | \\tVREvent_Quit\\t\\t\\t\\t\\t\\t\\t= 700, // data is process\\r\\n 899 | \\tVREvent_ProcessQuit\\t\\t\\t\\t\\t\\t= 701, // data is process\\r\\n 900 | \\t//VREvent_QuitAborted_UserPrompt\\t\\t\\t= 702, // data is process\\r\\n 901 | \\tVREvent_QuitAcknowledged\\t\\t\\t\\t= 703, // data is process\\r\\n 902 | \\tVREvent_DriverRequestedQuit\\t\\t\\t\\t= 704, // The driver has requested that SteamVR shut down\\r\\n 903 | \\tVREvent_RestartRequested\\t\\t\\t\\t= 705, // A driver or other component wants the user to restart SteamVR\\r\\n 904 | \\tVREvent_InvalidateSwapTextureSets\\t\\t= 706,\\r\\n 905 | \\r\\n 906 | \\tVREvent_ChaperoneDataHasChanged\\t\\t\\t= 800, // this will never happen with the new chaperone system\\r\\n 907 | \\tVREvent_ChaperoneUniverseHasChanged\\t\\t= 801,\\r\\n 908 | \\tVREvent_ChaperoneTempDataHasChanged\\t\\t= 802, // this will never happen with the new chaperone system\\r\\n 909 | \\tVREvent_ChaperoneSettingsHaveChanged\\t= 803,\\r\\n 910 | \\tVREvent_SeatedZeroPoseReset\\t\\t\\t\\t= 804,\\r\\n 911 | \\tVREvent_ChaperoneFlushCache\\t\\t\\t\\t= 805, // Sent when the process needs to reload any cached data it retrieved from VRChaperone()\\r\\n 912 | \\tVREvent_ChaperoneRoomSetupStarting\\t    = 806, // Triggered by CVRChaperoneClient::RoomSetupStarting\\r\\n 913 | \\tVREvent_ChaperoneRoomSetupFinished\\t    = 807, // Triggered by CVRChaperoneClient::CommitWorkingCopy\\r\\n 914 | \\tVREvent_StandingZeroPoseReset\\t\\t\\t= 808,\\r\\n 915 | \\r\\n 916 | \\tVREvent_AudioSettingsHaveChanged\\t\\t= 820,\\r\\n 917 | \\r\\n 918 | \\tVREvent_BackgroundSettingHasChanged\\t\\t\\t\\t= 850,\\r\\n 919 | \\tVREvent_CameraSettingsHaveChanged\\t\\t\\t\\t= 851,\\r\\n 920 | \\tVREvent_ReprojectionSettingHasChanged\\t\\t\\t= 852,\\r\\n 921 | \\tVREvent_ModelSkinSettingsHaveChanged\\t\\t\\t= 853,\\r\\n 922 | \\tVREvent_EnvironmentSettingsHaveChanged\\t\\t\\t= 854,\\r\\n 923 | \\tVREvent_PowerSettingsHaveChanged\\t\\t\\t\\t= 855,\\r\\n 924 | \\tVREvent_EnableHomeAppSettingsHaveChanged\\t\\t= 856,\\r\\n 925 | \\tVREvent_SteamVRSectionSettingChanged\\t\\t\\t= 857,\\r\\n 926 | \\tVREvent_LighthouseSectionSettingChanged\\t\\t\\t= 858,\\r\\n 927 | \\tVREvent_NullSectionSettingChanged\\t\\t\\t\\t= 859,\\r\\n 928 | \\tVREvent_UserInterfaceSectionSettingChanged\\t\\t= 860,\\r\\n 929 | \\tVREvent_NotificationsSectionSettingChanged\\t\\t= 861,\\r\\n 930 | \\tVREvent_KeyboardSectionSettingChanged\\t\\t\\t= 862,\\r\\n 931 | \\tVREvent_PerfSectionSettingChanged\\t\\t\\t\\t= 863,\\r\\n 932 | \\tVREvent_DashboardSectionSettingChanged\\t\\t\\t= 864,\\r\\n 933 | \\tVREvent_WebInterfaceSectionSettingChanged\\t\\t= 865,\\r\\n 934 | \\tVREvent_TrackersSectionSettingChanged\\t\\t\\t= 866,\\r\\n 935 | \\tVREvent_LastKnownSectionSettingChanged\\t\\t\\t= 867,\\r\\n 936 | \\tVREvent_DismissedWarningsSectionSettingChanged\\t= 868,\\r\\n 937 | \\tVREvent_GpuSpeedSectionSettingChanged\\t\\t\\t= 869,\\r\\n 938 | \\tVREvent_WindowsMRSectionSettingChanged\\t\\t\\t= 870,\\r\\n 939 | \\tVREvent_OtherSectionSettingChanged\\t\\t\\t\\t= 871,\\r\\n 940 | \\tVREvent_AnyDriverSettingsChanged\\t\\t\\t\\t= 872,\\r\\n 941 | \\r\\n 942 | \\tVREvent_StatusUpdate\\t\\t\\t\\t\\t= 900,\\r\\n 943 | \\r\\n 944 | \\tVREvent_WebInterface_InstallDriverCompleted = 950,\\r\\n 945 | \\r\\n 946 | \\tVREvent_MCImageUpdated\\t\\t\\t\\t\\t= 1000,\\r\\n 947 | \\r\\n 948 | \\tVREvent_FirmwareUpdateStarted\\t\\t\\t= 1100,\\r\\n 949 | \\tVREvent_FirmwareUpdateFinished\\t\\t\\t= 1101,\\r\\n 950 | \\r\\n 951 | \\tVREvent_KeyboardClosed\\t\\t\\t\\t\\t= 1200, // DEPRECATED: Sent only to the overlay it closed for, or globally if it was closed for a scene app\\r\\n 952 | \\tVREvent_KeyboardCharInput\\t\\t\\t\\t= 1201,\\r\\n 953 | \\tVREvent_KeyboardDone\\t\\t\\t\\t\\t= 1202, // Sent when DONE button clicked on keyboard\\r\\n 954 | \\tVREvent_KeyboardOpened_Global\\t\\t\\t= 1203, // Sent globally when the keyboard is opened. data.keyboard.overlayHandle is who it was opened for (scene app if k_ulOverlayHandleInvalid)\\r\\n 955 | \\tVREvent_KeyboardClosed_Global\\t\\t\\t= 1204, // Sent globally when the keyboard is closed. data.keyboard.overlayHandle is who it was opened for (scene app if k_ulOverlayHandleInvalid)\\r\\n 956 | \\r\\n 957 | \\t//VREvent_ApplicationTransitionStarted\\t\\t= 1300,\\r\\n 958 | \\t//VREvent_ApplicationTransitionAborted\\t\\t= 1301,\\r\\n 959 | \\t//VREvent_ApplicationTransitionNewAppStarted\\t= 1302,\\r\\n 960 | \\tVREvent_ApplicationListUpdated\\t\\t\\t\\t= 1303,\\r\\n 961 | \\tVREvent_ApplicationMimeTypeLoad\\t\\t\\t\\t= 1304,\\r\\n 962 | \\t// VREvent_ApplicationTransitionNewAppLaunchComplete = 1305,\\r\\n 963 | \\tVREvent_ProcessConnected\\t\\t\\t\\t\\t= 1306,\\r\\n 964 | \\tVREvent_ProcessDisconnected\\t\\t\\t\\t\\t= 1307,\\r\\n 965 | \\r\\n 966 | \\t//VREvent_Compositor_MirrorWindowShown\\t\\t= 1400, // DEPRECATED\\r\\n 967 | \\t//VREvent_Compositor_MirrorWindowHidden\\t\\t= 1401, // DEPRECATED\\r\\n 968 | \\tVREvent_Compositor_ChaperoneBoundsShown\\t\\t= 1410,\\r\\n 969 | \\tVREvent_Compositor_ChaperoneBoundsHidden\\t= 1411,\\r\\n 970 | \\tVREvent_Compositor_DisplayDisconnected\\t\\t= 1412,\\r\\n 971 | \\tVREvent_Compositor_DisplayReconnected\\t\\t= 1413,\\r\\n 972 | \\tVREvent_Compositor_HDCPError\\t\\t\\t\\t= 1414, // data is hdcpError\\r\\n 973 | \\tVREvent_Compositor_ApplicationNotResponding\\t= 1415,\\r\\n 974 | \\tVREvent_Compositor_ApplicationResumed\\t\\t= 1416,\\r\\n 975 | \\tVREvent_Compositor_OutOfVideoMemory\\t\\t\\t= 1417,\\r\\n 976 | \\tVREvent_Compositor_DisplayModeNotSupported\\t= 1418, // k_pch_SteamVR_PreferredRefreshRate\\r\\n 977 | \\tVREvent_Compositor_StageOverrideReady\\t\\t= 1419,\\r\\n 978 | \\tVREvent_Compositor_RequestDisconnectReconnect = 1420,\\r\\n 979 | \\r\\n 980 | \\tVREvent_TrackedCamera_StartVideoStream  = 1500,\\r\\n 981 | \\tVREvent_TrackedCamera_StopVideoStream   = 1501,\\r\\n 982 | \\tVREvent_TrackedCamera_PauseVideoStream  = 1502,\\r\\n 983 | \\tVREvent_TrackedCamera_ResumeVideoStream = 1503,\\r\\n 984 | \\tVREvent_TrackedCamera_EditingSurface    = 1550,\\r\\n 985 | \\r\\n 986 | \\tVREvent_PerformanceTest_EnableCapture\\t= 1600,\\r\\n 987 | \\tVREvent_PerformanceTest_DisableCapture\\t= 1601,\\r\\n 988 | \\tVREvent_PerformanceTest_FidelityLevel\\t= 1602,\\r\\n 989 | \\r\\n 990 | \\tVREvent_MessageOverlay_Closed\\t\\t\\t= 1650,\\r\\n 991 | \\tVREvent_MessageOverlayCloseRequested\\t= 1651,\\r\\n 992 | \\r\\n 993 | \\tVREvent_Input_HapticVibration\\t\\t\\t= 1700, // data is hapticVibration\\r\\n 994 | \\tVREvent_Input_BindingLoadFailed\\t\\t\\t= 1701, // data is inputBinding\\r\\n 995 | \\tVREvent_Input_BindingLoadSuccessful\\t\\t= 1702, // data is inputBinding\\r\\n 996 | \\tVREvent_Input_ActionManifestReloaded\\t= 1703, // no data\\r\\n 997 | \\tVREvent_Input_ActionManifestLoadFailed\\t= 1704, // data is actionManifest\\r\\n 998 | \\tVREvent_Input_ProgressUpdate\\t\\t\\t= 1705, // data is progressUpdate\\r\\n 999 | \\tVREvent_Input_TrackerActivated\\t\\t\\t= 1706,\\r\\n1000 | \\tVREvent_Input_BindingsUpdated\\t\\t\\t= 1707,\\r\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\ndocs\\\\Driver_API_Documentation.md\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:16:45 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n23,413 (12%)\\n\\n# Current Cost\\n$0.10\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":348,\"cacheWrites\":12478,\"cacheReads\":23251,\"cost\":0.0589998}"},{"ts":1744499812573,"type":"say","say":"text","text":"I'm continuing to analyze the OpenVR driver interface. I've found some interesting information about IMU data in the header file. Specifically, I noticed properties related to IMU data:\n\n1. `Prop_ImuToHeadTransform_Matrix34` (line 501)\n2. `Prop_ImuFactoryGyroBias_Vector3` (line 502)\n3. `Prop_ImuFactoryGyroScale_Vector3` (line 503)\n4. `Prop_ImuFactoryAccelerometerBias_Vector3` (line 504)\n5. `Prop_ImuFactoryAccelerometerScale_Vector3` (line 505)\n\nAlso, I noticed a struct `ImuSample_t` mentioned in the code definition names (line 2144). This is likely the structure used to represent IMU data samples.\n\nLet me continue reading the header file to find more information about the driver interface and how IMU data is handled, particularly focusing on the parts related to the driver implementation.\n\nI've found some interesting information about IMU data in the OpenVR driver interface. Let me continue reading more of the header file to understand the driver architecture better, particularly focusing on the driver implementation and IMU data handling:","partial":false},{"ts":1744499817851,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"headers/openvr_driver.h\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\headers\\\\openvr_driver.h\",\"reason\":\" (lines 2000-2500)\"}","partial":false},{"ts":1744499907313,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'headers/openvr_driver.h'] Result:\\n\\n<file><path>headers/openvr_driver.h</path>\\n<content lines=\\\"2000-2500\\\">\\n2000 | struct CameraVideoStreamFrameHeader_t\\r\\n2001 | {\\r\\n2002 | \\tEVRTrackedCameraFrameType eFrameType;\\r\\n2003 | \\r\\n2004 | \\tuint32_t nWidth;\\r\\n2005 | \\tuint32_t nHeight;\\r\\n2006 | \\tuint32_t nBytesPerPixel;\\r\\n2007 | \\r\\n2008 | \\tuint32_t nFrameSequence;\\r\\n2009 | \\r\\n2010 | \\tTrackedDevicePose_t trackedDevicePose;\\r\\n2011 | \\r\\n2012 | \\tuint64_t ulFrameExposureTime;\\t\\t\\t\\t\\t\\t// mid-point of the exposure of the image in host system ticks\\r\\n2013 | };\\r\\n2014 | \\r\\n2015 | // Screenshot types\\r\\n2016 | typedef uint32_t ScreenshotHandle_t;\\r\\n2017 | \\r\\n2018 | static const uint32_t k_unScreenshotHandleInvalid = 0;\\r\\n2019 | \\r\\n2020 | /** Compositor frame timing reprojection flags. */\\r\\n2021 | const uint32_t VRCompositor_ReprojectionReason_Cpu = 0x01;\\r\\n2022 | const uint32_t VRCompositor_ReprojectionReason_Gpu = 0x02;\\r\\n2023 | const uint32_t VRCompositor_ReprojectionAsync = 0x04;\\t\\t// This flag indicates the async reprojection mode is active,\\r\\n2024 | \\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t// but does not indicate if reprojection actually happened or not.\\r\\n2025 | \\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t// Use the ReprojectionReason flags above to check if reprojection\\r\\n2026 | \\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t// was actually applied (i.e. scene texture was reused).\\r\\n2027 | \\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t// NumFramePresents > 1 also indicates the scene texture was reused,\\r\\n2028 | \\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t// and also the number of times that it was presented in total.\\r\\n2029 | \\r\\n2030 | const uint32_t VRCompositor_ReprojectionMotion = 0x08;\\t\\t// This flag indicates whether or not motion smoothing was triggered for this frame\\r\\n2031 | \\r\\n2032 | const uint32_t VRCompositor_PredictionMask = 0xF0;\\t\\t\\t// The runtime may predict more than one frame ahead if\\r\\n2033 | \\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t// it detects the application is taking too long to render. These\\r\\n2034 | \\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t// bits will contain the count of additional frames (normally zero).\\r\\n2035 | \\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t// Use the VR_COMPOSITOR_ADDITIONAL_PREDICTED_FRAMES macro to read from\\r\\n2036 | \\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t// the latest frame timing entry.\\r\\n2037 | \\r\\n2038 | const uint32_t VRCompositor_ThrottleMask = 0xF00;\\t\\t\\t// Number of frames the compositor is throttling the application.\\r\\n2039 | \\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t// Use the VR_COMPOSITOR_NUMBER_OF_THROTTLED_FRAMES macro to read from\\r\\n2040 | \\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t// the latest frame timing entry.\\r\\n2041 | \\r\\n2042 | #define VR_COMPOSITOR_ADDITIONAL_PREDICTED_FRAMES( timing ) ( ( ( timing ).m_nReprojectionFlags & vr::VRCompositor_PredictionMask ) >> 4 )\\r\\n2043 | #define VR_COMPOSITOR_NUMBER_OF_THROTTLED_FRAMES( timing ) ( ( ( timing ).m_nReprojectionFlags & vr::VRCompositor_ThrottleMask ) >> 8 )\\r\\n2044 | \\r\\n2045 | #if defined(__linux__) || defined(__APPLE__)\\r\\n2046 | #pragma pack( push, 4 )\\r\\n2047 | #endif\\r\\n2048 | /** Provides a single frame's timing information to the app */\\r\\n2049 | struct Compositor_FrameTiming\\r\\n2050 | {\\r\\n2051 | \\tuint32_t m_nSize; // Set to sizeof( Compositor_FrameTiming )\\r\\n2052 | \\tuint32_t m_nFrameIndex;\\r\\n2053 | \\tuint32_t m_nNumFramePresents; // number of times this frame was presented\\r\\n2054 | \\tuint32_t m_nNumMisPresented; // number of times this frame was presented on a vsync other than it was originally predicted to\\r\\n2055 | \\tuint32_t m_nNumDroppedFrames; // number of additional times previous frame was scanned out\\r\\n2056 | \\tuint32_t m_nReprojectionFlags;\\r\\n2057 | \\r\\n2058 | \\t/** Absolute time reference for comparing frames.  This aligns with the vsync that running start is relative to. */\\r\\n2059 | \\tdouble m_flSystemTimeInSeconds;\\r\\n2060 | \\r\\n2061 | \\t/** These times may include work from other processes due to OS scheduling.\\r\\n2062 | \\t* The fewer packets of work these are broken up into, the less likely this will happen.\\r\\n2063 | \\t* GPU work can be broken up by calling Flush.  This can sometimes be useful to get the GPU started\\r\\n2064 | \\t* processing that work earlier in the frame. */\\r\\n2065 | \\tfloat m_flPreSubmitGpuMs; // time spent rendering the scene (gpu work submitted between WaitGetPoses and second Submit)\\r\\n2066 | \\tfloat m_flPostSubmitGpuMs; // additional time spent rendering by application (e.g. companion window)\\r\\n2067 | \\tfloat m_flTotalRenderGpuMs; // time between work submitted immediately after present (ideally vsync) until the end of compositor submitted work\\r\\n2068 | \\tfloat m_flCompositorRenderGpuMs; // time spend performing distortion correction, rendering chaperone, overlays, etc.\\r\\n2069 | \\tfloat m_flCompositorRenderCpuMs; // time spent on cpu submitting the above work for this frame\\r\\n2070 | \\tfloat m_flCompositorIdleCpuMs; // time spent waiting for running start (application could have used this much more time)\\r\\n2071 | \\r\\n2072 | \\t/** Miscellaneous measured intervals. */\\r\\n2073 | \\tfloat m_flClientFrameIntervalMs; // time between calls to WaitGetPoses\\r\\n2074 | \\tfloat m_flPresentCallCpuMs; // time blocked on call to present (usually 0.0, but can go long)\\r\\n2075 | \\tfloat m_flWaitForPresentCpuMs; // time spent spin-waiting for frame index to change (not near-zero indicates wait object failure)\\r\\n2076 | \\tfloat m_flSubmitFrameMs; // time spent in IVRCompositor::Submit (not near-zero indicates driver issue)\\r\\n2077 | \\r\\n2078 | \\t/** The following are all relative to this frame's SystemTimeInSeconds */\\r\\n2079 | \\tfloat m_flWaitGetPosesCalledMs;\\r\\n2080 | \\tfloat m_flNewPosesReadyMs;\\r\\n2081 | \\tfloat m_flNewFrameReadyMs; // second call to IVRCompositor::Submit\\r\\n2082 | \\tfloat m_flCompositorUpdateStartMs;\\r\\n2083 | \\tfloat m_flCompositorUpdateEndMs;\\r\\n2084 | \\tfloat m_flCompositorRenderStartMs;\\r\\n2085 | \\r\\n2086 | \\tvr::TrackedDevicePose_t m_HmdPose; // pose used by app to render this frame\\r\\n2087 | \\r\\n2088 | \\tuint32_t m_nNumVSyncsReadyForUse;\\r\\n2089 | \\tuint32_t m_nNumVSyncsToFirstView;\\r\\n2090 | \\r\\n2091 | \\tfloat m_flTransferLatencyMs;\\r\\n2092 | };\\r\\n2093 | #if defined(__linux__) || defined(__APPLE__)\\r\\n2094 | #pragma pack( pop )\\r\\n2095 | #endif\\r\\n2096 | \\r\\n2097 | /** Provides compositor benchmark results to the app */\\r\\n2098 | struct Compositor_BenchmarkResults\\r\\n2099 | {\\r\\n2100 | \\tfloat m_flMegaPixelsPerSecond; // Measurement of GPU MP/s performed by compositor benchmark\\r\\n2101 | \\tfloat m_flHmdRecommendedMegaPixelsPerSecond; // Recommended default MP/s given the HMD resolution, refresh, and panel mask.\\r\\n2102 | };\\r\\n2103 | \\r\\n2104 | /** Frame timing data provided by direct mode drivers. */\\r\\n2105 | struct DriverDirectMode_FrameTiming\\r\\n2106 | {\\r\\n2107 | \\tuint32_t m_nSize; // Set to sizeof( DriverDirectMode_FrameTiming )\\r\\n2108 | \\tuint32_t m_nNumFramePresents; // number of times frame was presented\\r\\n2109 | \\tuint32_t m_nNumMisPresented; // number of times frame was presented on a vsync other than it was originally predicted to\\r\\n2110 | \\tuint32_t m_nNumDroppedFrames; // number of additional times previous frame was scanned out (i.e. compositor missed vsync)\\r\\n2111 | \\tuint32_t m_nReprojectionFlags;\\r\\n2112 | };\\r\\n2113 | \\r\\n2114 | /** These flags will be set on DriverDirectMode_FrameTiming::m_nReprojectionFlags when IVRDriverDirectModeComponent::GetFrameTiming is called for drivers to optionally respond to. */\\r\\n2115 | const uint32_t VRCompositor_ReprojectionMotion_Enabled = 0x100; // Motion Smoothing is enabled in the UI for the currently running application\\r\\n2116 | const uint32_t VRCompositor_ReprojectionMotion_ForcedOn = 0x200; // Motion Smoothing is forced on in the UI for the currently running application\\r\\n2117 | const uint32_t VRCompositor_ReprojectionMotion_AppThrottled = 0x400; // Application is requesting throttling via ForceInterleavedReprojectionOn\\r\\n2118 | \\r\\n2119 | \\r\\n2120 | enum EVSync\\r\\n2121 | {\\r\\n2122 | \\tVSync_None,\\r\\n2123 | \\tVSync_WaitRender,\\t// block following render work until vsync\\r\\n2124 | \\tVSync_NoWaitRender,\\t// do not block following render work (allow to get started early)\\r\\n2125 | };\\r\\n2126 | \\r\\n2127 | enum EVRMuraCorrectionMode\\r\\n2128 | {\\r\\n2129 | \\tEVRMuraCorrectionMode_Default = 0,\\r\\n2130 | \\tEVRMuraCorrectionMode_NoCorrection\\r\\n2131 | };\\r\\n2132 | \\r\\n2133 | /** raw IMU data provided by IVRIOBuffer from paths to tracked devices with IMUs */\\r\\n2134 | enum Imu_OffScaleFlags\\r\\n2135 | {\\r\\n2136 | \\tOffScale_AccelX\\t= 0x01,\\r\\n2137 | \\tOffScale_AccelY\\t= 0x02,\\r\\n2138 | \\tOffScale_AccelZ\\t= 0x04,\\r\\n2139 | \\tOffScale_GyroX\\t= 0x08,\\r\\n2140 | \\tOffScale_GyroY\\t= 0x10,\\r\\n2141 | \\tOffScale_GyroZ\\t= 0x20,\\r\\n2142 | };\\r\\n2143 | \\r\\n2144 | struct ImuSample_t\\r\\n2145 | {\\r\\n2146 | \\tdouble fSampleTime;\\r\\n2147 | \\tHmdVector3d_t vAccel;\\r\\n2148 | \\tHmdVector3d_t vGyro;\\r\\n2149 | \\tuint32_t unOffScaleFlags;\\r\\n2150 | };\\r\\n2151 | \\r\\n2152 | #pragma pack( pop )\\r\\n2153 | \\r\\n2154 | // figure out how to import from the VR API dll\\r\\n2155 | #if defined(_WIN32)\\r\\n2156 | \\r\\n2157 |   #if !defined(OPENVR_BUILD_STATIC)\\r\\n2158 |     #ifdef VR_API_EXPORT\\r\\n2159 |       #define VR_INTERFACE extern \\\"C\\\" __declspec( dllexport )\\r\\n2160 |     #else\\r\\n2161 |       #define VR_INTERFACE extern \\\"C\\\" __declspec( dllimport )\\r\\n2162 |     #endif\\r\\n2163 |   #else\\r\\n2164 |     #define VR_INTERFACE extern \\\"C\\\"\\r\\n2165 |   #endif\\r\\n2166 | \\r\\n2167 | #elif defined(__GNUC__) || defined(COMPILER_GCC) || defined(__APPLE__)\\r\\n2168 | \\r\\n2169 | #ifdef VR_API_EXPORT\\r\\n2170 |   #define VR_INTERFACE extern \\\"C\\\" __attribute__((visibility(\\\"default\\\")))\\r\\n2171 | #else\\r\\n2172 |   #define VR_INTERFACE extern \\\"C\\\"\\r\\n2173 | #endif\\r\\n2174 | \\r\\n2175 | #else\\r\\n2176 |   #error \\\"Unsupported Platform.\\\"\\r\\n2177 | #endif\\r\\n2178 | \\r\\n2179 | \\r\\n2180 | #if defined( _WIN32 )\\r\\n2181 |   #define VR_CALLTYPE __cdecl\\r\\n2182 | #else\\r\\n2183 |   #define VR_CALLTYPE\\r\\n2184 | #endif\\r\\n2185 | \\r\\n2186 | } // namespace vr\\r\\n2187 | #endif // _INCLUDE_VRTYPES_H\\r\\n2188 | \\r\\n2189 | // vrannotation.h\\r\\n2190 | \\r\\n2191 | #ifdef API_GEN\\r\\n2192 | # define VR_CLANG_ATTR(ATTR) __attribute__((annotate( ATTR )))\\r\\n2193 | #else\\r\\n2194 | # define VR_CLANG_ATTR(ATTR)\\r\\n2195 | #endif\\r\\n2196 | \\r\\n2197 | #define VR_METHOD_DESC(DESC) VR_CLANG_ATTR( \\\"desc:\\\" #DESC \\\";\\\" )\\r\\n2198 | #define VR_IGNOREATTR() VR_CLANG_ATTR( \\\"ignore\\\" )\\r\\n2199 | #define VR_OUT_STRUCT() VR_CLANG_ATTR( \\\"out_struct: ;\\\" )\\r\\n2200 | #define VR_OUT_STRING() VR_CLANG_ATTR( \\\"out_string: ;\\\" )\\r\\n2201 | #define VR_OUT_ARRAY_CALL(COUNTER,FUNCTION,PARAMS) VR_CLANG_ATTR( \\\"out_array_call:\\\" #COUNTER \\\",\\\" #FUNCTION \\\",\\\" #PARAMS \\\";\\\" )\\r\\n2202 | #define VR_OUT_ARRAY_COUNT(COUNTER) VR_CLANG_ATTR( \\\"out_array_count:\\\" #COUNTER \\\";\\\" )\\r\\n2203 | #define VR_ARRAY_COUNT(COUNTER) VR_CLANG_ATTR( \\\"array_count:\\\" #COUNTER \\\";\\\" )\\r\\n2204 | #define VR_ARRAY_COUNT_D(COUNTER, DESC) VR_CLANG_ATTR( \\\"array_count:\\\" #COUNTER \\\";desc:\\\" #DESC )\\r\\n2205 | #define VR_BUFFER_COUNT(COUNTER) VR_CLANG_ATTR( \\\"buffer_count:\\\" #COUNTER \\\";\\\" )\\r\\n2206 | #define VR_OUT_BUFFER_COUNT(COUNTER) VR_CLANG_ATTR( \\\"out_buffer_count:\\\" #COUNTER \\\";\\\" )\\r\\n2207 | #define VR_OUT_STRING_COUNT(COUNTER) VR_CLANG_ATTR( \\\"out_string_count:\\\" #COUNTER \\\";\\\" )\\r\\n2208 | \\r\\n2209 | // vrtrackedcameratypes.h\\r\\n2210 | \\r\\n2211 | #ifndef _VRTRACKEDCAMERATYPES_H\\r\\n2212 | #define _VRTRACKEDCAMERATYPES_H\\r\\n2213 | \\r\\n2214 | namespace vr\\r\\n2215 | {\\r\\n2216 | \\r\\n2217 | #pragma pack( push, 8 )\\r\\n2218 | \\r\\n2219 | enum ECameraVideoStreamFormat\\r\\n2220 | {\\r\\n2221 | \\tCVS_FORMAT_UNKNOWN = 0,\\r\\n2222 | \\tCVS_FORMAT_RAW10 = 1,\\t\\t// 10 bits per pixel\\r\\n2223 | \\tCVS_FORMAT_NV12 = 2,\\t\\t// 12 bits per pixel\\r\\n2224 | \\tCVS_FORMAT_RGB24 = 3,\\t\\t// 24 bits per pixel\\r\\n2225 | \\tCVS_FORMAT_NV12_2 = 4,\\t\\t// 12 bits per pixel, 2x height\\r\\n2226 | \\tCVS_FORMAT_YUYV16 = 5,\\t\\t// 16 bits per pixel\\r\\n2227 | \\tCVS_FORMAT_BAYER16BG = 6,   // 16 bits per pixel, 10-bit BG-format Bayer, see https://docs.opencv.org/3.1.0/de/d25/imgproc_color_conversions.html\\r\\n2228 | \\tCVS_FORMAT_MJPEG = 7,       // variable-sized MJPEG Open DML format, see https://www.loc.gov/preservation/digital/formats/fdd/fdd000063.shtml\\r\\n2229 | \\tCVS_FORMAT_RGBX32 = 8,      // Full-sized pixels, 4BPP, LSB = RED\\r\\n2230 | \\tCVS_MAX_FORMATS\\r\\n2231 | };\\r\\n2232 | \\r\\n2233 | enum ECameraCompatibilityMode\\r\\n2234 | {\\r\\n2235 | \\tCAMERA_COMPAT_MODE_BULK_DEFAULT = 0,\\r\\n2236 | \\tCAMERA_COMPAT_MODE_BULK_64K_DMA = 1,\\r\\n2237 | \\tCAMERA_COMPAT_MODE_BULK_16K_DMA = 2,\\r\\n2238 | \\tCAMERA_COMPAT_MODE_BULK_8K_DMA = 3,\\r\\n2239 | \\tCAMERA_COMPAT_MODE_ISO_52FPS = 4,\\r\\n2240 | \\tCAMERA_COMPAT_MODE_ISO_50FPS = 5,\\r\\n2241 | \\tCAMERA_COMPAT_MODE_ISO_48FPS = 6,\\r\\n2242 | \\tCAMERA_COMPAT_MODE_ISO_46FPS = 7,\\r\\n2243 | \\tCAMERA_COMPAT_MODE_ISO_44FPS = 8,\\r\\n2244 | \\tCAMERA_COMPAT_MODE_ISO_42FPS = 9,\\r\\n2245 | \\tCAMERA_COMPAT_MODE_ISO_40FPS = 10,\\r\\n2246 | \\tCAMERA_COMPAT_MODE_ISO_35FPS = 11,\\r\\n2247 | \\tCAMERA_COMPAT_MODE_ISO_30FPS = 12,\\r\\n2248 | \\tCAMERA_COMPAT_MODE_ISO_15FPS = 13,\\r\\n2249 | \\tMAX_CAMERA_COMPAT_MODES\\r\\n2250 | };\\r\\n2251 | \\r\\n2252 | enum ECameraRoomViewStyle\\r\\n2253 | {\\r\\n2254 | \\tCAMERA_ROOMVIEW_STYLE_DEFAULT = 0,\\r\\n2255 | \\tCAMERA_ROOMVIEW_STYLE_EDGE_A = 1,\\r\\n2256 | \\tCAMERA_ROOMVIEW_STYLE_EDGE_B = 2,\\r\\n2257 | \\tCAMERA_ROOMVIEW_STYLE_VIDEO_TRANSLUSCENT = 3,\\r\\n2258 | \\tCAMERA_ROOMVIEW_STYLE_VIDEO_OPAQUE = 4,\\r\\n2259 | \\tCAMERA_ROOMVIEW_STYLE_COUNT = 5,\\r\\n2260 | };\\r\\n2261 | \\r\\n2262 | #ifdef _MSC_VER\\r\\n2263 | #define VR_CAMERA_DECL_ALIGN( x ) __declspec( align( x ) )\\r\\n2264 | #else\\r\\n2265 | #define VR_CAMERA_DECL_ALIGN( x ) //\\r\\n2266 | #endif\\r\\n2267 | \\r\\n2268 | static const uint32_t k_unMaxCameras = 4;\\r\\n2269 | static const uint32_t k_unMaxCameraFrameSharedHandles = 4;\\r\\n2270 | \\r\\n2271 | VR_CAMERA_DECL_ALIGN( 8 ) struct CameraVideoStreamFrame_t\\r\\n2272 | {\\r\\n2273 | \\tECameraVideoStreamFormat m_nStreamFormat;\\r\\n2274 | \\r\\n2275 | \\tuint32_t m_nWidth;\\r\\n2276 | \\tuint32_t m_nHeight;\\r\\n2277 | \\r\\n2278 | \\tuint32_t m_nImageDataSize;\\t\\t\\t\\t\\t\\t// Based on stream format, width, height\\r\\n2279 | \\r\\n2280 | \\tuint32_t m_nFrameSequence;\\t\\t\\t\\t\\t\\t// Starts from 0 when stream starts.\\r\\n2281 | \\r\\n2282 | \\tuint32_t m_nBufferIndex;\\t\\t\\t\\t\\t\\t// Identifies which buffer the image data is hosted\\r\\n2283 | \\tuint32_t m_nBufferCount;\\t\\t\\t\\t\\t\\t// Total number of configured buffers\\r\\n2284 | \\r\\n2285 | \\tuint32_t m_nExposureTime;\\r\\n2286 | \\r\\n2287 | \\tuint32_t m_nISPFrameTimeStamp;\\t\\t\\t\\t\\t// Driver provided time stamp per driver centric time base\\r\\n2288 | \\tuint32_t m_nISPReferenceTimeStamp;\\r\\n2289 | \\tuint32_t m_nSyncCounter;\\r\\n2290 | \\r\\n2291 | \\tuint32_t m_nCamSyncEvents;\\r\\n2292 | \\tuint32_t m_nISPSyncEvents;\\r\\n2293 | \\r\\n2294 | \\tdouble m_flReferenceCamSyncTime;\\r\\n2295 | \\r\\n2296 | \\tdouble m_flFrameElapsedTime;\\t\\t\\t\\t\\t// Starts from 0 when stream starts. In seconds.\\r\\n2297 | \\tdouble m_flFrameDeliveryRate;\\r\\n2298 | \\r\\n2299 | \\tdouble m_flFrameCaptureTime_DriverAbsolute;\\t\\t// In USB time, via AuxEvent\\r\\n2300 | \\tdouble m_flFrameCaptureTime_ServerRelative;\\t\\t// In System time within the server\\r\\n2301 | \\tuint64_t m_nFrameCaptureTicks_ServerAbsolute;\\t// In system ticks within the server\\r\\n2302 | \\tdouble m_flFrameCaptureTime_ClientRelative;\\t\\t// At the client, relative to when the frame was exposed/captured.\\r\\n2303 | \\r\\n2304 | \\tdouble m_flSyncMarkerError;\\r\\n2305 | \\r\\n2306 | \\tTrackedDevicePose_t m_RawTrackedDevicePose;\\t// Raw-and-uncalibrated pose, supplied by HMD layer when used as a tracked camera\\r\\n2307 | \\r\\n2308 | \\tuint64_t m_pImageData;\\r\\n2309 | };\\r\\n2310 | \\r\\n2311 | #pragma pack( pop )\\r\\n2312 | \\r\\n2313 | }\\r\\n2314 | \\r\\n2315 | #endif // _VRTRACKEDCAMERATYPES_H\\r\\n2316 | \\r\\n2317 | // ivrsettings.h\\r\\n2318 | \\r\\n2319 | #include <string>\\r\\n2320 | \\r\\n2321 | namespace vr\\r\\n2322 | {\\r\\n2323 | \\tenum EVRSettingsError\\r\\n2324 | \\t{\\r\\n2325 | \\t\\tVRSettingsError_None = 0,\\r\\n2326 | \\t\\tVRSettingsError_IPCFailed = 1,\\r\\n2327 | \\t\\tVRSettingsError_WriteFailed = 2,\\r\\n2328 | \\t\\tVRSettingsError_ReadFailed = 3,\\r\\n2329 | \\t\\tVRSettingsError_JsonParseFailed = 4,\\r\\n2330 | \\t\\tVRSettingsError_UnsetSettingHasNoDefault = 5, // This will be returned if the setting does not appear in the appropriate default file and has not been set\\r\\n2331 | \\t\\tVRSettingsError_AccessDenied = 6,\\r\\n2332 | \\t};\\r\\n2333 | \\r\\n2334 | \\t// The maximum length of a settings key\\r\\n2335 | \\tstatic const uint32_t k_unMaxSettingsKeyLength = 128;\\r\\n2336 | \\r\\n2337 | \\tclass IVRSettings\\r\\n2338 | \\t{\\r\\n2339 | \\tpublic:\\r\\n2340 | \\t\\tvirtual const char *GetSettingsErrorNameFromEnum( EVRSettingsError eError ) = 0;\\r\\n2341 | \\r\\n2342 | \\t\\tvirtual void SetBool( const char *pchSection, const char *pchSettingsKey, bool bValue, EVRSettingsError *peError = nullptr ) = 0;\\r\\n2343 | \\t\\tvirtual void SetInt32( const char *pchSection, const char *pchSettingsKey, int32_t nValue, EVRSettingsError *peError = nullptr ) = 0;\\r\\n2344 | \\t\\tvirtual void SetFloat( const char *pchSection, const char *pchSettingsKey, float flValue, EVRSettingsError *peError = nullptr ) = 0;\\r\\n2345 | \\t\\tvirtual void SetString( const char *pchSection, const char *pchSettingsKey, const char *pchValue, EVRSettingsError *peError = nullptr ) = 0;\\r\\n2346 | \\r\\n2347 | \\t\\t// Users of the system need to provide a proper default in default.vrsettings in the resources/settings/ directory\\r\\n2348 | \\t\\t// of either the runtime or the driver_xxx directory. Otherwise the default will be false, 0, 0.0 or \\\"\\\"\\r\\n2349 | \\t\\tvirtual bool GetBool( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0;\\r\\n2350 | \\t\\tvirtual int32_t GetInt32( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0;\\r\\n2351 | \\t\\tvirtual float GetFloat( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0;\\r\\n2352 | \\t\\tvirtual void GetString( const char *pchSection, const char *pchSettingsKey, VR_OUT_STRING() char *pchValue, uint32_t unValueLen, EVRSettingsError *peError = nullptr ) = 0;\\r\\n2353 | \\r\\n2354 | \\t\\tvirtual void RemoveSection( const char *pchSection, EVRSettingsError *peError = nullptr ) = 0;\\r\\n2355 | \\t\\tvirtual void RemoveKeyInSection( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr ) = 0;\\r\\n2356 | \\t};\\r\\n2357 | \\r\\n2358 | \\t//-----------------------------------------------------------------------------\\r\\n2359 | \\tstatic const char * const IVRSettings_Version = \\\"IVRSettings_003\\\";\\r\\n2360 | \\r\\n2361 | \\tclass CVRSettingHelper\\r\\n2362 | \\t{\\r\\n2363 | \\t\\tIVRSettings *m_pSettings;\\r\\n2364 | \\tpublic:\\r\\n2365 | \\t\\tCVRSettingHelper( IVRSettings *pSettings )\\r\\n2366 | \\t\\t{\\r\\n2367 | \\t\\t\\tm_pSettings = pSettings;\\r\\n2368 | \\t\\t}\\r\\n2369 | \\r\\n2370 | \\t\\tconst char *GetSettingsErrorNameFromEnum( EVRSettingsError eError )\\r\\n2371 | \\t\\t{\\r\\n2372 | \\t\\t\\treturn m_pSettings->GetSettingsErrorNameFromEnum( eError );\\r\\n2373 | \\t\\t}\\r\\n2374 | \\r\\n2375 | \\t\\tvoid SetBool( const char *pchSection, const char *pchSettingsKey, bool bValue, EVRSettingsError *peError = nullptr )\\r\\n2376 | \\t\\t{\\r\\n2377 | \\t\\t\\tm_pSettings->SetBool( pchSection, pchSettingsKey, bValue, peError );\\r\\n2378 | \\t\\t}\\r\\n2379 | \\r\\n2380 | \\t\\tvoid SetInt32( const char *pchSection, const char *pchSettingsKey, int32_t nValue, EVRSettingsError *peError = nullptr )\\r\\n2381 | \\t\\t{\\r\\n2382 | \\t\\t\\tm_pSettings->SetInt32( pchSection, pchSettingsKey, nValue, peError );\\r\\n2383 | \\t\\t}\\r\\n2384 | \\t\\tvoid SetFloat( const char *pchSection, const char *pchSettingsKey, float flValue, EVRSettingsError *peError = nullptr )\\r\\n2385 | \\t\\t{\\r\\n2386 | \\t\\t\\tm_pSettings->SetFloat( pchSection, pchSettingsKey, flValue, peError );\\r\\n2387 | \\t\\t}\\r\\n2388 | \\t\\tvoid SetString( const char *pchSection, const char *pchSettingsKey, const char *pchValue, EVRSettingsError *peError = nullptr )\\r\\n2389 | \\t\\t{\\r\\n2390 | \\t\\t\\tm_pSettings->SetString( pchSection, pchSettingsKey, pchValue, peError );\\r\\n2391 | \\t\\t}\\r\\n2392 | \\t\\tvoid SetString( const std::string & sSection, const std::string &  sSettingsKey, const std::string & sValue, EVRSettingsError *peError = nullptr )\\r\\n2393 | \\t\\t{\\r\\n2394 | \\t\\t\\tm_pSettings->SetString( sSection.c_str(), sSettingsKey.c_str(), sValue.c_str(), peError );\\r\\n2395 | \\t\\t}\\r\\n2396 | \\r\\n2397 | \\t\\tbool GetBool( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr )\\r\\n2398 | \\t\\t{\\r\\n2399 | \\t\\t\\treturn m_pSettings->GetBool( pchSection, pchSettingsKey, peError );\\r\\n2400 | \\t\\t}\\r\\n2401 | \\t\\tint32_t GetInt32( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr )\\r\\n2402 | \\t\\t{\\r\\n2403 | \\t\\t\\treturn m_pSettings->GetInt32( pchSection, pchSettingsKey, peError );\\r\\n2404 | \\t\\t}\\r\\n2405 | \\t\\tfloat GetFloat( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr )\\r\\n2406 | \\t\\t{\\r\\n2407 | \\t\\t\\treturn m_pSettings->GetFloat( pchSection, pchSettingsKey, peError );\\r\\n2408 | \\t\\t}\\r\\n2409 | \\t\\tvoid GetString( const char *pchSection, const char *pchSettingsKey, VR_OUT_STRING() char *pchValue, uint32_t unValueLen, EVRSettingsError *peError = nullptr )\\r\\n2410 | \\t\\t{\\r\\n2411 | \\t\\t\\tm_pSettings->GetString( pchSection, pchSettingsKey, pchValue, unValueLen, peError );\\r\\n2412 | \\t\\t}\\r\\n2413 | \\t\\tstd::string GetString( const std::string & sSection, const std::string & sSettingsKey, EVRSettingsError *peError = nullptr )\\r\\n2414 | \\t\\t{\\r\\n2415 | \\t\\t\\tchar buf[4096];\\r\\n2416 | \\t\\t\\tvr::EVRSettingsError eError;\\r\\n2417 | \\t\\t\\tm_pSettings->GetString( sSection.c_str(), sSettingsKey.c_str(), buf, sizeof( buf ), &eError );\\r\\n2418 | \\t\\t\\tif ( peError )\\r\\n2419 | \\t\\t\\t\\t*peError = eError;\\r\\n2420 | \\t\\t\\tif ( eError == vr::VRSettingsError_None )\\r\\n2421 | \\t\\t\\t\\treturn buf;\\r\\n2422 | \\t\\t\\telse\\r\\n2423 | \\t\\t\\t\\treturn \\\"\\\";\\r\\n2424 | \\t\\t}\\r\\n2425 | \\r\\n2426 | \\t\\tvoid RemoveSection( const char *pchSection, EVRSettingsError *peError = nullptr )\\r\\n2427 | \\t\\t{\\r\\n2428 | \\t\\t\\tm_pSettings->RemoveSection( pchSection, peError );\\r\\n2429 | \\t\\t}\\r\\n2430 | \\t\\tvoid RemoveKeyInSection( const char *pchSection, const char *pchSettingsKey, EVRSettingsError *peError = nullptr )\\r\\n2431 | \\t\\t{\\r\\n2432 | \\t\\t\\tm_pSettings->RemoveKeyInSection( pchSection, pchSettingsKey, peError );\\r\\n2433 | \\t\\t}\\r\\n2434 | \\t};\\r\\n2435 | \\r\\n2436 | \\r\\n2437 | \\t//-----------------------------------------------------------------------------\\r\\n2438 | \\t// steamvr keys\\r\\n2439 | \\tstatic const char * const k_pch_SteamVR_Section = \\\"steamvr\\\";\\r\\n2440 | \\tstatic const char * const k_pch_SteamVR_RequireHmd_String = \\\"requireHmd\\\";\\r\\n2441 | \\tstatic const char * const k_pch_SteamVR_ForcedDriverKey_String = \\\"forcedDriver\\\";\\r\\n2442 | \\tstatic const char * const k_pch_SteamVR_ForcedHmdKey_String = \\\"forcedHmd\\\";\\r\\n2443 | \\tstatic const char * const k_pch_SteamVR_DisplayDebug_Bool = \\\"displayDebug\\\";\\r\\n2444 | \\tstatic const char * const k_pch_SteamVR_DebugProcessPipe_String = \\\"debugProcessPipe\\\";\\r\\n2445 | \\tstatic const char * const k_pch_SteamVR_DisplayDebugX_Int32 = \\\"displayDebugX\\\";\\r\\n2446 | \\tstatic const char * const k_pch_SteamVR_DisplayDebugY_Int32 = \\\"displayDebugY\\\";\\r\\n2447 | \\tstatic const char * const k_pch_SteamVR_SendSystemButtonToAllApps_Bool= \\\"sendSystemButtonToAllApps\\\";\\r\\n2448 | \\tstatic const char * const k_pch_SteamVR_LogLevel_Int32 = \\\"loglevel\\\";\\r\\n2449 | \\tstatic const char * const k_pch_SteamVR_IPD_Float = \\\"ipd\\\";\\r\\n2450 | \\tstatic const char * const k_pch_SteamVR_Background_String = \\\"background\\\";\\r\\n2451 | \\tstatic const char * const k_pch_SteamVR_BackgroundUseDomeProjection_Bool = \\\"backgroundUseDomeProjection\\\";\\r\\n2452 | \\tstatic const char * const k_pch_SteamVR_BackgroundCameraHeight_Float = \\\"backgroundCameraHeight\\\";\\r\\n2453 | \\tstatic const char * const k_pch_SteamVR_BackgroundDomeRadius_Float = \\\"backgroundDomeRadius\\\";\\r\\n2454 | \\tstatic const char * const k_pch_SteamVR_GridColor_String = \\\"gridColor\\\";\\r\\n2455 | \\tstatic const char * const k_pch_SteamVR_PlayAreaColor_String = \\\"playAreaColor\\\";\\r\\n2456 | \\tstatic const char * const k_pch_SteamVR_TrackingLossColor_String = \\\"trackingLossColor\\\";\\r\\n2457 | \\tstatic const char * const k_pch_SteamVR_ShowStage_Bool = \\\"showStage\\\";\\r\\n2458 | \\tstatic const char * const k_pch_SteamVR_DrawTrackingReferences_Bool = \\\"drawTrackingReferences\\\";\\r\\n2459 | \\tstatic const char * const k_pch_SteamVR_ActivateMultipleDrivers_Bool = \\\"activateMultipleDrivers\\\";\\r\\n2460 | \\tstatic const char * const k_pch_SteamVR_UsingSpeakers_Bool = \\\"usingSpeakers\\\";\\r\\n2461 | \\tstatic const char * const k_pch_SteamVR_SpeakersForwardYawOffsetDegrees_Float = \\\"speakersForwardYawOffsetDegrees\\\";\\r\\n2462 | \\tstatic const char * const k_pch_SteamVR_BaseStationPowerManagement_Int32 = \\\"basestationPowerManagement\\\";\\r\\n2463 | \\tstatic const char * const k_pch_SteamVR_ShowBaseStationPowerManagementTip_Int32 = \\\"ShowBaseStationPowerManagementTip\\\";\\r\\n2464 | \\tstatic const char * const k_pch_SteamVR_NeverKillProcesses_Bool = \\\"neverKillProcesses\\\";\\r\\n2465 | \\tstatic const char * const k_pch_SteamVR_SupersampleScale_Float = \\\"supersampleScale\\\";\\r\\n2466 | \\tstatic const char * const k_pch_SteamVR_MaxRecommendedResolution_Int32 = \\\"maxRecommendedResolution\\\";\\r\\n2467 | \\tstatic const char * const k_pch_SteamVR_MotionSmoothing_Bool = \\\"motionSmoothing\\\";\\r\\n2468 | \\tstatic const char * const k_pch_SteamVR_MotionSmoothingOverride_Int32 = \\\"motionSmoothingOverride\\\";\\r\\n2469 | \\tstatic const char * const k_pch_SteamVR_FramesToThrottle_Int32 = \\\"framesToThrottle\\\";\\r\\n2470 | \\tstatic const char * const k_pch_SteamVR_AdditionalFramesToPredict_Int32 = \\\"additionalFramesToPredict\\\";\\r\\n2471 | \\tstatic const char * const k_pch_SteamVR_WorldScale_Float = \\\"worldScale\\\";\\r\\n2472 | \\tstatic const char * const k_pch_SteamVR_FovScale_Int32 = \\\"fovScale\\\";\\r\\n2473 | \\tstatic const char * const k_pch_SteamVR_FovScaleLetterboxed_Bool = \\\"fovScaleLetterboxed\\\";\\r\\n2474 | \\tstatic const char * const k_pch_SteamVR_DisableAsyncReprojection_Bool = \\\"disableAsync\\\";\\r\\n2475 | \\tstatic const char * const k_pch_SteamVR_ForceFadeOnBadTracking_Bool = \\\"forceFadeOnBadTracking\\\";\\r\\n2476 | \\tstatic const char * const k_pch_SteamVR_DefaultMirrorView_Int32 = \\\"mirrorView\\\";\\r\\n2477 | \\tstatic const char * const k_pch_SteamVR_ShowLegacyMirrorView_Bool = \\\"showLegacyMirrorView\\\";\\r\\n2478 | \\tstatic const char * const k_pch_SteamVR_MirrorViewVisibility_Bool = \\\"showMirrorView\\\";\\r\\n2479 | \\tstatic const char * const k_pch_SteamVR_MirrorViewDisplayMode_Int32 = \\\"mirrorViewDisplayMode\\\";\\r\\n2480 | \\tstatic const char * const k_pch_SteamVR_MirrorViewEye_Int32 = \\\"mirrorViewEye\\\";\\r\\n2481 | \\tstatic const char * const k_pch_SteamVR_MirrorViewGeometry_String = \\\"mirrorViewGeometry\\\";\\r\\n2482 | \\tstatic const char * const k_pch_SteamVR_MirrorViewGeometryMaximized_String = \\\"mirrorViewGeometryMaximized\\\";\\r\\n2483 | \\tstatic const char * const k_pch_SteamVR_PerfGraphVisibility_Bool = \\\"showPerfGraph\\\";\\r\\n2484 | \\tstatic const char * const k_pch_SteamVR_StartMonitorFromAppLaunch = \\\"startMonitorFromAppLaunch\\\";\\r\\n2485 | \\tstatic const char * const k_pch_SteamVR_StartCompositorFromAppLaunch_Bool = \\\"startCompositorFromAppLaunch\\\";\\r\\n2486 | \\tstatic const char * const k_pch_SteamVR_StartDashboardFromAppLaunch_Bool = \\\"startDashboardFromAppLaunch\\\";\\r\\n2487 | \\tstatic const char * const k_pch_SteamVR_StartOverlayAppsFromDashboard_Bool = \\\"startOverlayAppsFromDashboard\\\";\\r\\n2488 | \\tstatic const char * const k_pch_SteamVR_EnableHomeApp = \\\"enableHomeApp\\\";\\r\\n2489 | \\tstatic const char * const k_pch_SteamVR_CycleBackgroundImageTimeSec_Int32 = \\\"CycleBackgroundImageTimeSec\\\";\\r\\n2490 | \\tstatic const char * const k_pch_SteamVR_RetailDemo_Bool = \\\"retailDemo\\\";\\r\\n2491 | \\tstatic const char * const k_pch_SteamVR_IpdOffset_Float = \\\"ipdOffset\\\";\\r\\n2492 | \\tstatic const char * const k_pch_SteamVR_AllowSupersampleFiltering_Bool = \\\"allowSupersampleFiltering\\\";\\r\\n2493 | \\tstatic const char * const k_pch_SteamVR_SupersampleManualOverride_Bool = \\\"supersampleManualOverride\\\";\\r\\n2494 | \\tstatic const char * const k_pch_SteamVR_EnableLinuxVulkanAsync_Bool = \\\"enableLinuxVulkanAsync\\\";\\r\\n2495 | \\tstatic const char * const k_pch_SteamVR_AllowDisplayLockedMode_Bool = \\\"allowDisplayLockedMode\\\";\\r\\n2496 | \\tstatic const char * const k_pch_SteamVR_HaveStartedTutorialForNativeChaperoneDriver_Bool = \\\"haveStartedTutorialForNativeChaperoneDriver\\\";\\r\\n2497 | \\tstatic const char * const k_pch_SteamVR_ForceWindows32bitVRMonitor = \\\"forceWindows32BitVRMonitor\\\";\\r\\n2498 | \\tstatic const char * const k_pch_SteamVR_DebugInputBinding = \\\"debugInputBinding\\\";\\r\\n2499 | \\tstatic const char * const k_pch_SteamVR_DoNotFadeToGrid = \\\"doNotFadeToGrid\\\";\\r\\n2500 | \\tstatic const char * const k_pch_SteamVR_EnableSharedResourceJournaling = \\\"enableSharedResourceJournaling\\\";\\r\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\ndocs\\\\Driver_API_Documentation.md\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:18:27 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n36,081 (18%)\\n\\n# Current Cost\\n$0.15\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":310,\"cacheWrites\":11528,\"cacheReads\":35729,\"cost\":0.0586107}"},{"ts":1744499912751,"type":"say","say":"text","text":"I've found some important information about IMU data in the OpenVR driver interface:\n\n1. Lines 2133-2142 define an enum `Imu_OffScaleFlags` which indicates when IMU data is off-scale (likely when the sensor readings exceed the measurable range).\n\n2. Lines 2144-2150 define the `ImuSample_t` struct which represents a single IMU data sample:\n   - `fSampleTime`: The timestamp of the sample\n   - `vAccel`: A 3D vector representing accelerometer data\n   - `vGyro`: A 3D vector representing gyroscope data\n   - `unOffScaleFlags`: Flags indicating if any components are off-scale\n\nThis is very relevant to our task of accessing raw IMU data when optical tracking is lost.\n\nLet me continue reading to understand how drivers are implemented and how we can access this IMU data.\n\nI've found important information about IMU data in the OpenVR driver interface. Let me continue reading to understand how drivers are implemented and how we can access this IMU data:","partial":false},{"ts":1744499917368,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"headers/openvr_driver.h\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\headers\\\\openvr_driver.h\",\"reason\":\" (lines 2500-3000)\"}","partial":false},{"ts":1744499970633,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'headers/openvr_driver.h'] Result:\\n\\n<file><path>headers/openvr_driver.h</path>\\n<content lines=\\\"2500-3000\\\">\\n2500 | \\tstatic const char * const k_pch_SteamVR_EnableSharedResourceJournaling = \\\"enableSharedResourceJournaling\\\";\\r\\n2501 | \\tstatic const char * const k_pch_SteamVR_EnableSafeMode = \\\"enableSafeMode\\\";\\r\\n2502 | \\tstatic const char * const k_pch_SteamVR_PreferredRefreshRate = \\\"preferredRefreshRate\\\";\\r\\n2503 | \\tstatic const char * const k_pch_SteamVR_LastVersionNotice = \\\"lastVersionNotice\\\";\\r\\n2504 | \\tstatic const char * const k_pch_SteamVR_LastVersionNoticeDate = \\\"lastVersionNoticeDate\\\";\\r\\n2505 | \\tstatic const char * const k_pch_SteamVR_HmdDisplayColorGainR_Float = \\\"hmdDisplayColorGainR\\\";\\r\\n2506 | \\tstatic const char * const k_pch_SteamVR_HmdDisplayColorGainG_Float = \\\"hmdDisplayColorGainG\\\";\\r\\n2507 | \\tstatic const char * const k_pch_SteamVR_HmdDisplayColorGainB_Float = \\\"hmdDisplayColorGainB\\\";\\r\\n2508 | \\tstatic const char * const k_pch_SteamVR_CustomIconStyle_String = \\\"customIconStyle\\\";\\r\\n2509 | \\tstatic const char * const k_pch_SteamVR_CustomOffIconStyle_String = \\\"customOffIconStyle\\\";\\r\\n2510 | \\tstatic const char * const k_pch_SteamVR_CustomIconForceUpdate_String = \\\"customIconForceUpdate\\\";\\r\\n2511 | \\tstatic const char * const k_pch_SteamVR_AllowGlobalActionSetPriority = \\\"globalActionSetPriority\\\";\\r\\n2512 | \\tstatic const char * const k_pch_SteamVR_OverlayRenderQuality = \\\"overlayRenderQuality_2\\\";\\r\\n2513 | \\tstatic const char * const k_pch_SteamVR_BlockOculusSDKOnOpenVRLaunchOption_Bool = \\\"blockOculusSDKOnOpenVRLaunchOption\\\";\\r\\n2514 | \\tstatic const char * const k_pch_SteamVR_BlockOculusSDKOnAllLaunches_Bool = \\\"blockOculusSDKOnAllLaunches\\\";\\r\\n2515 | \\tstatic const char * const k_pch_SteamVR_HDCPLegacyCompatibility_Bool = \\\"hdcp14legacyCompatibility\\\";\\r\\n2516 | \\tstatic const char * const k_pch_SteamVR_DisplayPortTrainingMode_Int = \\\"displayPortTrainingMode\\\";\\r\\n2517 | \\tstatic const char * const k_pch_SteamVR_UsePrism_Bool = \\\"usePrism\\\";\\r\\n2518 | \\tstatic const char * const k_pch_SteamVR_AllowFallbackMirrorWindowLinux_Bool = \\\"allowFallbackMirrorWindowLinux\\\";\\r\\n2519 | \\r\\n2520 | \\t//-----------------------------------------------------------------------------\\r\\n2521 | \\t// openxr keys\\r\\n2522 | \\tstatic const char * const k_pch_OpenXR_Section = \\\"openxr\\\";\\r\\n2523 | \\tstatic const char * const k_pch_OpenXR_MetaUnityPluginCompatibility_Int32 = \\\"metaUnityPluginCompatibility\\\";\\r\\n2524 | \\r\\n2525 | \\t//-----------------------------------------------------------------------------\\r\\n2526 | \\t// direct mode keys\\r\\n2527 | \\tstatic const char * const k_pch_DirectMode_Section = \\\"direct_mode\\\";\\r\\n2528 | \\tstatic const char * const k_pch_DirectMode_Enable_Bool = \\\"enable\\\";\\r\\n2529 | \\tstatic const char * const k_pch_DirectMode_Count_Int32 = \\\"count\\\";\\r\\n2530 | \\tstatic const char * const k_pch_DirectMode_EdidVid_Int32 = \\\"edidVid\\\";\\r\\n2531 | \\tstatic const char * const k_pch_DirectMode_EdidPid_Int32 = \\\"edidPid\\\";\\r\\n2532 | \\r\\n2533 | \\t//-----------------------------------------------------------------------------\\r\\n2534 | \\t// lighthouse keys\\r\\n2535 | \\tstatic const char * const k_pch_Lighthouse_Section = \\\"driver_lighthouse\\\";\\r\\n2536 | \\tstatic const char * const k_pch_Lighthouse_DisableIMU_Bool = \\\"disableimu\\\";\\r\\n2537 | \\tstatic const char * const k_pch_Lighthouse_DisableIMUExceptHMD_Bool = \\\"disableimuexcepthmd\\\";\\r\\n2538 | \\tstatic const char * const k_pch_Lighthouse_UseDisambiguation_String = \\\"usedisambiguation\\\";\\r\\n2539 | \\tstatic const char * const k_pch_Lighthouse_DisambiguationDebug_Int32 = \\\"disambiguationdebug\\\";\\r\\n2540 | \\tstatic const char * const k_pch_Lighthouse_PrimaryBasestation_Int32 = \\\"primarybasestation\\\";\\r\\n2541 | \\tstatic const char * const k_pch_Lighthouse_DBHistory_Bool = \\\"dbhistory\\\";\\r\\n2542 | \\tstatic const char * const k_pch_Lighthouse_EnableBluetooth_Bool = \\\"enableBluetooth\\\";\\r\\n2543 | \\tstatic const char * const k_pch_Lighthouse_PowerManagedBaseStations_String = \\\"PowerManagedBaseStations\\\";\\r\\n2544 | \\tstatic const char * const k_pch_Lighthouse_PowerManagedBaseStations2_String = \\\"PowerManagedBaseStations2\\\";\\r\\n2545 | \\tstatic const char * const k_pch_Lighthouse_InactivityTimeoutForBaseStations_Int32 = \\\"InactivityTimeoutForBaseStations\\\";\\r\\n2546 | \\tstatic const char * const k_pch_Lighthouse_EnableImuFallback_Bool = \\\"enableImuFallback\\\";\\r\\n2547 | \\r\\n2548 | \\t//-----------------------------------------------------------------------------\\r\\n2549 | \\t// null keys\\r\\n2550 | \\tstatic const char * const k_pch_Null_Section = \\\"driver_null\\\";\\r\\n2551 | \\tstatic const char * const k_pch_Null_SerialNumber_String = \\\"serialNumber\\\";\\r\\n2552 | \\tstatic const char * const k_pch_Null_ModelNumber_String = \\\"modelNumber\\\";\\r\\n2553 | \\tstatic const char * const k_pch_Null_WindowX_Int32 = \\\"windowX\\\";\\r\\n2554 | \\tstatic const char * const k_pch_Null_WindowY_Int32 = \\\"windowY\\\";\\r\\n2555 | \\tstatic const char * const k_pch_Null_WindowWidth_Int32 = \\\"windowWidth\\\";\\r\\n2556 | \\tstatic const char * const k_pch_Null_WindowHeight_Int32 = \\\"windowHeight\\\";\\r\\n2557 | \\tstatic const char * const k_pch_Null_RenderWidth_Int32 = \\\"renderWidth\\\";\\r\\n2558 | \\tstatic const char * const k_pch_Null_RenderHeight_Int32 = \\\"renderHeight\\\";\\r\\n2559 | \\tstatic const char * const k_pch_Null_SecondsFromVsyncToPhotons_Float = \\\"secondsFromVsyncToPhotons\\\";\\r\\n2560 | \\tstatic const char * const k_pch_Null_DisplayFrequency_Float = \\\"displayFrequency\\\";\\r\\n2561 | \\r\\n2562 | \\t//-----------------------------------------------------------------------------\\r\\n2563 | \\t// Windows MR keys\\r\\n2564 | \\tstatic const char * const k_pch_WindowsMR_Section = \\\"driver_holographic\\\";\\r\\n2565 | \\r\\n2566 | \\t//-----------------------------------------------------------------------------\\r\\n2567 | \\t// user interface keys\\r\\n2568 | \\tstatic const char * const k_pch_UserInterface_Section = \\\"userinterface\\\";\\r\\n2569 | \\tstatic const char * const k_pch_UserInterface_StatusAlwaysOnTop_Bool = \\\"StatusAlwaysOnTop\\\";\\r\\n2570 | \\tstatic const char * const k_pch_UserInterface_MinimizeToTray_Bool = \\\"MinimizeToTray\\\";\\r\\n2571 | \\tstatic const char * const k_pch_UserInterface_HidePopupsWhenStatusMinimized_Bool = \\\"HidePopupsWhenStatusMinimized\\\";\\r\\n2572 | \\tstatic const char * const k_pch_UserInterface_Screenshots_Bool = \\\"screenshots\\\";\\r\\n2573 | \\tstatic const char * const k_pch_UserInterface_ScreenshotType_Int = \\\"screenshotType\\\";\\r\\n2574 | \\r\\n2575 | \\t//-----------------------------------------------------------------------------\\r\\n2576 | \\t// notification keys\\r\\n2577 | \\tstatic const char * const k_pch_Notifications_Section = \\\"notifications\\\";\\r\\n2578 | \\tstatic const char * const k_pch_Notifications_DoNotDisturb_Bool = \\\"DoNotDisturb\\\";\\r\\n2579 | \\r\\n2580 | \\t//-----------------------------------------------------------------------------\\r\\n2581 | \\t// keyboard keys\\r\\n2582 | \\tstatic const char * const k_pch_Keyboard_Section = \\\"keyboard\\\";\\r\\n2583 | \\tstatic const char * const k_pch_Keyboard_TutorialCompletions = \\\"TutorialCompletions\\\";\\r\\n2584 | \\tstatic const char * const k_pch_Keyboard_ScaleX = \\\"ScaleX\\\";\\r\\n2585 | \\tstatic const char * const k_pch_Keyboard_ScaleY = \\\"ScaleY\\\";\\r\\n2586 | \\tstatic const char * const k_pch_Keyboard_OffsetLeftX = \\\"OffsetLeftX\\\";\\r\\n2587 | \\tstatic const char * const k_pch_Keyboard_OffsetRightX = \\\"OffsetRightX\\\";\\r\\n2588 | \\tstatic const char * const k_pch_Keyboard_OffsetY = \\\"OffsetY\\\";\\r\\n2589 | \\tstatic const char * const k_pch_Keyboard_Smoothing = \\\"Smoothing\\\";\\r\\n2590 | \\r\\n2591 | \\t//-----------------------------------------------------------------------------\\r\\n2592 | \\t// perf keys\\r\\n2593 | \\tstatic const char * const k_pch_Perf_Section = \\\"perfcheck\\\";\\r\\n2594 | \\tstatic const char * const k_pch_Perf_PerfGraphInHMD_Bool = \\\"perfGraphInHMD\\\";\\r\\n2595 | \\tstatic const char * const k_pch_Perf_AllowTimingStore_Bool = \\\"allowTimingStore\\\";\\r\\n2596 | \\tstatic const char * const k_pch_Perf_SaveTimingsOnExit_Bool = \\\"saveTimingsOnExit\\\";\\r\\n2597 | \\tstatic const char * const k_pch_Perf_TestData_Float = \\\"perfTestData\\\";\\r\\n2598 | \\tstatic const char * const k_pch_Perf_GPUProfiling_Bool = \\\"GPUProfiling\\\";\\r\\n2599 | \\tstatic const char * const k_pch_Perf_GpuBusMonitoring_Bool = \\\"gpuBusMonitoring\\\";\\r\\n2600 | \\r\\n2601 | \\t//-----------------------------------------------------------------------------\\r\\n2602 | \\t// collision bounds keys\\r\\n2603 | \\tstatic const char * const k_pch_CollisionBounds_Section = \\\"collisionBounds\\\";\\r\\n2604 | \\tstatic const char * const k_pch_CollisionBounds_Style_Int32 = \\\"CollisionBoundsStyle\\\";\\r\\n2605 | \\tstatic const char * const k_pch_CollisionBounds_GroundPerimeterOn_Bool = \\\"CollisionBoundsGroundPerimeterOn\\\";\\r\\n2606 | \\tstatic const char * const k_pch_CollisionBounds_CenterMarkerOn_Bool = \\\"CollisionBoundsCenterMarkerOn\\\";\\r\\n2607 | \\tstatic const char * const k_pch_CollisionBounds_PlaySpaceOn_Bool = \\\"CollisionBoundsPlaySpaceOn\\\";\\r\\n2608 | \\tstatic const char * const k_pch_CollisionBounds_FadeDistance_Float = \\\"CollisionBoundsFadeDistance\\\";\\r\\n2609 | \\tstatic const char * const k_pch_CollisionBounds_WallHeight_Float = \\\"CollisionBoundsWallHeight\\\";\\r\\n2610 | \\tstatic const char * const k_pch_CollisionBounds_ColorGammaR_Int32 = \\\"CollisionBoundsColorGammaR\\\";\\r\\n2611 | \\tstatic const char * const k_pch_CollisionBounds_ColorGammaG_Int32 = \\\"CollisionBoundsColorGammaG\\\";\\r\\n2612 | \\tstatic const char * const k_pch_CollisionBounds_ColorGammaB_Int32 = \\\"CollisionBoundsColorGammaB\\\";\\r\\n2613 | \\tstatic const char * const k_pch_CollisionBounds_ColorGammaA_Int32 = \\\"CollisionBoundsColorGammaA\\\";\\r\\n2614 | \\tstatic const char * const k_pch_CollisionBounds_EnableDriverImport = \\\"enableDriverBoundsImport\\\";\\r\\n2615 | \\r\\n2616 | \\t//-----------------------------------------------------------------------------\\r\\n2617 | \\t// camera keys\\r\\n2618 | \\tstatic const char * const k_pch_Camera_Section = \\\"camera\\\";\\r\\n2619 | \\tstatic const char * const k_pch_Camera_EnableCamera_Bool = \\\"enableCamera\\\";\\r\\n2620 | \\tstatic const char * const k_pch_Camera_ShowOnController_Bool = \\\"showOnController\\\";\\r\\n2621 | \\tstatic const char * const k_pch_Camera_EnableCameraForCollisionBounds_Bool = \\\"enableCameraForCollisionBounds\\\";\\r\\n2622 | \\tstatic const char * const k_pch_Camera_RoomView_Int32 = \\\"roomView\\\";\\r\\n2623 | \\tstatic const char * const k_pch_Camera_BoundsColorGammaR_Int32 = \\\"cameraBoundsColorGammaR\\\";\\r\\n2624 | \\tstatic const char * const k_pch_Camera_BoundsColorGammaG_Int32 = \\\"cameraBoundsColorGammaG\\\";\\r\\n2625 | \\tstatic const char * const k_pch_Camera_BoundsColorGammaB_Int32 = \\\"cameraBoundsColorGammaB\\\";\\r\\n2626 | \\tstatic const char * const k_pch_Camera_BoundsColorGammaA_Int32 = \\\"cameraBoundsColorGammaA\\\";\\r\\n2627 | \\tstatic const char * const k_pch_Camera_BoundsStrength_Int32 = \\\"cameraBoundsStrength\\\";\\r\\n2628 | \\tstatic const char * const k_pch_Camera_RoomViewStyle_Int32 = \\\"roomViewStyle\\\";\\r\\n2629 | \\r\\n2630 | \\t//-----------------------------------------------------------------------------\\r\\n2631 | \\t// audio keys\\r\\n2632 | \\tstatic const char * const k_pch_audio_Section = \\\"audio\\\";\\r\\n2633 | \\tstatic const char * const k_pch_audio_SetOsDefaultPlaybackDevice_Bool = \\\"setOsDefaultPlaybackDevice\\\";\\r\\n2634 | \\tstatic const char * const k_pch_audio_EnablePlaybackDeviceOverride_Bool = \\\"enablePlaybackDeviceOverride\\\";\\r\\n2635 | \\tstatic const char * const k_pch_audio_PlaybackDeviceOverride_String = \\\"playbackDeviceOverride\\\";\\r\\n2636 | \\tstatic const char * const k_pch_audio_PlaybackDeviceOverrideName_String = \\\"playbackDeviceOverrideName\\\";\\r\\n2637 | \\tstatic const char * const k_pch_audio_SetOsDefaultRecordingDevice_Bool = \\\"setOsDefaultRecordingDevice\\\";\\r\\n2638 | \\tstatic const char * const k_pch_audio_EnableRecordingDeviceOverride_Bool = \\\"enableRecordingDeviceOverride\\\";\\r\\n2639 | \\tstatic const char * const k_pch_audio_RecordingDeviceOverride_String = \\\"recordingDeviceOverride\\\";\\r\\n2640 | \\tstatic const char * const k_pch_audio_RecordingDeviceOverrideName_String = \\\"recordingDeviceOverrideName\\\";\\r\\n2641 | \\tstatic const char * const k_pch_audio_EnablePlaybackMirror_Bool = \\\"enablePlaybackMirror\\\";\\r\\n2642 | \\tstatic const char * const k_pch_audio_PlaybackMirrorDevice_String = \\\"playbackMirrorDevice\\\";\\r\\n2643 | \\tstatic const char * const k_pch_audio_PlaybackMirrorDeviceName_String = \\\"playbackMirrorDeviceName\\\";\\r\\n2644 | \\tstatic const char * const k_pch_audio_OldPlaybackMirrorDevice_String = \\\"onPlaybackMirrorDevice\\\";\\r\\n2645 | \\tstatic const char * const k_pch_audio_ActiveMirrorDevice_String = \\\"activePlaybackMirrorDevice\\\";\\r\\n2646 | \\tstatic const char * const k_pch_audio_EnablePlaybackMirrorIndependentVolume_Bool = \\\"enablePlaybackMirrorIndependentVolume\\\";\\r\\n2647 | \\tstatic const char * const k_pch_audio_LastHmdPlaybackDeviceId_String = \\\"lastHmdPlaybackDeviceId\\\";\\r\\n2648 | \\tstatic const char * const k_pch_audio_VIVEHDMIGain = \\\"viveHDMIGain\\\";\\r\\n2649 | \\tstatic const char * const k_pch_audio_DualSpeakerAndJackOutput_Bool = \\\"dualSpeakerAndJackOutput\\\";\\r\\n2650 | \\tstatic const char * const k_pch_audio_MuteMicMonitor_Bool = \\\"muteMicMonitor\\\";\\r\\n2651 | \\r\\n2652 | \\t//-----------------------------------------------------------------------------\\r\\n2653 | \\t// power management keys\\r\\n2654 | \\tstatic const char * const k_pch_Power_Section = \\\"power\\\";\\r\\n2655 | \\tstatic const char * const k_pch_Power_PowerOffOnExit_Bool = \\\"powerOffOnExit\\\";\\r\\n2656 | \\tstatic const char * const k_pch_Power_TurnOffScreensTimeout_Float = \\\"turnOffScreensTimeout\\\";\\r\\n2657 | \\tstatic const char * const k_pch_Power_TurnOffControllersTimeout_Float = \\\"turnOffControllersTimeout\\\";\\r\\n2658 | \\tstatic const char * const k_pch_Power_ReturnToWatchdogTimeout_Float = \\\"returnToWatchdogTimeout\\\";\\r\\n2659 | \\tstatic const char * const k_pch_Power_AutoLaunchSteamVROnButtonPress = \\\"autoLaunchSteamVROnButtonPress\\\";\\r\\n2660 | \\tstatic const char * const k_pch_Power_PauseCompositorOnStandby_Bool = \\\"pauseCompositorOnStandby\\\";\\r\\n2661 | \\r\\n2662 | \\t//-----------------------------------------------------------------------------\\r\\n2663 | \\t// dashboard keys\\r\\n2664 | \\tstatic const char * const k_pch_Dashboard_Section = \\\"dashboard\\\";\\r\\n2665 | \\tstatic const char * const k_pch_Dashboard_EnableDashboard_Bool = \\\"enableDashboard\\\";\\r\\n2666 | \\tstatic const char * const k_pch_Dashboard_ArcadeMode_Bool = \\\"arcadeMode\\\";\\r\\n2667 | \\tstatic const char * const k_pch_Dashboard_Position = \\\"position\\\";\\r\\n2668 | \\tstatic const char * const k_pch_Dashboard_DesktopScale = \\\"desktopScale\\\";\\r\\n2669 | \\tstatic const char * const k_pch_Dashboard_DashboardScale = \\\"dashboardScale\\\";\\r\\n2670 | \\tstatic const char * const k_pch_Dashboard_UseStandaloneSystemLayer = \\\"standaloneSystemLayer\\\";\\r\\n2671 | \\tstatic const char * const k_pch_Dashboard_StickyDashboard = \\\"stickyDashboard\\\";\\r\\n2672 | \\tstatic const char * const k_pch_Dashboard_AllowSteamOverlays_Bool = \\\"allowSteamOverlays\\\";\\r\\n2673 | \\tstatic const char * const k_pch_Dashboard_AllowVRGamepadUI_Bool = \\\"allowVRGamepadUI\\\";\\r\\n2674 | \\tstatic const char * const k_pch_Dashboard_AllowVRGamepadUIViaGamescope_Bool = \\\"allowVRGamepadUIViaGamescope\\\";\\r\\n2675 | \\tstatic const char * const k_pch_Dashboard_SteamMatchesHMDFramerate = \\\"steamMatchesHMDFramerate\\\";\\r\\n2676 | \\r\\n2677 | \\t//-----------------------------------------------------------------------------\\r\\n2678 | \\t// model skin keys\\r\\n2679 | \\tstatic const char * const k_pch_modelskin_Section = \\\"modelskins\\\";\\r\\n2680 | \\r\\n2681 | \\t//-----------------------------------------------------------------------------\\r\\n2682 | \\t// driver keys - These could be checked in any driver_<name> section\\r\\n2683 | \\tstatic const char * const k_pch_Driver_Enable_Bool = \\\"enable\\\";\\r\\n2684 | \\tstatic const char * const k_pch_Driver_BlockedBySafemode_Bool = \\\"blocked_by_safe_mode\\\";\\r\\n2685 | \\tstatic const char * const k_pch_Driver_LoadPriority_Int32 = \\\"loadPriority\\\";\\r\\n2686 | \\r\\n2687 | \\t//-----------------------------------------------------------------------------\\r\\n2688 | \\t// web interface keys\\r\\n2689 | \\tstatic const char* const k_pch_WebInterface_Section = \\\"WebInterface\\\";\\r\\n2690 | \\r\\n2691 | \\t//-----------------------------------------------------------------------------\\r\\n2692 | \\t// vrwebhelper keys\\r\\n2693 | \\tstatic const char* const k_pch_VRWebHelper_Section = \\\"VRWebHelper\\\";\\r\\n2694 | \\tstatic const char* const k_pch_VRWebHelper_DebuggerEnabled_Bool = \\\"DebuggerEnabled\\\";\\r\\n2695 | \\tstatic const char* const k_pch_VRWebHelper_DebuggerPort_Int32 = \\\"DebuggerPort\\\";\\r\\n2696 | \\r\\n2697 | \\t//-----------------------------------------------------------------------------\\r\\n2698 | \\t// tracking overrides - keys are device paths, values are the device paths their\\r\\n2699 | \\t//  tracking/pose information overrides\\r\\n2700 | \\tstatic const char* const k_pch_TrackingOverride_Section = \\\"TrackingOverrides\\\";\\r\\n2701 | \\r\\n2702 | \\t//-----------------------------------------------------------------------------\\r\\n2703 | \\t// per-app keys - the section name for these is the app key itself. Some of these are prefixed by the controller type\\r\\n2704 | \\tstatic const char* const k_pch_App_BindingAutosaveURLSuffix_String = \\\"AutosaveURL\\\";\\r\\n2705 | \\tstatic const char* const k_pch_App_BindingLegacyAPISuffix_String = \\\"_legacy\\\";\\r\\n2706 | \\tstatic const char *const k_pch_App_BindingSteamVRInputAPISuffix_String = \\\"_steamvrinput\\\";\\r\\n2707 | \\tstatic const char *const k_pch_App_BindingOpenXRAPISuffix_String = \\\"_openxr\\\";\\r\\n2708 | \\tstatic const char* const k_pch_App_BindingCurrentURLSuffix_String = \\\"CurrentURL\\\";\\r\\n2709 | \\tstatic const char* const k_pch_App_BindingPreviousURLSuffix_String = \\\"PreviousURL\\\";\\r\\n2710 | \\tstatic const char* const k_pch_App_NeedToUpdateAutosaveSuffix_Bool = \\\"NeedToUpdateAutosave\\\";\\r\\n2711 | \\tstatic const char* const k_pch_App_DominantHand_Int32 = \\\"DominantHand\\\";\\r\\n2712 | \\tstatic const char* const k_pch_App_BlockOculusSDK_Bool = \\\"blockOculusSDK\\\";\\r\\n2713 | \\r\\n2714 | \\t//-----------------------------------------------------------------------------\\r\\n2715 | \\t// configuration for trackers\\r\\n2716 | \\tstatic const char * const k_pch_Trackers_Section = \\\"trackers\\\";\\r\\n2717 | \\r\\n2718 | \\t//-----------------------------------------------------------------------------\\r\\n2719 | \\t// configuration for desktop UI windows\\r\\n2720 | \\tstatic const char * const k_pch_DesktopUI_Section = \\\"DesktopUI\\\";\\r\\n2721 | \\r\\n2722 | \\t//-----------------------------------------------------------------------------\\r\\n2723 | \\t// Last known keys for righting recovery\\r\\n2724 | \\tstatic const char * const k_pch_LastKnown_Section = \\\"LastKnown\\\";\\r\\n2725 | \\tstatic const char* const k_pch_LastKnown_HMDManufacturer_String = \\\"HMDManufacturer\\\";\\r\\n2726 | \\tstatic const char *const k_pch_LastKnown_HMDModel_String = \\\"HMDModel\\\";\\r\\n2727 | \\tstatic const char* const k_pch_LastKnown_ActualHMDDriver_String = \\\"ActualHMDDriver\\\";\\r\\n2728 | \\r\\n2729 | \\t//-----------------------------------------------------------------------------\\r\\n2730 | \\t// Dismissed warnings\\r\\n2731 | \\tstatic const char * const k_pch_DismissedWarnings_Section = \\\"DismissedWarnings\\\";\\r\\n2732 | \\r\\n2733 | \\t//-----------------------------------------------------------------------------\\r\\n2734 | \\t// Input Settings\\r\\n2735 | \\tstatic const char * const k_pch_Input_Section = \\\"input\\\";\\r\\n2736 | \\tstatic const char* const k_pch_Input_LeftThumbstickRotation_Float = \\\"leftThumbstickRotation\\\";\\r\\n2737 | \\tstatic const char* const k_pch_Input_RightThumbstickRotation_Float = \\\"rightThumbstickRotation\\\";\\r\\n2738 | \\tstatic const char* const k_pch_Input_ThumbstickDeadzone_Float = \\\"thumbstickDeadzone\\\";\\r\\n2739 | \\r\\n2740 | \\t//-----------------------------------------------------------------------------\\r\\n2741 | \\t// Log of GPU performance\\r\\n2742 | \\tstatic const char * const k_pch_GpuSpeed_Section = \\\"GpuSpeed\\\";\\r\\n2743 | \\r\\n2744 | } // namespace vr\\r\\n2745 | \\r\\n2746 | // iservertrackeddevicedriver.h\\r\\n2747 | \\r\\n2748 | namespace vr\\r\\n2749 | {\\r\\n2750 | \\r\\n2751 | \\r\\n2752 | struct DriverPoseQuaternion_t\\r\\n2753 | {\\r\\n2754 | \\tdouble w, x, y, z;\\r\\n2755 | };\\r\\n2756 | \\r\\n2757 | struct DriverPose_t\\r\\n2758 | {\\r\\n2759 | \\t/* Time offset of this pose, in seconds from the actual time of the pose,\\r\\n2760 | \\t * relative to the time of the PoseUpdated() call made by the driver.\\r\\n2761 | \\t */\\r\\n2762 | \\tdouble poseTimeOffset;\\r\\n2763 | \\r\\n2764 | \\t/* Generally, the pose maintained by a driver\\r\\n2765 | \\t * is in an inertial coordinate system different\\r\\n2766 | \\t * from the world system of x+ right, y+ up, z+ back.\\r\\n2767 | \\t * Also, the driver is not usually tracking the \\\"head\\\" position,\\r\\n2768 | \\t * but instead an internal IMU or another reference point in the HMD.\\r\\n2769 | \\t * The following two transforms transform positions and orientations\\r\\n2770 | \\t * to app world space from driver world space,\\r\\n2771 | \\t * and to HMD head space from driver local body space.\\r\\n2772 | \\t *\\r\\n2773 | \\t * We maintain the driver pose state in its internal coordinate system,\\r\\n2774 | \\t * so we can do the pose prediction math without having to\\r\\n2775 | \\t * use angular acceleration.  A driver's angular acceleration is generally not measured,\\r\\n2776 | \\t * and is instead calculated from successive samples of angular velocity.\\r\\n2777 | \\t * This leads to a noisy angular acceleration values, which are also\\r\\n2778 | \\t * lagged due to the filtering required to reduce noise to an acceptable level.\\r\\n2779 | \\t */\\r\\n2780 | \\tvr::HmdQuaternion_t qWorldFromDriverRotation;\\r\\n2781 | \\tdouble vecWorldFromDriverTranslation[ 3 ];\\r\\n2782 | \\r\\n2783 | \\tvr::HmdQuaternion_t qDriverFromHeadRotation;\\r\\n2784 | \\tdouble vecDriverFromHeadTranslation[ 3 ];\\r\\n2785 | \\r\\n2786 | \\t/* State of driver pose, in meters and radians. */\\r\\n2787 | \\t/* Position of the driver tracking reference in driver world space\\r\\n2788 | \\t* +[0] (x) is right\\r\\n2789 | \\t* +[1] (y) is up\\r\\n2790 | \\t* -[2] (z) is forward\\r\\n2791 | \\t*/\\r\\n2792 | \\tdouble vecPosition[ 3 ];\\r\\n2793 | \\r\\n2794 | \\t/* Velocity of the pose in meters/second */\\r\\n2795 | \\tdouble vecVelocity[ 3 ];\\r\\n2796 | \\r\\n2797 | \\t/* Acceleration of the pose in meters/second */\\r\\n2798 | \\tdouble vecAcceleration[ 3 ];\\r\\n2799 | \\r\\n2800 | \\t/* Orientation of the tracker, represented as a quaternion */\\r\\n2801 | \\tvr::HmdQuaternion_t qRotation;\\r\\n2802 | \\r\\n2803 | \\t/* Angular velocity of the pose in axis-angle\\r\\n2804 | \\t* representation. The direction is the angle of\\r\\n2805 | \\t* rotation and the magnitude is the angle around\\r\\n2806 | \\t* that axis in radians/second. */\\r\\n2807 | \\tdouble vecAngularVelocity[ 3 ];\\r\\n2808 | \\r\\n2809 | \\t/* Angular acceleration of the pose in axis-angle\\r\\n2810 | \\t* representation. The direction is the angle of\\r\\n2811 | \\t* rotation and the magnitude is the angle around\\r\\n2812 | \\t* that axis in radians/second^2. */\\r\\n2813 | \\tdouble vecAngularAcceleration[ 3 ];\\r\\n2814 | \\r\\n2815 | \\tETrackingResult result;\\r\\n2816 | \\r\\n2817 | \\tbool poseIsValid;\\r\\n2818 | \\tbool willDriftInYaw;\\r\\n2819 | \\tbool shouldApplyHeadModel;\\r\\n2820 | \\tbool deviceIsConnected;\\r\\n2821 | };\\r\\n2822 | \\r\\n2823 | \\r\\n2824 | // ----------------------------------------------------------------------------------------------\\r\\n2825 | // Purpose: Represents a single tracked device in a driver\\r\\n2826 | // ----------------------------------------------------------------------------------------------\\r\\n2827 | class ITrackedDeviceServerDriver\\r\\n2828 | {\\r\\n2829 | public:\\r\\n2830 | \\r\\n2831 | \\t// ------------------------------------\\r\\n2832 | \\t// Management Methods\\r\\n2833 | \\t// ------------------------------------\\r\\n2834 | \\t/** This is called before an HMD is returned to the application. It will always be\\r\\n2835 | \\t* called before any display or tracking methods. Memory and processor use by the\\r\\n2836 | \\t* ITrackedDeviceServerDriver object should be kept to a minimum until it is activated.\\r\\n2837 | \\t* The pose listener is guaranteed to be valid until Deactivate is called, but\\r\\n2838 | \\t* should not be used after that point. */\\r\\n2839 | \\tvirtual EVRInitError Activate( uint32_t unObjectId ) = 0;\\r\\n2840 | \\r\\n2841 | \\t/** This is called when The VR system is switching from this Hmd being the active display\\r\\n2842 | \\t* to another Hmd being the active display. The driver should clean whatever memory\\r\\n2843 | \\t* and thread use it can when it is deactivated */\\r\\n2844 | \\tvirtual void Deactivate() = 0;\\r\\n2845 | \\r\\n2846 | \\t/** Handles a request from the system to put this device into standby mode. What that means is defined per-device. */\\r\\n2847 | \\tvirtual void EnterStandby() = 0;\\r\\n2848 | \\r\\n2849 | \\t/** Requests a component interface of the driver for device-specific functionality. The driver should return NULL\\r\\n2850 | \\t* if the requested interface or version is not supported. */\\r\\n2851 | \\tvirtual void *GetComponent( const char *pchComponentNameAndVersion ) = 0;\\r\\n2852 | \\r\\n2853 | \\t/** A VR Client has made this debug request of the driver. The set of valid requests is entirely\\r\\n2854 | \\t* up to the driver and the client to figure out, as is the format of the response. Responses that\\r\\n2855 | \\t* exceed the length of the supplied buffer should be truncated and null terminated */\\r\\n2856 | \\tvirtual void DebugRequest( const char *pchRequest, char *pchResponseBuffer, uint32_t unResponseBufferSize ) = 0;\\r\\n2857 | \\r\\n2858 | \\t// ------------------------------------\\r\\n2859 | \\t// Tracking Methods\\r\\n2860 | \\t// ------------------------------------\\r\\n2861 | \\tvirtual DriverPose_t GetPose() = 0;\\r\\n2862 | };\\r\\n2863 | \\r\\n2864 | \\r\\n2865 | \\r\\n2866 | static const char *ITrackedDeviceServerDriver_Version = \\\"ITrackedDeviceServerDriver_005\\\";\\r\\n2867 | \\r\\n2868 | }\\r\\n2869 | \\r\\n2870 | // ivrdisplaycomponent.h\\r\\n2871 | \\r\\n2872 | namespace vr\\r\\n2873 | {\\r\\n2874 | \\r\\n2875 | \\r\\n2876 | \\t// ----------------------------------------------------------------------------------------------\\r\\n2877 | \\t// Purpose: The display component on a single tracked device\\r\\n2878 | \\t// ----------------------------------------------------------------------------------------------\\r\\n2879 | \\tclass IVRDisplayComponent\\r\\n2880 | \\t{\\r\\n2881 | \\tpublic:\\r\\n2882 | \\r\\n2883 | \\t\\t// ------------------------------------\\r\\n2884 | \\t\\t// Display Methods\\r\\n2885 | \\t\\t// ------------------------------------\\r\\n2886 | \\r\\n2887 | \\t\\t/** Size and position that the window needs to be on the VR display. */\\r\\n2888 | \\t\\tvirtual void GetWindowBounds( int32_t *pnX, int32_t *pnY, uint32_t *pnWidth, uint32_t *pnHeight ) = 0;\\r\\n2889 | \\r\\n2890 | \\t\\t/** Returns true if the display is extending the desktop. */\\r\\n2891 | \\t\\tvirtual bool IsDisplayOnDesktop( ) = 0;\\r\\n2892 | \\r\\n2893 | \\t\\t/** Returns true if the display is real and not a fictional display. */\\r\\n2894 | \\t\\tvirtual bool IsDisplayRealDisplay( ) = 0;\\r\\n2895 | \\r\\n2896 | \\t\\t/** Suggested size for the intermediate render target that the distortion pulls from. */\\r\\n2897 | \\t\\tvirtual void GetRecommendedRenderTargetSize( uint32_t *pnWidth, uint32_t *pnHeight ) = 0;\\r\\n2898 | \\r\\n2899 | \\t\\t/** Gets the viewport in the frame buffer to draw the output of the distortion into */\\r\\n2900 | \\t\\tvirtual void GetEyeOutputViewport( EVREye eEye, uint32_t *pnX, uint32_t *pnY, uint32_t *pnWidth, uint32_t *pnHeight ) = 0;\\r\\n2901 | \\r\\n2902 | \\t\\t/** The components necessary to build your own projection matrix in case your\\r\\n2903 | \\t\\t* application is doing something fancy like infinite Z */\\r\\n2904 | \\t\\tvirtual void GetProjectionRaw( EVREye eEye, float *pfLeft, float *pfRight, float *pfTop, float *pfBottom ) = 0;\\r\\n2905 | \\r\\n2906 | \\t\\t/** Returns the result of the distortion function for the specified eye and input UVs. UVs go from 0,0 in\\r\\n2907 | \\t\\t* the upper left of that eye's viewport and 1,1 in the lower right of that eye's viewport. */\\r\\n2908 | \\t\\tvirtual DistortionCoordinates_t ComputeDistortion( EVREye eEye, float fU, float fV ) = 0;\\r\\n2909 | \\r\\n2910 | \\t\\t/** Computes the result of the inverse distortion function for the specified eye, channel, and input UV.\\r\\n2911 | \\t\\t* Operation can fail, returns success/failure, on success result is stored in *pResult */\\r\\n2912 | \\t\\tvirtual bool ComputeInverseDistortion( HmdVector2_t *pResult, EVREye eEye, uint32_t unChannel, float fU, float fV ) = 0;\\r\\n2913 | \\t};\\r\\n2914 | \\r\\n2915 | \\tstatic const char *IVRDisplayComponent_Version = \\\"IVRDisplayComponent_003\\\";\\r\\n2916 | \\r\\n2917 | }\\r\\n2918 | \\r\\n2919 | // ivrdriverdirectmodecomponent.h\\r\\n2920 | \\r\\n2921 | namespace vr\\r\\n2922 | {\\r\\n2923 | \\tenum VRSwapTextureFlag\\r\\n2924 | \\t{\\r\\n2925 | \\t\\t// Specify that the shared texture resource was created with the SHARED_NTHANDLE option (Windows)\\r\\n2926 | \\t\\tVRSwapTextureFlag_Shared_NTHandle = 1 << 0,\\r\\n2927 | \\t};\\r\\n2928 | \\r\\n2929 | \\t// ----------------------------------------------------------------------------------------------\\r\\n2930 | \\t// Purpose: This component is used for drivers that implement direct mode entirely on their own\\r\\n2931 | \\t//\\t\\t\\twithout allowing the VR Compositor to own the window/device.\\r\\n2932 | \\t// ----------------------------------------------------------------------------------------------\\r\\n2933 | \\tclass IVRDriverDirectModeComponent\\r\\n2934 | \\t{\\r\\n2935 | \\tpublic:\\r\\n2936 | \\r\\n2937 | \\t\\t// -----------------------------------\\r\\n2938 | \\t\\t// Direct mode methods\\r\\n2939 | \\t\\t// -----------------------------------\\r\\n2940 | \\r\\n2941 | \\t\\tstruct SwapTextureSetDesc_t\\r\\n2942 | \\t\\t{\\r\\n2943 | \\t\\t\\tuint32_t nWidth;\\r\\n2944 | \\t\\t\\tuint32_t nHeight;\\r\\n2945 | \\t\\t\\tuint32_t nFormat;\\r\\n2946 | \\t\\t\\tuint32_t nSampleCount;\\r\\n2947 | \\t\\t};\\r\\n2948 | \\r\\n2949 | \\t\\tstruct SwapTextureSet_t\\r\\n2950 | \\t\\t{\\r\\n2951 | \\t\\t\\tvr::SharedTextureHandle_t rSharedTextureHandles[ 3 ];\\r\\n2952 | \\t\\t\\tuint32_t unTextureFlags;\\r\\n2953 | \\t\\t};\\r\\n2954 | \\r\\n2955 | \\t\\t/** Called to allocate textures for applications to render into.  One of these per eye will be passed back to SubmitLayer each frame. */\\r\\n2956 | \\t\\tvirtual void CreateSwapTextureSet( uint32_t unPid, const SwapTextureSetDesc_t *pSwapTextureSetDesc, SwapTextureSet_t *pOutSwapTextureSet ) {}\\r\\n2957 | \\r\\n2958 | \\t\\t/** Used to textures created using CreateSwapTextureSet.  Only one of the set's handles needs to be used to destroy the entire set. */\\r\\n2959 | \\t\\tvirtual void DestroySwapTextureSet( vr::SharedTextureHandle_t sharedTextureHandle ) {}\\r\\n2960 | \\r\\n2961 | \\t\\t/** Used to purge all texture sets for a given process. */\\r\\n2962 | \\t\\tvirtual void DestroyAllSwapTextureSets( uint32_t unPid ) {}\\r\\n2963 | \\r\\n2964 | \\t\\t/** After Present returns, calls this to get the next index to use for rendering. */\\r\\n2965 | \\t\\tvirtual void GetNextSwapTextureSetIndex( vr::SharedTextureHandle_t sharedTextureHandles[ 2 ], uint32_t( *pIndices )[ 2 ] ) {}\\r\\n2966 | \\r\\n2967 | \\t\\t/** Call once per layer to draw for this frame.  One shared texture handle per eye.  Textures must be created\\r\\n2968 | \\t\\t* using CreateSwapTextureSet and should be alternated per frame.  Call Present once all layers have been submitted. */\\r\\n2969 | \\t\\tstruct SubmitLayerPerEye_t\\r\\n2970 | \\t\\t{\\r\\n2971 | \\t\\t\\t// Shared texture handles (depth not always provided).\\r\\n2972 | \\t\\t\\tvr::SharedTextureHandle_t hTexture, hDepthTexture;\\r\\n2973 | \\r\\n2974 | \\t\\t\\t// Valid region of provided texture (and depth).\\r\\n2975 | \\t\\t\\tvr::VRTextureBounds_t bounds;\\r\\n2976 | \\r\\n2977 | \\t\\t\\t// Projection matrix used to render the depth buffer.\\r\\n2978 | \\t\\t\\tvr::HmdMatrix44_t mProjection;\\r\\n2979 | \\r\\n2980 | \\t\\t\\t// Hmd pose used to render this layer.\\r\\n2981 | \\t\\t\\tvr::HmdMatrix34_t mHmdPose;\\r\\n2982 | \\r\\n2983 | \\t\\t\\t// Time in seconds from now that mHmdPose was predicted to.\\r\\n2984 | \\t\\t\\tfloat flHmdPosePredictionTimeInSecondsFromNow;\\r\\n2985 | \\t\\t};\\r\\n2986 | \\t\\tvirtual void SubmitLayer( const SubmitLayerPerEye_t( &perEye )[ 2 ] ) {}\\r\\n2987 | \\r\\n2988 | \\t\\t/** Submits queued layers for display. */\\r\\n2989 | \\t\\tvirtual void Present( vr::SharedTextureHandle_t syncTexture ) {}\\r\\n2990 | \\r\\n2991 | \\t\\t/** Called after Present to allow driver to take more time until vsync after they've successfully acquired the sync texture in Present.\\r\\n2992 | \\t\\t* Set Prop_Hmd_SupportsAppThrottling_Bool to enable throttling / prediction UI in per-app video settings. */\\r\\n2993 | \\t\\tstruct Throttling_t\\r\\n2994 | \\t\\t{\\r\\n2995 | \\t\\t\\tuint32_t nFramesToThrottle;\\r\\n2996 | \\t\\t\\tuint32_t nAdditionalFramesToPredict;\\r\\n2997 | \\t\\t};\\r\\n2998 | \\t\\tvirtual void PostPresent( const Throttling_t *pThrottling ) {}\\r\\n2999 | \\r\\n3000 | \\t\\t/** Called to get additional frame timing stats from driver.  Check m_nSize for versioning (new members will be added to end only). */\\r\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\ndocs\\\\Driver_API_Documentation.md\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:19:30 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n47,571 (24%)\\n\\n# Current Cost\\n$0.21\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":759,\"cacheWrites\":11480,\"cacheReads\":47257,\"cost\":0.0686241}"},{"ts":1744499974809,"type":"say","say":"text","text":"I've found some very important information in this section of the header file:\n\n1. Lines 2536-2537 show configuration keys for the lighthouse driver:\n   - `k_pch_Lighthouse_DisableIMU_Bool` - Option to disable IMU\n   - `k_pch_Lighthouse_DisableIMUExceptHMD_Bool` - Option to disable IMU except for HMD\n\n2. Line 2546 shows:\n   - `k_pch_Lighthouse_EnableImuFallback_Bool` - Option to enable IMU fallback\n\n3. Lines 2757-2821 define the `DriverPose_t` struct which is used to represent the pose of a tracked device. This includes:\n   - Position, velocity, and acceleration\n   - Orientation (quaternion)\n   - Angular velocity and acceleration\n   - Tracking result status\n\n4. Lines 2827-2862 define the `ITrackedDeviceServerDriver` interface, which is the base interface for tracked devices in a driver. This includes:\n   - `Activate` and `Deactivate` methods for device lifecycle\n   - `GetComponent` method to get device-specific functionality\n   - `GetPose` method to get the current pose of the device\n\nThis information is crucial for understanding how to implement a custom driver that can access raw IMU data when optical tracking is lost.\n\nLet me continue reading to find more information about the driver architecture and how to implement a custom driver.\n\nI've found some important information about the OpenVR driver architecture and IMU data handling:\n\n1. The `ImuSample_t` struct (lines 2144-2150) represents raw IMU data:\n   ```cpp\n   struct ImuSample_t {\n       double fSampleTime;\n       HmdVector3d_t vAccel;\n       HmdVector3d_t vGyro;\n       uint32_t unOffScaleFlags;\n   };\n   ```\n\n2. The lighthouse driver has configuration options related to IMU:\n   - `k_pch_Lighthouse_DisableIMU_Bool` (line 2536) - Option to disable IMU\n   - `k_pch_Lighthouse_DisableIMUExceptHMD_Bool` (line 2537) - Option to disable IMU except for HMD\n   - `k_pch_Lighthouse_EnableImuFallback_Bool` (line 2546) - Option to enable IMU fallback\n\n3. The `DriverPose_t` struct (lines 2757-2821) is used to represent the pose of a tracked device, including:\n   - Position, velocity, and acceleration\n   - Orientation (quaternion)\n   - Angular velocity and acceleration\n   - Tracking result status\n\n4. The `ITrackedDeviceServerDriver` interface (lines 2827-2862) is the base interface for tracked devices in a driver.\n\nLet me continue reading to understand more about the driver implementation and how to access IMU data:","partial":false},{"ts":1744499985849,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"headers/openvr_driver.h\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\headers\\\\openvr_driver.h\",\"reason\":\" (lines 3000-3500)\"}","partial":false},{"ts":1744500589706,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'headers/openvr_driver.h'] Result:\\n\\n<file><path>headers/openvr_driver.h</path>\\n<content lines=\\\"3000-3500\\\">\\n3000 | \\t\\t/** Called to get additional frame timing stats from driver.  Check m_nSize for versioning (new members will be added to end only). */\\r\\n3001 | \\t\\tvirtual void GetFrameTiming( DriverDirectMode_FrameTiming *pFrameTiming )\\r\\n3002 | \\t\\t{\\r\\n3003 | \\t\\t\\t/** VRCompositor_ReprojectionMotion_XXX flags get passed in, and since these overlap with VRCompositor_ThrottleMask, they need\\r\\n3004 | \\t\\t\\t* to be cleared out if this function isn't implemented; otherwise, those settings will get interpreted as throttling. */\\r\\n3005 | \\t\\t\\tpFrameTiming->m_nReprojectionFlags = 0;\\r\\n3006 | \\t\\t}\\r\\n3007 | \\t};\\r\\n3008 | \\r\\n3009 | \\tstatic const char *IVRDriverDirectModeComponent_Version = \\\"IVRDriverDirectModeComponent_009\\\";\\r\\n3010 | \\r\\n3011 | }\\r\\n3012 | \\r\\n3013 | // ivrcameracomponent.h\\r\\n3014 | \\r\\n3015 | namespace vr\\r\\n3016 | {\\r\\n3017 | \\t//-----------------------------------------------------------------------------\\r\\n3018 | \\t//-----------------------------------------------------------------------------\\r\\n3019 | \\tclass ICameraVideoSinkCallback\\r\\n3020 | \\t{\\r\\n3021 | \\tpublic:\\r\\n3022 | \\t\\tvirtual void OnCameraVideoSinkCallback() = 0;\\r\\n3023 | \\t};\\r\\n3024 | \\r\\n3025 | \\t// ----------------------------------------------------------------------------------------------\\r\\n3026 | \\t// Purpose: The camera on a single tracked device\\r\\n3027 | \\t// ----------------------------------------------------------------------------------------------\\r\\n3028 | \\tclass IVRCameraComponent\\r\\n3029 | \\t{\\r\\n3030 | \\tpublic:\\r\\n3031 | \\t\\t// ------------------------------------\\r\\n3032 | \\t\\t// Camera Methods\\r\\n3033 | \\t\\t// ------------------------------------\\r\\n3034 | \\t\\tvirtual bool GetCameraFrameDimensions( vr::ECameraVideoStreamFormat nVideoStreamFormat, uint32_t *pWidth, uint32_t *pHeight ) = 0;\\r\\n3035 | \\t\\tvirtual bool GetCameraFrameBufferingRequirements( int *pDefaultFrameQueueSize, uint32_t *pFrameBufferDataSize ) = 0;\\r\\n3036 | \\t\\tvirtual bool SetCameraFrameBuffering( int nFrameBufferCount, void **ppFrameBuffers, uint32_t nFrameBufferDataSize ) = 0;\\r\\n3037 | \\t\\tvirtual bool SetCameraVideoStreamFormat( vr::ECameraVideoStreamFormat nVideoStreamFormat ) = 0;\\r\\n3038 | \\t\\tvirtual vr::ECameraVideoStreamFormat GetCameraVideoStreamFormat() = 0;\\r\\n3039 | \\t\\tvirtual bool StartVideoStream() = 0;\\r\\n3040 | \\t\\tvirtual void StopVideoStream() = 0;\\r\\n3041 | \\t\\tvirtual bool IsVideoStreamActive( bool *pbPaused, float *pflElapsedTime ) = 0;\\r\\n3042 | \\t\\tvirtual const vr::CameraVideoStreamFrame_t *GetVideoStreamFrame() = 0;\\r\\n3043 | \\t\\tvirtual void ReleaseVideoStreamFrame( const vr::CameraVideoStreamFrame_t *pFrameImage ) = 0;\\r\\n3044 | \\t\\tvirtual bool SetAutoExposure( bool bEnable ) = 0;\\r\\n3045 | \\t\\tvirtual bool PauseVideoStream() = 0;\\r\\n3046 | \\t\\tvirtual bool ResumeVideoStream() = 0;\\r\\n3047 | \\t\\tvirtual bool GetCameraDistortion( uint32_t nCameraIndex, float flInputU, float flInputV, float *pflOutputU, float *pflOutputV ) = 0;\\r\\n3048 | \\t\\tvirtual bool GetCameraProjection( uint32_t nCameraIndex, vr::EVRTrackedCameraFrameType eFrameType, float flZNear, float flZFar, vr::HmdMatrix44_t *pProjection ) = 0;\\r\\n3049 | \\t\\tvirtual bool SetFrameRate( int nISPFrameRate, int nSensorFrameRate ) = 0;\\r\\n3050 | \\t\\tvirtual bool SetCameraVideoSinkCallback( vr::ICameraVideoSinkCallback *pCameraVideoSinkCallback ) = 0;\\r\\n3051 | \\t\\tvirtual bool GetCameraCompatibilityMode( vr::ECameraCompatibilityMode *pCameraCompatibilityMode ) = 0;\\r\\n3052 | \\t\\tvirtual bool SetCameraCompatibilityMode( vr::ECameraCompatibilityMode nCameraCompatibilityMode ) = 0;\\r\\n3053 | \\t\\tvirtual bool GetCameraFrameBounds( vr::EVRTrackedCameraFrameType eFrameType, uint32_t *pLeft, uint32_t *pTop, uint32_t *pWidth, uint32_t *pHeight ) = 0;\\r\\n3054 | \\t\\tvirtual bool GetCameraIntrinsics( uint32_t nCameraIndex, vr::EVRTrackedCameraFrameType eFrameType, HmdVector2_t *pFocalLength, HmdVector2_t *pCenter, vr::EVRDistortionFunctionType *peDistortionType, double rCoefficients[ k_unMaxDistortionFunctionParameters ] ) = 0;\\r\\n3055 | \\t};\\r\\n3056 | \\r\\n3057 | \\tstatic const char *IVRCameraComponent_Version = \\\"IVRCameraComponent_003\\\";\\r\\n3058 | }\\r\\n3059 | \\r\\n3060 | // itrackeddevicedriverprovider.h\\r\\n3061 | \\r\\n3062 | namespace vr\\r\\n3063 | {\\r\\n3064 | \\r\\n3065 | class ITrackedDeviceServerDriver;\\r\\n3066 | struct TrackedDeviceDriverInfo_t;\\r\\n3067 | struct DriverPose_t;\\r\\n3068 | \\r\\n3069 | /** This interface is provided by vrserver to allow the driver to notify\\r\\n3070 | * the system when something changes about a device. These changes must\\r\\n3071 | * not change the serial number or class of the device because those values\\r\\n3072 | * are permanently associated with the device's index. */\\r\\n3073 | class IVRDriverContext\\r\\n3074 | {\\r\\n3075 | public:\\r\\n3076 | \\t/** Returns the requested interface. If the interface was not available it will return NULL and fill\\r\\n3077 | \\t* out the error. */\\r\\n3078 | \\tvirtual void *GetGenericInterface( const char *pchInterfaceVersion, EVRInitError *peError = nullptr ) = 0;\\r\\n3079 | \\r\\n3080 | \\t/** Returns the property container handle for this driver */\\r\\n3081 | \\tvirtual DriverHandle_t GetDriverHandle() = 0;\\r\\n3082 | };\\r\\n3083 | \\r\\n3084 | \\r\\n3085 | /** This interface must be implemented in each driver. It will be loaded in vrserver.exe */\\r\\n3086 | class IServerTrackedDeviceProvider\\r\\n3087 | {\\r\\n3088 | public:\\r\\n3089 | \\t/** initializes the driver. This will be called before any other methods are called.\\r\\n3090 | \\t* If Init returns anything other than VRInitError_None the driver DLL will be unloaded.\\r\\n3091 | \\t*\\r\\n3092 | \\t* pDriverHost will never be NULL, and will always be a pointer to a IServerDriverHost interface\\r\\n3093 | \\t*\\r\\n3094 | \\t* pchUserDriverConfigDir - The absolute path of the directory where the driver should store user\\r\\n3095 | \\t*\\tconfig files.\\r\\n3096 | \\t* pchDriverInstallDir - The absolute path of the root directory for the driver.\\r\\n3097 | \\t*/\\r\\n3098 | \\tvirtual EVRInitError Init( IVRDriverContext *pDriverContext ) = 0;\\r\\n3099 | \\r\\n3100 | \\t/** cleans up the driver right before it is unloaded */\\r\\n3101 | \\tvirtual void Cleanup() = 0;\\r\\n3102 | \\r\\n3103 | \\t/** Returns the version of the ITrackedDeviceServerDriver interface used by this driver */\\r\\n3104 | \\tvirtual const char * const *GetInterfaceVersions() = 0;\\r\\n3105 | \\r\\n3106 | \\t/** Allows the driver do to some work in the main loop of the server. */\\r\\n3107 | \\tvirtual void RunFrame() = 0;\\r\\n3108 | \\r\\n3109 | \\r\\n3110 | \\t// ------------  Power State Functions ----------------------- //\\r\\n3111 | \\r\\n3112 | \\t/** Returns true if the driver wants to block Standby mode. */\\r\\n3113 | \\tvirtual bool ShouldBlockStandbyMode() = 0;\\r\\n3114 | \\r\\n3115 | \\t/** Called when the system is entering Standby mode. The driver should switch itself into whatever sort of low-power\\r\\n3116 | \\t* state it has. */\\r\\n3117 | \\tvirtual void EnterStandby() = 0;\\r\\n3118 | \\r\\n3119 | \\t/** Called when the system is leaving Standby mode. The driver should switch itself back to\\r\\n3120 | \\tfull operation. */\\r\\n3121 | \\tvirtual void LeaveStandby() = 0;\\r\\n3122 | \\r\\n3123 | };\\r\\n3124 | \\r\\n3125 | \\r\\n3126 | static const char *IServerTrackedDeviceProvider_Version = \\\"IServerTrackedDeviceProvider_004\\\";\\r\\n3127 | \\r\\n3128 | \\r\\n3129 | \\r\\n3130 | \\r\\n3131 | /** This interface must be implemented in each driver. It will be loaded in vrclient.dll */\\r\\n3132 | class IVRWatchdogProvider\\r\\n3133 | {\\r\\n3134 | public:\\r\\n3135 | \\t/** initializes the driver in watchdog mode. */\\r\\n3136 | \\tvirtual EVRInitError Init( IVRDriverContext *pDriverContext ) = 0;\\r\\n3137 | \\r\\n3138 | \\t/** cleans up the driver right before it is unloaded */\\r\\n3139 | \\tvirtual void Cleanup() = 0;\\r\\n3140 | };\\r\\n3141 | \\r\\n3142 | static const char *IVRWatchdogProvider_Version = \\\"IVRWatchdogProvider_001\\\";\\r\\n3143 | \\r\\n3144 | \\r\\n3145 | \\r\\n3146 | \\r\\n3147 | /** This is an optional interface drivers may implement. It will be loaded in vrcompositor.exe */\\r\\n3148 | class IVRCompositorPluginProvider\\r\\n3149 | {\\r\\n3150 | public:\\r\\n3151 | \\t/** initializes the driver when used to load compositor plugins */\\r\\n3152 | \\tvirtual EVRInitError Init( IVRDriverContext *pDriverContext ) = 0;\\r\\n3153 | \\r\\n3154 | \\t/** cleans up the driver right before it is unloaded */\\r\\n3155 | \\tvirtual void Cleanup() = 0;\\r\\n3156 | \\r\\n3157 | \\t/** Returns the versions of interfaces used by this driver */\\r\\n3158 | \\tvirtual const char * const *GetInterfaceVersions() = 0;\\r\\n3159 | \\r\\n3160 | \\t/** Requests a component interface of the driver for specific functionality. The driver should return NULL\\r\\n3161 | \\t* if the requested interface or version is not supported. */\\r\\n3162 | \\tvirtual void *GetComponent( const char *pchComponentNameAndVersion ) = 0;\\r\\n3163 | };\\r\\n3164 | \\r\\n3165 | static const char *IVRCompositorPluginProvider_Version = \\\"IVRCompositorPluginProvider_001\\\";\\r\\n3166 | \\r\\n3167 | }\\r\\n3168 | \\r\\n3169 | // ivrproperties.h\\r\\n3170 | \\r\\n3171 | #include <string>\\r\\n3172 | #include <vector>\\r\\n3173 | \\r\\n3174 | namespace vr\\r\\n3175 | {\\r\\n3176 | \\r\\n3177 | \\t/** This container is automatically created before a display redirect device is activated.\\r\\n3178 | \\t* Any properties in this container will be returned when that property is read from the HMD's\\r\\n3179 | \\t* property container. */\\r\\n3180 | \\tstatic const PropertyContainerHandle_t k_ulDisplayRedirectContainer = 0x600000003;\\r\\n3181 | \\r\\n3182 | \\tenum EPropertyWriteType\\r\\n3183 | \\t{\\r\\n3184 | \\t\\tPropertyWrite_Set = 0,\\r\\n3185 | \\t\\tPropertyWrite_Erase = 1,\\r\\n3186 | \\t\\tPropertyWrite_SetError = 2\\r\\n3187 | \\t};\\r\\n3188 | \\r\\n3189 | \\tstruct PropertyWrite_t\\r\\n3190 | \\t{\\r\\n3191 | \\t\\tETrackedDeviceProperty prop;\\r\\n3192 | \\t\\tEPropertyWriteType writeType;\\r\\n3193 | \\t\\tETrackedPropertyError eSetError;\\r\\n3194 | \\t\\tvoid *pvBuffer;\\r\\n3195 | \\t\\tuint32_t unBufferSize;\\r\\n3196 | \\t\\tPropertyTypeTag_t unTag;\\r\\n3197 | \\t\\tETrackedPropertyError eError;\\r\\n3198 | \\t};\\r\\n3199 | \\r\\n3200 | \\tstruct PropertyRead_t\\r\\n3201 | \\t{\\r\\n3202 | \\t\\tETrackedDeviceProperty prop;\\r\\n3203 | \\t\\tvoid *pvBuffer;\\r\\n3204 | \\t\\tuint32_t unBufferSize;\\r\\n3205 | \\t\\tPropertyTypeTag_t unTag;\\r\\n3206 | \\t\\tuint32_t unRequiredBufferSize;\\r\\n3207 | \\t\\tETrackedPropertyError eError;\\r\\n3208 | \\t};\\r\\n3209 | \\r\\n3210 | \\r\\n3211 | class IVRProperties\\r\\n3212 | {\\r\\n3213 | public:\\r\\n3214 | \\r\\n3215 | \\t/** Reads a set of properties atomically. See the PropertyReadBatch_t struct for more information. */\\r\\n3216 | \\tvirtual ETrackedPropertyError ReadPropertyBatch( PropertyContainerHandle_t ulContainerHandle, PropertyRead_t *pBatch, uint32_t unBatchEntryCount ) = 0;\\r\\n3217 | \\r\\n3218 | \\t/** Writes a set of properties atomically. See the PropertyWriteBatch_t struct for more information. */\\r\\n3219 | \\tvirtual ETrackedPropertyError WritePropertyBatch( PropertyContainerHandle_t ulContainerHandle, PropertyWrite_t *pBatch, uint32_t unBatchEntryCount ) = 0;\\r\\n3220 | \\r\\n3221 | \\t/** returns a string that corresponds with the specified property error. The string will be the name\\r\\n3222 | \\t* of the error enum value for all valid error codes */\\r\\n3223 | \\tvirtual const char *GetPropErrorNameFromEnum( ETrackedPropertyError error ) = 0;\\r\\n3224 | \\r\\n3225 | \\t/** Returns a container handle given a tracked device index */\\r\\n3226 | \\tvirtual PropertyContainerHandle_t TrackedDeviceToPropertyContainer( TrackedDeviceIndex_t nDevice ) = 0;\\r\\n3227 | };\\r\\n3228 | \\r\\n3229 | static const char * const IVRProperties_Version = \\\"IVRProperties_001\\\";\\r\\n3230 | \\r\\n3231 | class CVRPropertyHelpers\\r\\n3232 | {\\r\\n3233 | public:\\r\\n3234 | \\tCVRPropertyHelpers( IVRProperties * pProperties ) : m_pProperties( pProperties ) {}\\r\\n3235 | \\r\\n3236 | \\t/** Gets the typed property according to the caller's expected return type. */\\r\\n3237 | \\ttemplate <typename T>\\r\\n3238 | \\tT GetTypedProperty( vr::PropertyContainerHandle_t ulContainer, vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *peError );\\r\\n3239 | \\r\\n3240 | \\t/** Returns a scaler property. If the device index is not valid or the property value type does not match,\\r\\n3241 | \\t* this function will return false. */\\r\\n3242 | \\tbool GetBoolProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, ETrackedPropertyError *pError = 0L );\\r\\n3243 | \\tfloat GetFloatProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, ETrackedPropertyError *pError = 0L );\\r\\n3244 | \\tint32_t GetInt32Property( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, ETrackedPropertyError *pError = 0L );\\r\\n3245 | \\tuint64_t GetUint64Property( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, ETrackedPropertyError *pError = 0L );\\r\\n3246 | \\tHmdVector2_t GetVec2Property( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, ETrackedPropertyError *pError = 0L );\\r\\n3247 | \\tHmdVector3_t GetVec3Property( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, ETrackedPropertyError *pError = 0L );\\r\\n3248 | \\tHmdVector4_t GetVec4Property( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, ETrackedPropertyError *pError = 0L );\\r\\n3249 | \\tdouble GetDoubleProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, ETrackedPropertyError *pError = 0L );\\r\\n3250 | \\r\\n3251 | \\t/** Returns a single typed property. If the device index is not valid or the property is not a string type this function will\\r\\n3252 | \\t* return 0. Otherwise it returns the length of the number of bytes necessary to hold this string including the trailing\\r\\n3253 | \\t* null. Strings will always fit in buffers of k_unMaxPropertyStringSize characters. */\\r\\n3254 | \\tuint32_t GetProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, VR_OUT_STRING() void *pvBuffer, uint32_t unBufferSize, PropertyTypeTag_t *punTag, ETrackedPropertyError *pError = 0L );\\r\\n3255 | \\r\\n3256 | \\t/** Returns a string property. If the device index is not valid or the property is not a string type this function will\\r\\n3257 | \\t* return 0. Otherwise it returns the length of the number of bytes necessary to hold this string including the trailing\\r\\n3258 | \\t* null. Strings will always fit in buffers of k_unMaxPropertyStringSize characters. */\\r\\n3259 | \\tuint32_t GetStringProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, VR_OUT_STRING() char *pchValue, uint32_t unBufferSize, ETrackedPropertyError *pError = 0L );\\r\\n3260 | \\r\\n3261 | \\t/** Returns a string property as a std::string. If the device index is not valid or the property is not a string type this function will\\r\\n3262 | \\t* return an empty string. */\\r\\n3263 | \\tstd::string GetStringProperty( vr::PropertyContainerHandle_t ulContainer, vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *peError = nullptr );\\r\\n3264 | \\r\\n3265 | \\t/** Reads a std::vector of data from a property. */\\r\\n3266 | \\ttemplate< typename T>\\r\\n3267 | \\tETrackedPropertyError GetPropertyVector( PropertyContainerHandle_t ulContainer, ETrackedDeviceProperty prop, PropertyTypeTag_t unExpectedTag, std::vector<T> *pvecResults );\\r\\n3268 | \\r\\n3269 | \\t/** Sets a scaler property. The new value will be returned on any subsequent call to get this property in any process. */\\r\\n3270 | \\tETrackedPropertyError SetBoolProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, bool bNewValue );\\r\\n3271 | \\tETrackedPropertyError SetFloatProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, float fNewValue );\\r\\n3272 | \\tETrackedPropertyError SetInt32Property( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, int32_t nNewValue );\\r\\n3273 | \\tETrackedPropertyError SetUint64Property( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, uint64_t ulNewValue );\\r\\n3274 | \\tETrackedPropertyError SetVec2Property( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, const HmdVector2_t & vNewValue );\\r\\n3275 | \\tETrackedPropertyError SetVec3Property( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, const HmdVector3_t & vNewValue );\\r\\n3276 | \\tETrackedPropertyError SetVec4Property( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, const HmdVector4_t & vNewValue );\\r\\n3277 | \\tETrackedPropertyError SetDoubleProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, double vNewValue );\\r\\n3278 | \\r\\n3279 | \\t/** Sets a string property. The new value will be returned on any subsequent call to get this property in any process. */\\r\\n3280 | \\tETrackedPropertyError SetStringProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, const char *pchNewValue );\\r\\n3281 | \\r\\n3282 | \\t/** Sets a single typed property. The new value will be returned on any subsequent call to get this property in any process. */\\r\\n3283 | \\tETrackedPropertyError SetProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, void *pvNewValue, uint32_t unNewValueSize, PropertyTypeTag_t unTag );\\r\\n3284 | \\r\\n3285 | \\t/** Sets the error return value for a property. This value will be returned on all subsequent requests to get the property */\\r\\n3286 | \\tETrackedPropertyError SetPropertyError( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, ETrackedPropertyError eError );\\r\\n3287 | \\r\\n3288 | \\t/** Clears any value or error set for the property. */\\r\\n3289 | \\tETrackedPropertyError EraseProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop );\\r\\n3290 | \\r\\n3291 | \\t/* Turns a device index into a property container handle. */\\r\\n3292 | \\tPropertyContainerHandle_t TrackedDeviceToPropertyContainer( TrackedDeviceIndex_t nDevice ) { return m_pProperties->TrackedDeviceToPropertyContainer( nDevice );  }\\r\\n3293 | \\r\\n3294 | \\t/** Sets a std::vector of typed data to a property. */\\r\\n3295 | \\ttemplate< typename T>\\r\\n3296 | \\tETrackedPropertyError SetPropertyVector( PropertyContainerHandle_t ulContainer, ETrackedDeviceProperty prop, PropertyTypeTag_t unExpectedTag, std::vector<T> *vecProperties );\\r\\n3297 | \\r\\n3298 | \\t/** Returns true if the specified property is set on the specified container */\\r\\n3299 | \\tbool IsPropertySet( PropertyContainerHandle_t ulContainer, ETrackedDeviceProperty prop, ETrackedPropertyError *peError = nullptr );\\r\\n3300 | private:\\r\\n3301 | \\ttemplate<typename T>\\r\\n3302 | \\tT GetPropertyHelper( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, ETrackedPropertyError *pError, T bDefault, PropertyTypeTag_t unTypeTag );\\r\\n3303 | \\r\\n3304 | \\tIVRProperties *m_pProperties;\\r\\n3305 | };\\r\\n3306 | \\r\\n3307 | \\r\\n3308 | /** Returns a string property as a std::string. If the device index is not valid or the property is not a string type this function will\\r\\n3309 | * return an empty string. */\\r\\n3310 | template <>\\r\\n3311 | inline std::string CVRPropertyHelpers::GetTypedProperty( vr::PropertyContainerHandle_t ulContainer, vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *peError )\\r\\n3312 | {\\r\\n3313 | \\treturn GetStringProperty( ulContainer, prop, peError );\\r\\n3314 | }\\r\\n3315 | \\r\\n3316 | \\r\\n3317 | template <>\\r\\n3318 | inline bool CVRPropertyHelpers::GetTypedProperty( vr::PropertyContainerHandle_t ulContainer, vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *peError )\\r\\n3319 | {\\r\\n3320 | \\treturn GetBoolProperty( ulContainer, prop, peError );\\r\\n3321 | }\\r\\n3322 | \\r\\n3323 | \\r\\n3324 | template <>\\r\\n3325 | inline float CVRPropertyHelpers::GetTypedProperty( vr::PropertyContainerHandle_t ulContainer, vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *peError )\\r\\n3326 | {\\r\\n3327 | \\treturn GetFloatProperty( ulContainer, prop, peError );\\r\\n3328 | }\\r\\n3329 | \\r\\n3330 | \\r\\n3331 | template <>\\r\\n3332 | inline int32_t CVRPropertyHelpers::GetTypedProperty( vr::PropertyContainerHandle_t ulContainer, vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *peError )\\r\\n3333 | {\\r\\n3334 | \\treturn GetInt32Property( ulContainer, prop, peError );\\r\\n3335 | }\\r\\n3336 | \\r\\n3337 | \\r\\n3338 | template <>\\r\\n3339 | inline uint64_t CVRPropertyHelpers::GetTypedProperty( vr::PropertyContainerHandle_t ulContainer, vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *peError )\\r\\n3340 | {\\r\\n3341 | \\treturn GetUint64Property( ulContainer, prop, peError );\\r\\n3342 | }\\r\\n3343 | \\r\\n3344 | \\r\\n3345 | template <>\\r\\n3346 | inline HmdVector2_t CVRPropertyHelpers::GetTypedProperty( vr::PropertyContainerHandle_t ulContainer, vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *peError )\\r\\n3347 | {\\r\\n3348 | \\treturn GetVec2Property( ulContainer, prop, peError );\\r\\n3349 | }\\r\\n3350 | \\r\\n3351 | \\r\\n3352 | template <>\\r\\n3353 | inline HmdVector3_t CVRPropertyHelpers::GetTypedProperty( vr::PropertyContainerHandle_t ulContainer, vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *peError )\\r\\n3354 | {\\r\\n3355 | \\treturn GetVec3Property( ulContainer, prop, peError );\\r\\n3356 | }\\r\\n3357 | \\r\\n3358 | \\r\\n3359 | template <>\\r\\n3360 | inline HmdVector4_t CVRPropertyHelpers::GetTypedProperty( vr::PropertyContainerHandle_t ulContainer, vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *peError )\\r\\n3361 | {\\r\\n3362 | \\treturn GetVec4Property( ulContainer, prop, peError );\\r\\n3363 | }\\r\\n3364 | \\r\\n3365 | \\r\\n3366 | template <>\\r\\n3367 | inline double CVRPropertyHelpers::GetTypedProperty( vr::PropertyContainerHandle_t ulContainer, vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *peError )\\r\\n3368 | {\\r\\n3369 | \\treturn GetDoubleProperty( ulContainer, prop, peError );\\r\\n3370 | }\\r\\n3371 | \\r\\n3372 | \\r\\n3373 | inline uint32_t CVRPropertyHelpers::GetProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, VR_OUT_STRING() void *pvBuffer, uint32_t unBufferSize, PropertyTypeTag_t *punTag, ETrackedPropertyError *pError )\\r\\n3374 | {\\r\\n3375 | \\tPropertyRead_t batch;\\r\\n3376 | \\tbatch.prop = prop;\\r\\n3377 | \\tbatch.pvBuffer = pvBuffer;\\r\\n3378 | \\tbatch.unBufferSize = unBufferSize;\\r\\n3379 | \\r\\n3380 | \\tm_pProperties->ReadPropertyBatch( ulContainerHandle, &batch, 1 );\\r\\n3381 | \\r\\n3382 | \\tif ( pError )\\r\\n3383 | \\t{\\r\\n3384 | \\t\\t*pError = batch.eError;\\r\\n3385 | \\t}\\r\\n3386 | \\r\\n3387 | \\tif ( punTag )\\r\\n3388 | \\t{\\r\\n3389 | \\t\\t*punTag = batch.unTag;\\r\\n3390 | \\t}\\r\\n3391 | \\r\\n3392 | \\treturn batch.unRequiredBufferSize;\\r\\n3393 | }\\r\\n3394 | \\r\\n3395 | \\r\\n3396 | /** Sets a single typed property. The new value will be returned on any subsequent call to get this property in any process. */\\r\\n3397 | inline ETrackedPropertyError CVRPropertyHelpers::SetProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, void *pvNewValue, uint32_t unNewValueSize, PropertyTypeTag_t unTag )\\r\\n3398 | {\\r\\n3399 | \\tPropertyWrite_t batch;\\r\\n3400 | \\tbatch.writeType = PropertyWrite_Set;\\r\\n3401 | \\tbatch.prop = prop;\\r\\n3402 | \\tbatch.pvBuffer = pvNewValue;\\r\\n3403 | \\tbatch.unBufferSize = unNewValueSize;\\r\\n3404 | \\tbatch.unTag = unTag;\\r\\n3405 | \\r\\n3406 | \\tm_pProperties->WritePropertyBatch( ulContainerHandle, &batch, 1 );\\r\\n3407 | \\r\\n3408 | \\treturn batch.eError;\\r\\n3409 | }\\r\\n3410 | \\r\\n3411 | \\r\\n3412 | /** Returns a string property. If the device index is not valid or the property is not a string type this function will\\r\\n3413 | * return 0. Otherwise it returns the length of the number of bytes necessary to hold this string including the trailing\\r\\n3414 | * null. Strings will always fit in buffers of k_unMaxPropertyStringSize characters. */\\r\\n3415 | inline uint32_t CVRPropertyHelpers::GetStringProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, VR_OUT_STRING() char *pchValue, uint32_t unBufferSize, ETrackedPropertyError *pError )\\r\\n3416 | {\\r\\n3417 | \\tPropertyTypeTag_t unTag;\\r\\n3418 | \\tETrackedPropertyError error;\\r\\n3419 | \\tuint32_t unRequiredSize = GetProperty( ulContainerHandle, prop, pchValue, unBufferSize, &unTag, &error );\\r\\n3420 | \\tif ( unTag != k_unStringPropertyTag && error == TrackedProp_Success )\\r\\n3421 | \\t{\\r\\n3422 | \\t\\terror = TrackedProp_WrongDataType;\\r\\n3423 | \\t}\\r\\n3424 | \\r\\n3425 | \\tif ( pError )\\r\\n3426 | \\t{\\r\\n3427 | \\t\\t*pError = error;\\r\\n3428 | \\t}\\r\\n3429 | \\r\\n3430 | \\tif ( error != TrackedProp_Success )\\r\\n3431 | \\t{\\r\\n3432 | \\t\\tif ( pchValue && unBufferSize )\\r\\n3433 | \\t\\t{\\r\\n3434 | \\t\\t\\t*pchValue = '\\\\0';\\r\\n3435 | \\t\\t}\\r\\n3436 | \\t}\\r\\n3437 | \\r\\n3438 | \\treturn unRequiredSize;\\r\\n3439 | }\\r\\n3440 | \\r\\n3441 | \\r\\n3442 | /** Returns a string property as a std::string. If the device index is not valid or the property is not a string type this function will\\r\\n3443 | * return an empty string. */\\r\\n3444 | inline std::string CVRPropertyHelpers::GetStringProperty( vr::PropertyContainerHandle_t ulContainer, vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *peError )\\r\\n3445 | {\\r\\n3446 | \\tchar buf[1024];\\r\\n3447 | \\tvr::ETrackedPropertyError err;\\r\\n3448 | \\tuint32_t unRequiredBufferLen = GetStringProperty( ulContainer, prop, buf, sizeof(buf), &err );\\r\\n3449 | \\r\\n3450 | \\tstd::string sResult;\\r\\n3451 | \\r\\n3452 | \\tif ( err == TrackedProp_Success )\\r\\n3453 | \\t{\\r\\n3454 | \\t\\tsResult = buf;\\r\\n3455 | \\t}\\r\\n3456 | \\telse if ( err == TrackedProp_BufferTooSmall )\\r\\n3457 | \\t{\\r\\n3458 | \\t\\tchar *pchBuffer = new char[unRequiredBufferLen];\\r\\n3459 | \\t\\tunRequiredBufferLen = GetStringProperty( ulContainer, prop, pchBuffer, unRequiredBufferLen, &err );\\r\\n3460 | \\t\\tsResult = pchBuffer;\\r\\n3461 | \\t\\tdelete[] pchBuffer;\\r\\n3462 | \\t}\\r\\n3463 | \\r\\n3464 | \\tif ( peError )\\r\\n3465 | \\t{\\r\\n3466 | \\t\\t*peError = err;\\r\\n3467 | \\t}\\r\\n3468 | \\r\\n3469 | \\treturn sResult;\\r\\n3470 | }\\r\\n3471 | \\r\\n3472 | \\r\\n3473 | /** Sets a string property. The new value will be returned on any subsequent call to get this property in any process. */\\r\\n3474 | inline ETrackedPropertyError CVRPropertyHelpers::SetStringProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, const char *pchNewValue )\\r\\n3475 | {\\r\\n3476 | \\tif ( !pchNewValue )\\r\\n3477 | \\t\\treturn TrackedProp_InvalidOperation;\\r\\n3478 | \\r\\n3479 | \\t// this is strlen without the dependency on string.h\\r\\n3480 | \\tconst char *pchCurr = pchNewValue;\\r\\n3481 | \\twhile ( *pchCurr )\\r\\n3482 | \\t{\\r\\n3483 | \\t\\tpchCurr++;\\r\\n3484 | \\t}\\r\\n3485 | \\r\\n3486 | \\treturn SetProperty( ulContainerHandle, prop, (void *)pchNewValue, (uint32_t)(pchCurr - pchNewValue) + 1, k_unStringPropertyTag );\\r\\n3487 | }\\r\\n3488 | \\r\\n3489 | \\r\\n3490 | template<typename T>\\r\\n3491 | inline T CVRPropertyHelpers::GetPropertyHelper( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, ETrackedPropertyError *pError, T bDefault, PropertyTypeTag_t unTypeTag )\\r\\n3492 | {\\r\\n3493 | \\tT bValue;\\r\\n3494 | \\tETrackedPropertyError eError;\\r\\n3495 | \\tPropertyTypeTag_t unReadTag;\\r\\n3496 | \\tGetProperty( ulContainerHandle, prop, &bValue, sizeof( bValue ), &unReadTag, &eError );\\r\\n3497 | \\tif ( unReadTag != unTypeTag && eError == TrackedProp_Success )\\r\\n3498 | \\t{\\r\\n3499 | \\t\\teError = TrackedProp_WrongDataType;\\r\\n3500 | \\t};\\r\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\ndocs\\\\Driver_API_Documentation.md\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:29:49 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n59,500 (30%)\\n\\n# Current Cost\\n$0.28\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":349,\"cacheWrites\":68862,\"cacheReads\":0,\"cost\":0.26347950000000003}"},{"ts":1744500597861,"type":"say","say":"text","text":"I've found more important information about the OpenVR driver architecture:\n\n1. Lines 3085-3123 define the `IServerTrackedDeviceProvider` interface, which is the main entry point for a driver. This interface must be implemented by each driver and includes methods like:\n   - `Init`: Initializes the driver\n   - `Cleanup`: Cleans up the driver before unloading\n   - `RunFrame`: Allows the driver to do work in the main loop of the server\n\n2. Lines 2827-2862 define the `ITrackedDeviceServerDriver` interface, which represents a single tracked device in a driver. This includes methods like:\n   - `Activate`: Called before a device is returned to the application\n   - `Deactivate`: Called when the system is switching from this device to another\n   - `GetComponent`: Gets a component interface for device-specific functionality\n   - `GetPose`: Gets the current pose of the device\n\n3. Line 2851 shows the `GetComponent` method, which is used to get device-specific functionality. This is likely how we would expose our custom IMU data interface.\n\nNow I need to look at the Driver API Documentation to understand how to implement a custom driver that wraps the existing lighthouse driver and accesses raw IMU data.\n\nNow let's look at the Driver API Documentation to understand how to implement a custom driver:","partial":false},{"ts":1744500603945,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"docs/Driver_API_Documentation.md\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\docs\\\\Driver_API_Documentation.md\",\"reason\":\" (max 500 lines)\"}","partial":false},{"ts":1744500755018,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'docs/Driver_API_Documentation.md'] Result:\\n\\n<file><path>docs/Driver_API_Documentation.md</path>\\n<content lines=\\\"1-500\\\">\\n  1 | # OpenVR Driver Documentation\\r\\n  2 | \\r\\n  3 | - [OpenVR Driver Documentation](#openvr-driver-documentation)\\r\\n  4 |     - [About](#about)\\r\\n  5 |     - [Overview & Important points](#overview--important-points)\\r\\n  6 |         - [Using interfaces implemented by the runtime](#using-interfaces-implemented-by-the-runtime)\\r\\n  7 |         - [Import interfaces and functions](#import-interfaces-and-functions)\\r\\n  8 |     - [Driver Folder Structure](#driver-folder-structure)\\r\\n  9 |     - [Driver files](#driver-files)\\r\\n 10 |         - [driver.vrdrivermanifest](#drivervrdrivermanifest)\\r\\n 11 |         - [resources/driver.vrresources](#resourcesdrivervrresources)\\r\\n 12 |             - [Example](#example)\\r\\n 13 |         - [localization/localization.json](#localizationlocalizationjson)\\r\\n 14 |             - [Defining localization in one file](#defining-localization-in-one-file)\\r\\n 15 |             - [Defining localization in multiple files](#defining-localization-in-multiple-files)\\r\\n 16 |         - [resources/settings/default.vrsettings](#resourcessettingsdefaultvrsettings)\\r\\n 17 |             - [Example](#example)\\r\\n 18 |     - [Icons](#icons)\\r\\n 19 |         - [Setting icons](#setting-icons)\\r\\n 20 |         - [Updating Icons](#updating-icons)\\r\\n 21 |     - [Device Classes](#device-classes)\\r\\n 22 |         - [Controller roles](#controller-roles)\\r\\n 23 |         - [Trackers (Full body Tracking)](#trackers-full-body-tracking)\\r\\n 24 | - [Driver Structure](#driver-structure)\\r\\n 25 |     - [HmdDriverFactory](#hmddriverfactory)\\r\\n 26 |     - [IServerTrackedDeviceProvider](#iservertrackeddeviceprovider)\\r\\n 27 |         - [Example](#example)\\r\\n 28 |     - [ITrackedDeviceServerDriver](#itrackeddeviceserverdriver)\\r\\n 29 |         - [Device Components](#device-components)\\r\\n 30 |             - [IVRDisplayComponent](#ivrdisplaycomponent)\\r\\n 31 |             - [IVRDriverDirectModeComponent](#ivrdriverdirectmodecomponent)\\r\\n 32 |             - [IVRVirtualDisplay](#ivrvirtualdisplay)\\r\\n 33 |     - [IVRServerDriverHost](#ivrserverdriverhost)\\r\\n 34 |     - [IVRDriverLog](#ivrdriverlog)\\r\\n 35 |     - [IVRWatchdogProvider](#ivrwatchdogprovider)\\r\\n 36 |         - [The watchdog interface is deprecated and should no longer be used for new projects.](#the-watchdog-interface-is-deprecated-and-should-no-longer-be-used-for-new-projects)\\r\\n 37 |         - [IVRWatchdogHost](#ivrwatchdoghost)\\r\\n 38 |     - [Device Inputs](#device-inputs)\\r\\n 39 |         - [Input Profiles](#input-profiles)\\r\\n 40 |             - [Input sources](#input-sources)\\r\\n 41 |         - [Input Profile JSON](#input-profile-json)\\r\\n 42 |             - [Reserved input sources](#reserved-input-sources)\\r\\n 43 |     - [Binding Profiles](#binding-profiles)\\r\\n 44 |         - [Default Bindings](#default-bindings)\\r\\n 45 |     - [Driver Input](#driver-input)\\r\\n 46 |         - [Creating Components](#creating-components)\\r\\n 47 |         - [Updating Components](#updating-components)\\r\\n 48 |     - [Events](#events)\\r\\n 49 |         - [Haptic Events](#haptic-events)\\r\\n 50 |     - [Device Properties](#device-properties)\\r\\n 51 |         - [Implementing Properties](#implementing-properties)\\r\\n 52 |         - [IVRProperties](#ivrproperties)\\r\\n 53 |         - [CVRPropertyHelpers](#cvrpropertyhelpers)\\r\\n 54 |             - [Getting properties](#getting-properties)\\r\\n 55 |             - [Setting Properties](#setting-properties)\\r\\n 56 |             - [Property Utilities](#property-utilities)\\r\\n 57 |     - [IVRSettings](#ivrsettings)\\r\\n 58 |     - [IVRResources](#ivrresources)\\r\\n 59 |     - [IVRDriverSpatialAnchors](#ivrdriverspatialanchors)\\r\\n 60 |     - [Poses](#poses)\\r\\n 61 |     - [Skeletal Input](#skeletal-input)\\r\\n 62 |         - [Notes on hand tracking compatibility](#notes-on-hand-tracking-compatibility)\\r\\n 63 |         - [The Skeleton](#the-skeleton)\\r\\n 64 |         - [Units and Coordinate System](#units-and-coordinate-system)\\r\\n 65 |         - [Bone Structure](#bone-structure)\\r\\n 66 |             - [Notes on the skeleton](#notes-on-the-skeleton)\\r\\n 67 |         - [Using Skeletal Input](#using-skeletal-input)\\r\\n 68 |             - [Creating Hand Animations](#creating-hand-animations)\\r\\n 69 |     - [Application Compatibility](#application-compatibility)\\r\\n 70 |         - [Automatic Rebinding](#automatic-rebinding)\\r\\n 71 |             - [File Structure](#file-structure)\\r\\n 72 |             - [One-to-Many Remappings](#one-to-many-remappings)\\r\\n 73 |             - [Examples](#examples)\\r\\n 74 |         - [Emulating Devices in Bindings](#emulating-devices-in-bindings)\\r\\n 75 |             - [SteamVR Input and Legacy Input](#steamvr-input-and-legacy-input)\\r\\n 76 |             - [OpenXR](#openxr)\\r\\n 77 |         - [Legacy Binding Simulation](#legacy-binding-simulation)\\r\\n 78 |         - [Binding Duplication](#binding-duplication)\\r\\n 79 |         - [Emulateable Devices](#emulateable-devices)\\r\\n 80 |     - [Render Models](#render-models)\\r\\n 81 |     - [Chaperone](#chaperone)\\r\\n 82 |     - [Building & Development Environment](#building--development-environment)\\r\\n 83 |         - [Debugging SteamVR with Visual Studio](#debugging-steamvr-with-visual-studio)\\r\\n 84 | - [Further Examples](#further-examples)\\r\\n 85 | \\r\\n 86 | ## About\\r\\n 87 | \\r\\n 88 | OpenVR provides a driver interface for hardware to interact with SteamVR and OpenVR-supported applications.  \\r\\n 89 | The interface is **device-agnostic**: applications do not need to provide explicit support for your hardware, and so\\r\\n 90 | long as you conform to the OpenVR driver API, your devices will be supported in SteamVR games.\\r\\n 91 | \\r\\n 92 | It's important to note that OpenVR **does not** provide definitions for the functions it declares. These functions are\\r\\n 93 | implemented into SteamVR, or any other conformant OpenVR *runtime*.\\r\\n 94 | \\r\\n 95 | SteamVR is backwards compatible with previous versions of OpenVR. If OpenVR\\r\\n 96 | interfaces were to be updated, a driver or application developer need not update their software, as it is guaranteed to\\r\\n 97 | continue to be supported.\\r\\n 98 | \\r\\n 99 | The documentation provides an overview of common interfaces and use cases for setting up a driver.\\r\\n100 | \\r\\n101 | ## Overview & Important points\\r\\n102 | \\r\\n103 | The available interfaces in the OpenVR Driver API can be found\\r\\n104 | in [openvr/headers/openvr_driver.h](https://github.com/ValveSoftware/openvr/blob/master/headers/openvr_driver.h).\\r\\n105 | \\r\\n106 | Sample drivers can be found in `samples/drivers`.\\r\\n107 | \\r\\n108 | ### Using interfaces implemented by the runtime\\r\\n109 | \\r\\n110 | Some interfaces in the OpenVR Driver API are implemented already by the runtime. You **must not** implement\\r\\n111 | these interfaces yourself, but you **can** call the methods they contain. These interfaces include:\\r\\n112 | \\r\\n113 | * `IVRSettings`\\r\\n114 | * `IVRProperties`\\r\\n115 | * `CVRPropertyHelpers`\\r\\n116 | * `CVRHiddenAreaHelpers`\\r\\n117 | * `IVRDriverLog`\\r\\n118 | * `IVRServerDriverHost`\\r\\n119 | * `IVRWatchdogHost`\\r\\n120 | * `IVRCompositorDriverHost`\\r\\n121 | * `DriverHandle_t`\\r\\n122 | * `IVRDriverManager`\\r\\n123 | * `IVRResources`\\r\\n124 | * `IVRDriverInput`\\r\\n125 | * `IVRIOBuffer`\\r\\n126 | * `IVRDriverSpatialAnchors`\\r\\n127 | \\r\\n128 | The OpenVR Driver API provides utility functions to retrieve pointers to these objects. They are functions of\\r\\n129 | the same name as the interface, without the `I` prefix. For example: `vr::VRServerDriverHost()` returns a valid pointer\\r\\n130 | to an `IVRServerDriverHost` implemented in the runtime.\\r\\n131 | \\r\\n132 | ```c++\\r\\n133 | IVRDriverLog* log = vr::VRDriverLog();\\r\\n134 | IVRSettings* settings = vr::VRSettings();\\r\\n135 | \\r\\n136 | // Some of these methods return pointers to wrappers around the origin classes to help simplify them\\r\\n137 | CVRPropertyHelpers* properties = vr::VRProperties();\\r\\n138 | ```\\r\\n139 | \\r\\n140 | ### Import interfaces and functions\\r\\n141 | \\r\\n142 | This section provides a short introduction to what the code that you will be writing for your driver will look like.\\r\\n143 | This section **does not** provide documentation on the interfaces, but a brief overview of what you'll be writing will\\r\\n144 | look like.\\r\\n145 | \\r\\n146 | The flow typically looks like this. Documentation on each of these classes and methods are outlined elsewhere.\\r\\n147 | \\r\\n148 | ```mermaid\\r\\n149 | graph TD;\\r\\n150 |     A[HmdDriverFactory]-->B[IServerTrackedDeviceProvider];\\r\\n151 |     B-->C[\\\"IServerTrackedDeviceProvider::Init\\\"];\\r\\n152 |     B-->D[\\\"IServerTrackedDeviceProvider::RunFrame\\\"];\\r\\n153 | \\r\\n154 |     C--\\\"VRServerDriverHost()->TrackedDeviceAdded(...)\\\"-->E[\\\"ITrackedDeviceServerDriver::Activate\\\"];\\r\\n155 |     D-->G[\\\"VRServerDriverHost()->PollNextEvent(...)\\\"];\\r\\n156 | \\r\\n157 |     E-->H[\\\"VRProperties()->SetXProperty(...)\\\"];\\r\\n158 |     E-->I[\\\"VRDriverInput()->CreateXComponent(...)\\\"];\\r\\n159 | \\r\\n160 |     C-->M[\\\"MyDeviceDriver::MyInputThread\\\"];\\r\\n161 |     M-->N[\\\"VRDriverInput()->UpdateXComponent(...)\\\"];\\r\\n162 | \\r\\n163 |     A-->K[IVRWatchdogProvider];\\r\\n164 |     K-->L[\\\"VRWatchdogHost()->WatchdogWakeUp(...)\\\"];\\r\\n165 | ```\\r\\n166 | \\r\\n167 | ## Driver Folder Structure\\r\\n168 | \\r\\n169 |     <driver_name>\\r\\n170 |     ├── bin                                          # Contains all binary files\\r\\n171 |     │   ├── win64   \\r\\n172 |     │   │   └── driver_<driver_name>.dll             # Driver binary. The name MUST follow the driver_<driver_name>.dll pattern in order for it to be loaded\\r\\n173 |     │   └── ...\\r\\n174 |     ├── resources                                    # Contains all resource files\\r\\n175 |     │   ├── icons\\r\\n176 |     │   │   ├── <my_device_status>.png               # Device status & binding icons.\\r\\n177 |     │   │   └── ...\\r\\n178 |     │   ├── input\\r\\n179 |     │   │   ├── <my_controller>_profile.json         # Input profile for device\\r\\n180 |     │   │   └── legacy_binding_<my_controller>.json  # Legacy binding file for your device\\r\\n181 |     │   ├── localization\\r\\n182 |     │   │   ├── localization.json                    # Localized strings that will appear in places such as the bindings configuration interface.\\r\\n183 |     │   │   └── locatization_<lang>.json             # Optional: specify localization languages in different files \\r\\n184 |     │   ├── settings\\r\\n185 |     │   │   └── default.vrsettings                   # Default Driver settings\\r\\n186 |     │   └── driver.vrresources                       # Defines resources for the driver's devices, such as icons\\r\\n187 |     └── driver.vrdrivermanifest                      # Manifest file that identifies the location of the driver binaries (relative to the manifest file) and several other attributes of the driver.\\r\\n188 | \\r\\n189 | <br />\\r\\n190 | \\r\\n191 | `<driver_name>` **should** be a non-whitespace, lowercase string giving the name of your driver.\\r\\n192 | \\r\\n193 | `<driver_name>` **must** be the same between the name of the driver binary file, and the root folder name.\\r\\n194 | \\r\\n195 | - Inconsistent naming **will** result in SteamVR returning `VRInitError_Init_FileNotFound` when attempting to load the\\r\\n196 |   driver.\\r\\n197 | \\r\\n198 | ## Driver files\\r\\n199 | \\r\\n200 | SteamVR uses the JSON format for many of its configuration files. Files containing invalid JSON (such as trailing\\r\\n201 | commas), **will**\\r\\n202 | cause the runtime to fail to load the files.\\r\\n203 | \\r\\n204 | ### driver.vrdrivermanifest\\r\\n205 | \\r\\n206 | The `driver.vrdrivermanifest` is a **required** file that lives in the **root** of the driver folder.\\r\\n207 | \\r\\n208 | It contains information relating to attributes of your driver.\\r\\n209 | \\r\\n210 | * `name` - The globally-unique name of the driver. The name **must** match the root folder name (the folder that\\r\\n211 |   contains the `driver.vrdrivermanifest`). The driver DLL(s) **must** also be called `driver_<name>.dll` (or the\\r\\n212 |   equivalent\\r\\n213 |   extension for other platforms).\\r\\n214 | * `directory` - The name of the directory that contains the rest of the driver files. If this is a relative path it is\\r\\n215 |   relative to the directory that contains `driver.vrdrivermanifest`. Defaults to the full path contains\\r\\n216 |   `driver.vrdrivermanifest`.\\r\\n217 | * `alwaysActivate` - If this is true this driver will be activated even if the active HMD is from another driver.\\r\\n218 |   Defaults to false.\\r\\n219 |     - A driver that exposes *only* controllers, **should** set this to true if it is known that the HMD may be from a\\r\\n220 |       different tracking system.\\r\\n221 | * `resourceOnly` - The driver contains a `resources` directory, but not any binaries. This is used for\\r\\n222 |   *lighthouse-tracked devices*, which define driver behaviour and inputs through a JSON file. See `The JSON File` for\\r\\n223 |   information.\\r\\n224 | * `hmd_presence` - This is an array of strings that identify the USB VID and PID combinations that indicate an HMD from\\r\\n225 |   this driver is probably present. Each entry **should** be hex values in this form:\\r\\n226 |     * `28DE.*` - Any USB device with a VID of 28DE will cause OpenVR to return true from `VR_IsHmdPresent`.\\r\\n227 |     * `28DE.2000` - Any USE device with a VID of 28DE and a PID of 2000 will cause OpenVR to return true\\r\\n228 |       from `VR_IsHmdPresent`.\\r\\n229 |     * `*.*` - The runtime **will** always return true from `VR_IsHmdPresent` if this driver is installed.\\r\\n230 | * `other_presence` - An array of strings in the same format as hmd_presence that indicates that there is a non-HMD\\r\\n231 |   device plugged in.\\r\\n232 | * `redirectsDisplay` - Whether the device implements `vr::TrackedDeviceClass_DisplayRedirect` devices.\\r\\n233 |   See [IVRVirtualDisplay](#ivrvirtualdisplay) for more details.\\r\\n234 | * `prefersUpperDeviceIndices` - Whether the device should be activated with a higher index. This will make it a lower\\r\\n235 |   priority for being set in an active role. Defaults to false.\\r\\n236 | * `spatialAnchorsSupport` - Whether the device supports [Spatial Anchors](#ivrdriverspatialanchors). Defaults to false.\\r\\n237 |   Without this, SteamVR **will** short-circuit anchor requests from applications and provide a generic descriptor that\\r\\n238 |   does not have any of the advantages of true spatial anchors.\\r\\n239 | \\r\\n240 | The sample `driver.vrdrivermanifest` looks like this:\\r\\n241 | \\r\\n242 | ```json\\r\\n243 | {\\r\\n244 |   \\\"alwaysActivate\\\": false,\\r\\n245 |   \\\"name\\\": \\\"barebones\\\",\\r\\n246 |   \\\"directory\\\": \\\"\\\",\\r\\n247 |   \\\"resourceOnly\\\": false,\\r\\n248 |   \\\"hmd_presence\\\": [\\r\\n249 |     \\\"*.*\\\"\\r\\n250 |   ]\\r\\n251 | }\\r\\n252 | ```\\r\\n253 | \\r\\n254 | See `samples/drivers/barebones` for a full example.\\r\\n255 | \\r\\n256 | ### resources/driver.vrresources\\r\\n257 | \\r\\n258 | The `driver.vrresources` file is an optional file that lives in the `resources/` folder.\\r\\n259 | \\r\\n260 | It contains information relating to the external resources of your driver such as icons.\\r\\n261 | These icons are displayed in the SteamVR monitor window while SteamVR is running\\r\\n262 | and convey icon-representations of the current status of your devices.\\r\\n263 | \\r\\n264 | See [Icons](#icons) for how these icons should be formatted.\\r\\n265 | \\r\\n266 | `driver.vrresources` contains the following keys:\\r\\n267 | \\r\\n268 | * `jsonid` - Required. The value of this **must** be `vrresources` for this file.\\r\\n269 | * `statusicons` - Optional. Used to define icons for specific device types\\r\\n270 |     * `<model_number>` - The `Prop_ModelNumber_String` of the device you want to define icons for.\\r\\n271 |       See [Device Properties](#Device-Properties) for setting this property.\\r\\n272 |         * `<icon_name>` - The name of the icon to provide the path to. A list of possible keys for the names of icons\\r\\n273 |           are listed in [Setting Icons](#setting-icons).\\r\\n274 |             * Values of `<icon_name>` represent the path to an image file. File paths **can** use the `{<driver_name>}`\\r\\n275 |               wildcard format to match the root path to the driver. For\\r\\n276 |               example: `{my_driver}/resources/icons/my_image.png`.\\r\\n277 |             * See [Icons](#icons) for more information on how the icons should be formatted.\\r\\n278 |             * If a key is not specified, the `{system}/icons/invalid_status.png` icon **will** be used.\\r\\n279 |         * `Alias` - a reserved key for chaining through different model number icons (see example).\\r\\n280 |             * Icon name keys that are not found in the original section will chase through to the section specified by\\r\\n281 |               the value of the `Alias` key.\\r\\n282 |             * This is useful for different model numbers that might have the same icons for some images, but not others,\\r\\n283 |               and this allows the driver to avoid duplication by providing a \\\"common\\\" icon section.\\r\\n284 | \\r\\n285 | If `Prop_ModelNumber_String` is not matched, a fallback considers the following child keys of `statusicons`:\\r\\n286 | \\r\\n287 | * `HMD` - Considered for driver devices of class `TrackedDeviceClass_HMD`. See [Device Classes](#device-classes) for\\r\\n288 |   more\\r\\n289 |   information.\\r\\n290 | * `<Left/Right>Controller` - Considered for driver devices of class `TrackedDeviceClass_Controller`.\\r\\n291 |   See [Device Classes](#device-classes) for more information.\\r\\n292 |     - If `<Left/Right>` is omitted, a fallback to `Controller` is considered. However, this means that the user won't be\\r\\n293 |       able to identify which icon represents the left/right hand.\\r\\n294 | * `GenericTracker` - Considered for driver devices of class `TrackedDeviceClass_GenericTracker`.\\r\\n295 |   See [Device Classes](#device-classes) for more information.\\r\\n296 | * `TrackingReference` - Considered for driver devices of class `TrackedDeviceClass_TrackingReference`.\\r\\n297 |   See [Device Classes](#device-classes) for more information.\\r\\n298 | \\r\\n299 | If these are not matched, the runtime **will** fallback to generic icons specified under these same keys\\r\\n300 | in `system.vrresources`.\\r\\n301 | \\r\\n302 | #### Example\\r\\n303 | \\r\\n304 | ```json\\r\\n305 | {\\r\\n306 |   \\\"jsonid\\\": \\\"vrresources\\\",\\r\\n307 |   \\\"statusicons\\\": {\\r\\n308 |     \\\"HMD\\\": {\\r\\n309 |       \\\"Prop_NamedIconPathDeviceOff_String\\\": \\\"{sample}/icons/headset_sample_status_off.png\\\",\\r\\n310 |       \\\"Prop_NamedIconPathDeviceSearching_String\\\": \\\"{sample}/icons/headset_sample_status_searching.gif\\\",\\r\\n311 |       \\\"Prop_NamedIconPathDeviceSearchingAlert_String\\\": \\\"{sample}/icons/headset_sample_status_searching_alert.gif\\\",\\r\\n312 |       \\\"Prop_NamedIconPathDeviceReady_String\\\": \\\"{sample}/icons/headset_sample_status_ready.png\\\",\\r\\n313 |       \\\"Prop_NamedIconPathDeviceReadyAlert_String\\\": \\\"{sample}/icons/headset_sample_status_ready_alert.png\\\",\\r\\n314 |       \\\"Prop_NamedIconPathDeviceNotReady_String\\\": \\\"{sample}/icons/headset_sample_status_error.png\\\",\\r\\n315 |       \\\"Prop_NamedIconPathDeviceStandby_String\\\": \\\"{sample}/icons/headset_sample_status_standby.png\\\",\\r\\n316 |       \\\"Prop_NamedIconPathDeviceAlertLow_String\\\": \\\"{sample}/icons/headset_sample_status_ready_low.png\\\"\\r\\n317 |     },\\r\\n318 |     \\\"Model-v Defaults\\\": {\\r\\n319 |       \\\"Prop_NamedIconPathDeviceOff_String\\\": \\\"{sample}/icons/headset_sample_status_off.png\\\",\\r\\n320 |       \\\"Prop_NamedIconPathDeviceSearching_String\\\": \\\"Prop_NamedIconPathDeviceOff_String\\\",\\r\\n321 |       \\\"Prop_NamedIconPathDeviceSearchingAlert_String\\\": \\\"Prop_NamedIconPathDeviceOff_String\\\",\\r\\n322 |       \\\"Prop_NamedIconPathDeviceReady_String\\\": \\\"Prop_NamedIconPathDeviceOff_String\\\",\\r\\n323 |       \\\"Prop_NamedIconPathDeviceReadyAlert_String\\\": \\\"Prop_NamedIconPathDeviceOff_String\\\",\\r\\n324 |       \\\"Prop_NamedIconPathDeviceNotReady_String\\\": \\\"Prop_NamedIconPathDeviceOff_String\\\",\\r\\n325 |       \\\"Prop_NamedIconPathDeviceStandby_String\\\": \\\"Prop_NamedIconPathDeviceOff_String\\\",\\r\\n326 |       \\\"Prop_NamedIconPathDeviceAlertLow_String\\\": \\\"Prop_NamedIconPathDeviceOff_String\\\"\\r\\n327 |     },\\r\\n328 |     \\\"Model-v1.0\\\": {\\r\\n329 |       \\\"Alias\\\": \\\"Model-v Defaults\\\",\\r\\n330 |       \\\"Prop_NamedIconPathDeviceAlertLow_String\\\": \\\"{sample}/icons/headset_model1_alertlow.png\\\"\\r\\n331 |     },\\r\\n332 |     \\\"Model-v2.0\\\": {\\r\\n333 |       \\\"Alias\\\": \\\"Model-v1.0\\\",\\r\\n334 |       \\\"Prop_NamedIconPathDeviceAlertLow_String\\\": \\\"{sample}/icons/headset_model2_alertlow.png\\\"\\r\\n335 |     },\\r\\n336 |     \\\"LeftController\\\": {\\r\\n337 |       \\\"Prop_NamedIconPathDeviceOff_String\\\": \\\"{sample}/icons/controller_status_off.png\\\",\\r\\n338 |       \\\"Prop_NamedIconPathDeviceSearching_String\\\": \\\"{sample}/icons/controller_status_searching.gif\\\",\\r\\n339 |       \\\"Prop_NamedIconPathDeviceSearchingAlert_String\\\": \\\"{sample}/icons/controller_status_searching_alert.gif\\\",\\r\\n340 |       \\\"Prop_NamedIconPathDeviceReady_String\\\": \\\"{sample}/icons/controller_status_ready.png\\\",\\r\\n341 |       \\\"Prop_NamedIconPathDeviceReadyAlert_String\\\": \\\"{sample}/icons/controller_status_ready_alert.png\\\",\\r\\n342 |       \\\"Prop_NamedIconPathDeviceNotReady_String\\\": \\\"{sample}/icons/controller_status_error.png\\\",\\r\\n343 |       \\\"Prop_NamedIconPathDeviceStandby_String\\\": \\\"{sample}/icons/controller_status_standby.png\\\",\\r\\n344 |       \\\"Prop_NamedIconPathDeviceAlertLow_String\\\": \\\"{sample}/icons/controller_status_ready_low.png\\\"\\r\\n345 |     },\\r\\n346 |     \\\"RightController\\\": {\\r\\n347 |       \\\"Prop_NamedIconPathDeviceOff_String\\\": \\\"{sample}/icons/controller_status_off.png\\\",\\r\\n348 |       \\\"Prop_NamedIconPathDeviceSearching_String\\\": \\\"{sample}/icons/controller_status_searching.gif\\\",\\r\\n349 |       \\\"Prop_NamedIconPathDeviceSearchingAlert_String\\\": \\\"{sample}/icons/controller_status_searching_alert.gif\\\",\\r\\n350 |       \\\"Prop_NamedIconPathDeviceReady_String\\\": \\\"{sample}/icons/controller_status_ready.png\\\",\\r\\n351 |       \\\"Prop_NamedIconPathDeviceReadyAlert_String\\\": \\\"{sample}/icons/controller_status_ready_alert.png\\\",\\r\\n352 |       \\\"Prop_NamedIconPathDeviceNotReady_String\\\": \\\"{sample}/icons/controller_status_error.png\\\",\\r\\n353 |       \\\"Prop_NamedIconPathDeviceStandby_String\\\": \\\"{sample}/icons/controller_status_standby.png\\\",\\r\\n354 |       \\\"Prop_NamedIconPathDeviceAlertLow_String\\\": \\\"{sample}/icons/controller_status_ready_low.png\\\"\\r\\n355 |     }\\r\\n356 |   }\\r\\n357 | }\\r\\n358 | ```\\r\\n359 | \\r\\n360 | ### localization/localization.json\\r\\n361 | \\r\\n362 | The localization JSON file specifies localization information for the device.\\r\\n363 | \\r\\n364 | Drivers **can** either choose to create new files *for each* localized version, or define them all\\r\\n365 | in `localization/localization.json`\\r\\n366 | \\r\\n367 | This file is also used for providing *user-friendly* names for the devices. For\\r\\n368 | example, `Prop_RegisteredDeviceType_String` for the Index Controllers are `knuckles`. These are then localized\\r\\n369 | in English to `Index Controller`.\\r\\n370 | \\r\\n371 | The keys **can** define localized versions for whatever is exported from your driver through its visible properties (\\r\\n372 | e.g. `Prop_RegisteredDeviceType_String`).\\r\\n373 | \\r\\n374 | #### Defining localization in one file\\r\\n375 | \\r\\n376 | `localization/localization.json` **must** contain a JSON-formatted array, containing objects for each localized version.\\r\\n377 | This object **must** contain:\\r\\n378 | \\r\\n379 | * `language_tag`: a recognized language tag, e.g `en_US`.\\r\\n380 | \\r\\n381 | And any strings the driver exports that the driver wishes to be localized.\\r\\n382 | \\r\\n383 | ```json\\r\\n384 | [\\r\\n385 |   {\\r\\n386 |     \\\"language_tag\\\": \\\"en_US\\\",\\r\\n387 |     \\\"knuckles\\\": \\\"Index Controller\\\",\\r\\n388 |     \\\"knuckles_ev1\\\": \\\"Knuckles (EV1) Controller\\\",\\r\\n389 |     \\\"/input/a\\\": \\\"A Button\\\",\\r\\n390 |     \\\"/input/b\\\": \\\"B Button\\\",\\r\\n391 |     \\\"/input/pinch\\\": \\\"Pinch Gesture\\\",\\r\\n392 |     \\\"/input/finger/index\\\": \\\"Index Finger\\\",\\r\\n393 |     \\\"/input/finger/middle\\\": \\\"Middle Finger\\\",\\r\\n394 |     \\\"/input/finger/ring\\\": \\\"Ring Finger\\\",\\r\\n395 |     \\\"/input/finger/pinky\\\": \\\"Pinky Finger\\\",\\r\\n396 |     \\\"/input/thumbstick\\\": \\\"Thumb Stick\\\"\\r\\n397 |   }\\r\\n398 | ]\\r\\n399 | ```\\r\\n400 | \\r\\n401 | #### Defining localization in multiple files\\r\\n402 | \\r\\n403 | `localization/localization.json` **must** contain a JSON-formatted object, containing language tag keys for each\\r\\n404 | localized version.\\r\\n405 | \\r\\n406 | ```json\\r\\n407 | {\\r\\n408 |   \\\"en_US\\\": \\\"{<driver_name>}/localization/localization_en_us.json\\\"\\r\\n409 | }\\r\\n410 | ```\\r\\n411 | \\r\\n412 | Where `<driver_name>` is the name of the driver. This then expands to an absolute path which the runtime can then load.\\r\\n413 | \\r\\n414 | Each individual file linked to then **must** be a JSON-formatted object.\\r\\n415 | This object **must** contain one key:\\r\\n416 | \\r\\n417 | * `language_tag`: a recognized language tag, e.g `en_us`\\r\\n418 | \\r\\n419 | ```json\\r\\n420 | {\\r\\n421 |   \\\"language_tag\\\": \\\"en_US\\\",\\r\\n422 |   \\\"knuckles\\\": \\\"Index Controller\\\",\\r\\n423 |   \\\"knuckles_ev1\\\": \\\"Knuckles (EV1) Controller\\\",\\r\\n424 |   \\\"/input/a\\\": \\\"A Button\\\",\\r\\n425 |   \\\"/input/b\\\": \\\"B Button\\\",\\r\\n426 |   \\\"/input/pinch\\\": \\\"Pinch Gesture\\\",\\r\\n427 |   \\\"/input/finger/index\\\": \\\"Index Finger\\\",\\r\\n428 |   \\\"/input/finger/middle\\\": \\\"Middle Finger\\\",\\r\\n429 |   \\\"/input/finger/ring\\\": \\\"Ring Finger\\\",\\r\\n430 |   \\\"/input/finger/pinky\\\": \\\"Pinky Finger\\\",\\r\\n431 |   \\\"/input/thumbstick\\\": \\\"Thumb Stick\\\"\\r\\n432 | }\\r\\n433 | ```\\r\\n434 | \\r\\n435 | ### resources/settings/default.vrsettings\\r\\n436 | \\r\\n437 | The `default.vrsettings` file provides default settings values for the driver. The file **should not** be modified by\\r\\n438 | users and should only provide default driver setting values which can then later be configured using the \\r\\n439 | [IVRSettings](#ivrsettings) interface. `IVRSettings` writes updated setting values to `steamvr.vrsettings`.\\r\\n440 | \\r\\n441 | Drivers **should** provide a `default.vrsettings` file to ship with the driver, which **must** be located\\r\\n442 | in `<driver_name>/resources/settings/default.vrsettings`. This file provides a default set of settings which will be\\r\\n443 | used if a setting is not found in `steamvr.vrsettings`.\\r\\n444 | \\r\\n445 | Settings are grouped in driver-defined sections. These sections contain keys and associated setting values. Values can\\r\\n446 | be strings (maximum 4096 characters), floats, integers, or booleans.\\r\\n447 | \\r\\n448 | Drivers **should** be careful when choosing names for sections, as they are global and not namespaced to a specific\\r\\n449 | driver. Drivers **should** prefix their sections with their name to avoid these collisions.\\r\\n450 | \\r\\n451 | A driver **should** specify at least one _section_ (JSON object in the root of the file), with the key\\r\\n452 | name `driver_<my_driver_name>`.\\r\\n453 | \\r\\n454 | While the driver can add any custom keys in this section, there are some keys that are reserved for use by the runtime:\\r\\n455 | \\r\\n456 | * `enable` - A boolean value that determines whether the driver is enabled or not.\\r\\n457 |     * This is a special value, and can be modified by the user through the SteamVR settings\\r\\n458 |       UI (`SteamVR Settings > Startup/Shutdown > Manage addons`).\\r\\n459 |     * This is defaulted to `true` if not specified.\\r\\n460 | * `loadPriority` - An integer value that determines the order in which to load drivers.\\r\\n461 |     * The order of priority is descending (drivers with higher integer `loadPriority` values will be loaded first).\\r\\n462 |     * This is defaulted to `0` if not specified.\\r\\n463 |     * All drivers that ship with SteamVR have a `loadPriority` of `0`.\\r\\n464 | * `blocked_by_safe_mode` - A boolean value that determines whether the driver is blocked from loading when SteamVR is in\\r\\n465 |   safe mode.\\r\\n466 |     * This is defaulted to `false` if not specified. This **should** be set to false (so the driver is blocked by safe\\r\\n467 |       mode) for 3rd party drivers. Having this value set to `true` will mean if the driver is crashing on startup, the\\r\\n468 |       user will be unable to use SteamVR without uninstalling the driver.\\r\\n469 | \\r\\n470 | #### Example\\r\\n471 | \\r\\n472 | ```json\\r\\n473 | {\\r\\n474 |   \\\"driver_mydriver\\\": {\\r\\n475 |     \\\"enable\\\": true,\\r\\n476 |     \\\"loadPriority\\\": 100,\\r\\n477 |     \\\"blocked_by_safe_mode\\\": false,\\r\\n478 |     \\\"my_custom_setting\\\": \\\"my_custom_value\\\"\\r\\n479 |   },\\r\\n480 |   \\\"driver_mydriver_customsettings\\\": {\\r\\n481 |     \\\"my_custom_setting2\\\": \\\"my_custom_value2\\\"\\r\\n482 |   }\\r\\n483 | }\\r\\n484 | ```\\r\\n485 | \\r\\n486 | ## Icons\\r\\n487 | \\r\\n488 | If an icon is to be displayed in SteamVR, it **must** be one of the following sizes,\\r\\n489 | depending on what type of device it is:\\r\\n490 | \\r\\n491 | * HMD: 50x32 or 100x64 (see below) png/gif\\r\\n492 | * Other: 32x32 or 64x64 (see below) png/gif\\r\\n493 | \\r\\n494 | Append `@2x` to the end of the file name to have a 100x64 HMD icon or 64x64 device icon.\\r\\n495 | Otherwise, a 50x32 or 32x32 icon size **will** be used.\\r\\n496 | \\r\\n497 | For example:\\r\\n498 | \\r\\n499 | * `my_hmd_icon.png` - 50x32 icon **must** be used.\\r\\n500 | * `my_hmd_icon@2x.png` - 100x64 icon **must** be used.\\r\\n</content>\\n<notice>Showing only 500 of 3733 total lines. Use start_line and end_line if you need to read more</notice>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\ndocs\\\\Driver_API_Documentation.md\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:32:35 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n69,215 (35%)\\n\\n# Current Cost\\n$0.55\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":131,\"cacheWrites\":9699,\"cacheReads\":68862,\"cost\":0.05900685}"},{"ts":1744500758500,"type":"say","say":"text","text":"The Driver API Documentation provides a good overview of how to implement an OpenVR driver. Let me continue reading more of this documentation to understand how to implement a custom driver that can access raw IMU data when optical tracking is lost.\n\nLet me continue reading the Driver API Documentation to understand more about the driver structure and implementation:","partial":false},{"ts":1744500759968,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"docs/Driver_API_Documentation.md\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\docs\\\\Driver_API_Documentation.md\",\"reason\":\" (lines 500-1000)\"}","partial":false},{"ts":1744500768635,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'docs/Driver_API_Documentation.md'] Result:\\n\\n<file><path>docs/Driver_API_Documentation.md</path>\\n<content lines=\\\"500-1000\\\">\\n 500 | * `my_hmd_icon@2x.png` - 100x64 icon **must** be used.\\r\\n 501 | \\r\\n 502 | An icon which is not a supported size **will** be cropped from the top-left.\\r\\n 503 | \\r\\n 504 | An icon **can** choose to animate using a gif format. For example, it is typical for tracked controllers to have a\\r\\n 505 | breathing animation when they are on, but have not established tracking.\\r\\n 506 | \\r\\n 507 | Icons **must** be a colored green-blue gradient across the image. Icons **will** be formatted appropriately to include\\r\\n 508 | this gradient. These gradients are generated by the runtime, and are placed into the same folder\\r\\n 509 | the icon is in, with  `.b4bfb144` appended to the filename.\\r\\n 510 | \\r\\n 511 | ### Setting icons\\r\\n 512 | \\r\\n 513 | To set icons, they **must** be set as a property of the device. This can either be done in\\r\\n 514 | the `driver.vrdrivermanifest` file or through setting the properties programmatically.\\r\\n 515 | See [Device Properties](#device-properties).\\r\\n 516 | \\r\\n 517 | A list of icons that **can** be set are defined below:\\r\\n 518 | \\r\\n 519 | * `Prop_NamedIconPathDeviceOff_String` - The device is off.\\r\\n 520 | * `Prop_NamedIconPathDeviceSearching_String` - The device is on, but does not have tracking established.\\r\\n 521 | * `Prop_NamedIconPathDeviceSearchingAlert_String` - The device is on, does not have tracking established and has\\r\\n 522 |   received a warning.\\r\\n 523 | * `Prop_NamedIconPathDeviceReady_String` - The device is on, tracking and working nominally.\\r\\n 524 | * `Prop_NamedIconPathDeviceReadyAlert_String` - The device is on and ready to use, but needs to inform the user of\\r\\n 525 |   something (E.g. firmware update).\\r\\n 526 | * `Prop_NamedIconPathDeviceNotReady_String` - The device is on, but not ready to start up and establish tracking.\\r\\n 527 | * `Prop_NamedIconPathDeviceStandby_String` - The device has been put to sleep due to system inactivity.\\r\\n 528 | * `Prop_NamedIconPathDeviceStandbyAlert_String` - The device is in standby, but needs to inform the user of something (\\r\\n 529 |   E.g. firmware update).\\r\\n 530 | * `Prop_NamedIconPathDeviceAlertLow_String` - The device is working, but has a low battery. This is\\r\\n 531 |   when `Prop_DeviceBatteryPercentage_Float` is less than 15%. See [Device Properties](#device-properties).\\r\\n 532 | * `Prop_NamedIconPathTrackingReferenceDeviceOff_String` - The tracking reference device (i.e. basestation) is not yet\\r\\n 533 |   detected or has been switched off.\\r\\n 534 | * `Prop_NamedIconPathControllerLeftDeviceOff_String` - The left hand controller is off.\\r\\n 535 | * `Prop_NamedIconPathControllerRightDeviceOff_String` - The right hand controller is off.\\r\\n 536 | \\r\\n 537 | If a key is not matched, the `{system}/icons/invalid_status.png` icon **will** be used.\\r\\n 538 | \\r\\n 539 | ### Updating Icons\\r\\n 540 | \\r\\n 541 | The icon currently used to represent a device **can** be updated in two ways: by the runtime when\\r\\n 542 | a device ([submits a pose](#poses)) or the driver sending an event to update an icon.\\r\\n 543 | \\r\\n 544 | In a pose, a combination of setting these members:\\r\\n 545 | \\r\\n 546 |     ETrackingResult result\\r\\n 547 |     bool poseIsValid\\r\\n 548 |     bool deviceIsConnected\\r\\n 549 | \\r\\n 550 | Will update the icons to represent the current state of the device:\\r\\n 551 | \\r\\n 552 | * `Prop_NamedIconPathDeviceOff_String`\\r\\n 553 |     * `deviceIsConnected` is false.\\r\\n 554 | * `Prop_NamedIconPathDeviceSearching_String`\\r\\n 555 |     * `deviceIsConnected` is true.\\r\\n 556 |     * `poseIsValid` is false.\\r\\n 557 |     * The device previously connected, but then disconnected.\\r\\n 558 | * `Prop_NamedIconPathDeviceReady_String`\\r\\n 559 |     * `deviceIsConnected` is true.\\r\\n 560 |     * `poseIsValid` is true.\\r\\n 561 | * `Prop_NamedIconPathDeviceStandby_String`\\r\\n 562 |     * The orientation of the device's pose has remained close to constant.\\r\\n 563 |     * The `/proximity` boolean input path is `false`. For this to be used, `Prop_ContainsProximitySensor_Bool` **must** be set to true.\\r\\n 564 | * `Prop_NamedIconPathDeviceAlertLow_String`\\r\\n 565 |     * `deviceIsConnected` is true.\\r\\n 566 |     * `poseIsValid` is true.\\r\\n 567 |     * `result` is `TrackingResult_Running_OK`.\\r\\n 568 |     * `Prop_DeviceBatteryPercentage_Float` is less than 0.15.\\r\\n 569 | \\r\\n 570 | ## Device Classes\\r\\n 571 | \\r\\n 572 | Devices in OpenVR **must** have a class associated with them. The class of the device defines what sort of device is\\r\\n 573 | being exposed to the runtime. The device classes available are defined in the `ETrackedDeviceClass` enum and the class\\r\\n 574 | of a device is provided to the runtime through `IVRServerDriverHost::TrackedDeviceAdded`.\\r\\n 575 | \\r\\n 576 | * `TrackedDeviceClass_HMD` - Head-Mounted Displays. E.g. Index HMD.\\r\\n 577 | * `TrackedDeviceClass_Controller` - Tracked controllers. E.g. Index controllers.\\r\\n 578 | * `TrackedDeviceClass_GenericTracker` - Generic trackers, similar to controllers. E.g. Vive trackers. An\\r\\n 579 |   additional `manage trackers` interface in SteamVR **will** be shown for the user to configure where and how this\\r\\n 580 |   tracker is\\r\\n 581 |   used. Note: Tracker roles are not configurable by the driver.\\r\\n 582 | * `TrackedDeviceClass_TrackingReference` - Camera and base stations that serve as tracking reference points. E.g.\\r\\n 583 |   Basestation 2.0.\\r\\n 584 | * `TrackedDeviceClass_DisplayRedirect` - Accessories that aren't necessarily tracked themselves, but may redirect video\\r\\n 585 |   output from other tracked devices.\\r\\n 586 | \\r\\n 587 | ### Controller roles\\r\\n 588 | \\r\\n 589 | Devices of `TrackedDeviceClass_Controller` **must** have a role associated with them. The role identifies how the\\r\\n 590 | controller is used by the user and how the device will behave within the runtime. The roles are defined in\\r\\n 591 | the `ETrackedControllerRole` enum.\\r\\n 592 | \\r\\n 593 | * `TrackedControllerRole_LeftHand` - Tracked device associated with the left hand.\\r\\n 594 | * `TrackedControllerRole_RightHand` - Tracked device associated with the right hand.\\r\\n 595 | * `TrackedControllerRole_OptOut` - Tracked device is opting out of left/right hand selection.\\r\\n 596 | * `TrackedControllerRole_Treadmill` - Tracked device is a treadmill or other locomotion device that is to be used in\\r\\n 597 |   conjunction with the handed controllers.\\r\\n 598 | * `TrackedControllerRole_Stylus` - Tracked device is a stylus\\r\\n 599 | \\r\\n 600 | At any given time, there will be one and only one _active_ controller associated with\\r\\n 601 | a `TrackedControllerRole_LeftHand`, `TrackedControllerRole_RightHand` and `TrackedControllerRole_Treadmill` role.\\r\\n 602 | \\r\\n 603 | Applications **will not** receive input from multiple controllers assigned to the\\r\\n 604 | same `TrackedControllerRole_LeftHand`, `TrackedControllerRole_RightHand` and `TrackedControllerRole_Treadmill` roles at\\r\\n 605 | one time.\\r\\n 606 | \\r\\n 607 | The active device for each role is decided by the runtime, but can be influenced by the device\\r\\n 608 | through setting `Prop_ControllerHandSelectionPriority_Int32`.\\r\\n 609 | \\r\\n 610 | `TrackedControllerRole_Treadmill` **can** be used at the same time as `TrackedControllerRole_LeftHand`\\r\\n 611 | and `TrackedControllerRole_RightHand`. Additional UI is shown to the user for how to\\r\\n 612 | configure `TrackedControllerRole_Treadmill` bindings.\\r\\n 613 | \\r\\n 614 | If both an _input_ from `TrackedControllerRole_Treadmill` and an _input_ from a handed controller are assigned to the\\r\\n 615 | same _action_ in an application, SteamVR **will** use the input with the greatest absolute value.\\r\\n 616 | \\r\\n 617 | ### Trackers (Full body Tracking)\\r\\n 618 | \\r\\n 619 | Drivers **can** expose device(s) of class `TrackedDeviceClass_GenericTracker` to expose trackers to SteamVR. These\\r\\n 620 | trackers can then be used by the user for features such as full-body tracking, object tracking and more.\\r\\n 621 | \\r\\n 622 | Tracker roles can be set by the user in the \\\"Manage Trackers\\\" section of SteamVR.\\r\\n 623 | \\r\\n 624 | Tracker roles are stored in `steamvr.vrsettings`, under the `vr::k_pch_Trackers_Section` (\\\"trackers\\\") section. Each key\\r\\n 625 | of the section has the formatting: `/devices/<driver_name>/<device_serial_number>`, with a string value of one of the\\r\\n 626 | tracker roles below.\\r\\n 627 | \\r\\n 628 | In most circumstances, SteamVR expects users to be the ones to assign roles to individual trackers, and so SteamVR\\r\\n 629 | provides the \\\"Manage Trackers\\\" UI in settings.\\r\\n 630 | However, a driver **can** write to the `trackers` section in the `steamvr.vrsettings` file using\\r\\n 631 | the [IVRSettings](#ivrsettings) interface as a way to modify each tracker's role.\\r\\n 632 | \\r\\n 633 | The list of available tracker roles that can be set by the user are:\\r\\n 634 | \\r\\n 635 | * `TrackerRole_Handed`\\r\\n 636 | * `TrackerRole_LeftFoot`\\r\\n 637 | * `TrackerRole_RightFoot`\\r\\n 638 | * `TrackerRole_LeftShoulder`\\r\\n 639 | * `TrackerRole_RightShoulder`\\r\\n 640 | * `TrackerRole_LeftElbow`\\r\\n 641 | * `TrackerRole_RightElbow`\\r\\n 642 | * `TrackerRole_LeftKnee`\\r\\n 643 | * `TrackerRole_RightKnee`\\r\\n 644 | * `TrackerRole_Waist`\\r\\n 645 | * `TrackerRole_Chest`\\r\\n 646 | * `TrackerRole_Camera`\\r\\n 647 | * `TrackerRole_Keyboard`\\r\\n 648 | \\r\\n 649 | Trackers **can** have input profiles, which are set depending on the current role of the tracker.\\r\\n 650 | See [Input Profiles](#input-profiles) for more information on the `tracker_types` section.\\r\\n 651 | \\r\\n 652 | # Driver Structure\\r\\n 653 | \\r\\n 654 | A runtime expects driver code to be compiled into a _shared library_ (.dll or .so).\\r\\n 655 | \\r\\n 656 | Having the driver compiled to a shared library means that it can be loaded into SteamVR at runtime, rather than compile\\r\\n 657 | time, meaning that SteamVR does not need to have explicit support for each driver that it interacts with and can load\\r\\n 658 | drivers dynamically.\\r\\n 659 | \\r\\n 660 | The resultant driver shared library **must** have the `openvr_api` static library compiled into it.\\r\\n 661 | \\r\\n 662 | * The static libraries can be found in [openvr/lib](https://github.com/ValveSoftware/openvr/tree/master/lib)\\r\\n 663 |     * Use the correct platform and architecture for what you are targeting.\\r\\n 664 | \\r\\n 665 | Loading a driver involves pointing the runtime to a specific folder where the driver binary is stored.\\r\\n 666 | \\r\\n 667 | Your driver binary **must** be located at `<my_driver_name>/bin/<platform><arch>/driver_<my_driver_name>.dll/so`.\\r\\n 668 | \\r\\n 669 | Drivers **must not** use both the `openvr.h` and `openvr_driver.h` in a single binary. Doing so will cause the runtime\\r\\n 670 | to crash.\\r\\n 671 | \\r\\n 672 | OpenVR interfaces are defined in the API as abstract classes with pure virtual methods. This means that if\\r\\n 673 | a driver wishes to implement a specific interface, they **must** publicly inherit the interface, then provide\\r\\n 674 | definitions for every method declared in that interface.\\r\\n 675 | \\r\\n 676 | The next section documents interfaces and functions of the OpenVR API.\\r\\n 677 | \\r\\n 678 | ## HmdDriverFactory\\r\\n 679 | \\r\\n 680 | Drivers are loaded as shared libraries (.dll or .so) into the runtime, and **must** export a `HmdDriverFactory` function\\r\\n 681 | from the shared library. This function becomes the entry-point for every driver.\\r\\n 682 | \\r\\n 683 | ```c++\\r\\n 684 | extern \\\"C\\\" __declspec( dllexport ) \\r\\n 685 | void *HmdDriverFactory( const char *pInterfaceName, int *pReturnCode );\\r\\n 686 | ```\\r\\n 687 | \\r\\n 688 | If `HmdDriverFactory` is not found, the runtime **will** return `VRInitError_Init_FactoryNotFound`.\\r\\n 689 | \\r\\n 690 | The runtime calls this function multiple times, to find which interfaces and versions of interfaces the driver supports.\\r\\n 691 | The driver **must only** return a pointer to its interface implementation when `pInterfaceName` matches the interface\\r\\n 692 | and version of the interface implemented.\\r\\n 693 | \\r\\n 694 | `Ixxxxx_Version` are constants defined in the OpenVR API that are set to the current version of the interface\\r\\n 695 | implemented in the API version you are using. They **will** eventually match one of the `pInterfaceName` calls.\\r\\n 696 | \\r\\n 697 | Two common interfaces a driver **might** return pointers to are implementations\\r\\n 698 | of [IServerTrackedDeviceProvider](#IServerTrackedDeviceProvider) and [IVRWatchdogProvider](#ivrwatchdogprovider).\\r\\n 699 | \\r\\n 700 | ```c++\\r\\n 701 | #include <openvr_driver.h>\\r\\n 702 | \\r\\n 703 | class MyServerTrackedDeviceProvider : public vr::IServerTrackedDeviceProvider {\\r\\n 704 |     ...\\r\\n 705 | }\\r\\n 706 | \\r\\n 707 | class MyWatchdogProvider : public vr::IVRWatchdogProvider {\\r\\n 708 |     ...\\r\\n 709 | }\\r\\n 710 | \\r\\n 711 | MyServerTrackedDeviceProvider device_provider;\\r\\n 712 | MyWatchdogProvider watchdog_provider;\\r\\n 713 | \\r\\n 714 | extern \\\"C\\\" __declspec( dllexport ) \\r\\n 715 | void *HmdDriverFactory( const char *pInterfaceName, int *pReturnCode )\\r\\n 716 | {\\r\\n 717 | \\tif( 0 == strcmp( IServerTrackedDeviceProvider_Version, pInterfaceName ) )\\r\\n 718 | \\t{\\r\\n 719 | \\t\\treturn &device_provider; //return a pointer to your vr::IServerTrackedDeviceProvider object\\r\\n 720 | \\t}\\r\\n 721 | \\tif( 0 == strcmp( IVRWatchdogProvider_Version, pInterfaceName ) )\\r\\n 722 | \\t{\\r\\n 723 | \\t\\treturn &watchdog_provider; //return a pointer to your vr::IVRWatchdogProvider object\\r\\n 724 | \\t}\\r\\n 725 | \\r\\n 726 | \\r\\n 727 | \\tif( pReturnCode )\\r\\n 728 | \\t\\t*pReturnCode = VRInitError_Init_InterfaceNotFound;\\r\\n 729 | \\r\\n 730 | \\treturn NULL;\\r\\n 731 | }\\r\\n 732 | ```\\r\\n 733 | \\r\\n 734 | ## IServerTrackedDeviceProvider\\r\\n 735 | \\r\\n 736 | An `IServerTrackedDeviceProvider` is an interface that is implemented by a driver and its methods are called by the\\r\\n 737 | runtime when the state of the runtime changes. It **must** be a global, single instance and exist for the duration\\r\\n 738 | of the runtime session.\\r\\n 739 | \\r\\n 740 | An `IServerTrackedDeviceProvider` **can** interact\\r\\n 741 | with [IVRServerDriverHost](#IVRServerDriverHost), an interface\\r\\n 742 | implemented by the runtime that provides useful methods to retrieve and update state from the runtime.\\r\\n 743 | \\r\\n 744 | `IServerTrackedDeviceProvider` **does not** implement any devices itself, but **should**\\r\\n 745 | initialize a [ITrackedDeviceServerDriver](#ITrackedDeviceServerDriver) for each device it wants to add to the\\r\\n 746 | runtime.\\r\\n 747 | \\r\\n 748 | See [IVRServerDriverHost](#IVRServerDriverHost) for how to add a device to the runtime.\\r\\n 749 | \\r\\n 750 | <br/>\\r\\n 751 | \\r\\n 752 | ```c++\\r\\n 753 | virtual EVRInitError Init( IVRDriverContext *pDriverContext ) = 0;\\r\\n 754 | ```\\r\\n 755 | \\r\\n 756 | `Init` is called before any other methods of the class are called. `Init` **may** choose to initialize device drivers,\\r\\n 757 | and **must** return `VRInitError_None` if the call is successful.\\r\\n 758 | \\r\\n 759 | Returning anything else than `VRInitError_None` **will** cause the driver and shared library to be unloaded\\r\\n 760 | from `vrserver.exe`.\\r\\n 761 | \\r\\n 762 | The implementation of `IServerTrackedDeviceProvider` **should** keep resource usage to a minimum before `Init` is\\r\\n 763 | called.\\r\\n 764 | \\r\\n 765 | * `IVRDriverContext *pDriverContext` - Contains pointers to interfaces implemented by the runtime. The\\r\\n 766 |   macro `VR_INIT_SERVER_DRIVER_CONTEXT` provided in the OpenVR API **can** be used to initialize this context.\\r\\n 767 | \\r\\n 768 | The implementation of `IServerTrackedDeviceProvider` **must not** call any methods in the runtime (such as\\r\\n 769 | in [IVRServerDriverHost](#IVRServerDriverHost)) until `Init` has been called and the server driver context has been\\r\\n 770 | initialized. See example at the end of the section.\\r\\n 771 | \\r\\n 772 | <br/>\\r\\n 773 | \\r\\n 774 | ```c++\\r\\n 775 | virtual void Cleanup() = 0;\\r\\n 776 | ```\\r\\n 777 | \\r\\n 778 | `Cleanup` is called right before the driver is unloaded.\\r\\n 779 | \\r\\n 780 | `Cleanup` **should** release any resources\\r\\n 781 | that `IServerTrackedDeviceProvider` or child `ITrackedDeviceServerDriver` have acquired throughout the session.\\r\\n 782 | \\r\\n 783 | <br/>\\r\\n 784 | \\r\\n 785 | ```c++\\r\\n 786 | virtual const char * const *GetInterfaceVersions() = 0;\\r\\n 787 | ```\\r\\n 788 | \\r\\n 789 | `GetInterfaceVersions` **must** return a pointer to an array of strings that represent the versions of interfaces used\\r\\n 790 | in this driver.\\r\\n 791 | \\r\\n 792 | The helper variable `k_InterfaceVersions` in the OpenVR API **should** be returned directly from this method.\\r\\n 793 | This variable contains versions of the interfaces you are compiling your driver against.\\r\\n 794 | \\r\\n 795 |     IVRSettings_Version\\r\\n 796 |     ITrackedDeviceServerDriver_Version\\r\\n 797 |     IVRDisplayComponent_Version\\r\\n 798 |     IVRDriverDirectModeComponent_Version\\r\\n 799 |     IVRCameraComponent_Version\\r\\n 800 |     IServerTrackedDeviceProvider_Version\\r\\n 801 |     IVRWatchdogProvider_Version\\r\\n 802 |     IVRVirtualDisplay_Version\\r\\n 803 |     IVRDriverManager_Version\\r\\n 804 |     IVRResources_Version\\r\\n 805 |     IVRCompositorPluginProvider_Version\\r\\n 806 | \\r\\n 807 | <br/>\\r\\n 808 | \\r\\n 809 | ```c++\\r\\n 810 | virtual void RunFrame() = 0;\\r\\n 811 | ```\\r\\n 812 | \\r\\n 813 | `RunFrame` is called *directly* in the main loop of `vrserver.exe`. As a result, it **should not** perform calls that\\r\\n 814 | might block. It is called on every frame.\\r\\n 815 | \\r\\n 816 | It is strongly recommended for a driver to use their own thread for performing work that might need to be done at a\\r\\n 817 | regular interval.\\r\\n 818 | \\r\\n 819 | A driver **should** (and perhaps only) poll for events using `RunFrame`. See [events](#events).\\r\\n 820 | \\r\\n 821 | <br/>\\r\\n 822 | \\r\\n 823 | ```c++\\r\\n 824 | virtual bool ShouldBlockStandbyMode() = 0;\\r\\n 825 | ```\\r\\n 826 | \\r\\n 827 | `ShouldBlockStandbyMode` is deprecated, and will never be called in newer versions of SteamVR. Drivers **must**\\r\\n 828 | implement\\r\\n 829 | this function (because it is pure virtual), but the return value has no effect on behavior.\\r\\n 830 | \\r\\n 831 | <br/>\\r\\n 832 | \\r\\n 833 | ```c++\\r\\n 834 | virtual void EnterStandby() = 0;\\r\\n 835 | ```\\r\\n 836 | \\r\\n 837 | `EnterStandby` is called when the whole system is entering standby mode.\\r\\n 838 | \\r\\n 839 | This is after a user-configured time after which the system becomes inactive (HMD not being worn, controllers off or not\\r\\n 840 | used, etc.).\\r\\n 841 | \\r\\n 842 | The driver **should** switch itself into whatever sort of low-power state it has.\\r\\n 843 | \\r\\n 844 | <br/>\\r\\n 845 | \\r\\n 846 | ```c++\\r\\n 847 | virtual void LeaveStandby() = 0;\\r\\n 848 | ```\\r\\n 849 | \\r\\n 850 | `LeaveStandby` is called when the whole system is leaving Standby mode. The driver **should** switch itself back to full\\r\\n 851 | operation.\\r\\n 852 | \\r\\n 853 | ### Example\\r\\n 854 | \\r\\n 855 | ```c++\\r\\n 856 | class MyDeviceProvider : public IServerTrackedDeviceProvider\\r\\n 857 | {\\r\\n 858 | public:\\r\\n 859 |     virtual EVRInitError Init( vr::IVRDriverContext *pDriverContext )\\r\\n 860 |     {\\r\\n 861 |         VR_INIT_SERVER_DRIVER_CONTEXT( pDriverContext );\\r\\n 862 | \\r\\n 863 |         m_pMyHmdDevice = new MyHmdDeviceDriver();\\r\\n 864 |         m_pMyControllerDevice = new MyControllerDriver();\\r\\n 865 | \\r\\n 866 |         //see IVRServerDriverHost - notify the runtime that our driver wishes to add two devices to the session\\r\\n 867 |         vr::VRServerDriverHost()->TrackedDeviceAdded( \\\"MyHMD1\\\", vr::TrackedDeviceClass_HMD, m_pMyHmdDevice );\\r\\n 868 |         vr::VRServerDriverHost()->TrackedDeviceAdded( \\\"MyController1\\\", vr::TrackedDeviceClass_Controller, m_pMyControllerDevice );\\r\\n 869 | \\r\\n 870 |         return VRInitError_None;\\r\\n 871 |     }\\r\\n 872 | \\r\\n 873 |     virtual void Cleanup() \\r\\n 874 |     {\\r\\n 875 |         delete m_pMyHmdDevice;\\r\\n 876 |         m_pMyHmdDevice = NULL;\\r\\n 877 |         delete m_pMyControllerDevice;\\r\\n 878 |         m_pMyControllerDevice = NULL;\\r\\n 879 |     }\\r\\n 880 | \\r\\n 881 |     virtual const char * const *GetInterfaceVersions() { return vr::k_InterfaceVersions; }\\r\\n 882 |     virtual void MyRunFrame() {}\\r\\n 883 |     virtual bool ShouldBlockStandbyMode()  { return false; } //never called.\\r\\n 884 |     virtual void EnterStandby()  {}\\r\\n 885 |     virtual void LeaveStandby()  {}\\r\\n 886 | \\r\\n 887 | private:\\r\\n 888 |     MyHmdDeviceDriver *m_pMyHmdDevice = nullptr;\\r\\n 889 |     MyControllerDriver *m_pMyControllerDevice = nullptr;\\r\\n 890 | };\\r\\n 891 | ```\\r\\n 892 | \\r\\n 893 | ## ITrackedDeviceServerDriver\\r\\n 894 | \\r\\n 895 | `ITrackedDeviceServerDriver` represents a singular device in the *driver*.\\r\\n 896 | \\r\\n 897 | <br/>\\r\\n 898 | \\r\\n 899 | ```c++\\r\\n 900 | virtual EVRInitError Activate( uint32_t unObjectId ) = 0;\\r\\n 901 | ```\\r\\n 902 | \\r\\n 903 | `Activate` is called after the driver makes a call to `IVRServerDriverHost::TrackedDeviceAdded`.\\r\\n 904 | \\r\\n 905 | Resource usage should be kept to a minimum until this method has been called by the runtime.\\r\\n 906 | \\r\\n 907 | Devices **should not** make any calls to the runtime until `Activate()` has been called.\\r\\n 908 | \\r\\n 909 | * `uint32_t unObjectId` - The device's id. This is unique across SteamVR and is used to get and update various state and\\r\\n 910 |   properties relating to the device, such as [poses](#Poses) and [properties](#device-properties).\\r\\n 911 | \\r\\n 912 | <br/>\\r\\n 913 | \\r\\n 914 | ```c++\\r\\n 915 | virtual void Deactivate() = 0;\\r\\n 916 | ```\\r\\n 917 | \\r\\n 918 | `Deactivate` is called when the device is needed to be deactivated, either from SteamVR closing or the system switching\\r\\n 919 | between HMDs, if this device class represents the currently active HMD.\\r\\n 920 | \\r\\n 921 | The device  **should** free whatever resources it has acquired when this method is called by the runtime.\\r\\n 922 | \\r\\n 923 | Any valid calls the device can make to various runtime-implemented interfaces are guaranteed to be valid\\r\\n 924 | until `Deactivate` is called. The device **must not** call any of these interfaces after the device has returned from\\r\\n 925 | this method, as they are not guaranteed to be valid past this point.\\r\\n 926 | \\r\\n 927 | `IServerTrackedDeviceProvider::Cleanup` **will** be called after this method has been called on each device currently\\r\\n 928 | added to the runtime.\\r\\n 929 | \\r\\n 930 | <br/>\\r\\n 931 | \\r\\n 932 | ```c++\\r\\n 933 | virtual void EnterStandby() = 0;\\r\\n 934 | ```\\r\\n 935 | \\r\\n 936 | `EnterStandby` is called when the device should enter standby mode. This occurs when the user requests the device to\\r\\n 937 | be turned off, when the system is entering standby mode, or when the system shuts down.\\r\\n 938 | \\r\\n 939 | The device should switch into a lower power state or turn off.\\r\\n 940 | \\r\\n 941 | <br/>\\r\\n 942 | \\r\\n 943 | ```c++\\r\\n 944 | virtual void *GetComponent( const char *pchComponentNameAndVersion ) = 0;\\r\\n 945 | ```\\r\\n 946 | \\r\\n 947 | `GetComponent` is called on activation and the device **should** return whatever components it has for device-specific\\r\\n 948 | functionality. If the component requested does not exist on the device, the device **must** return NULL from this\\r\\n 949 | method.\\r\\n 950 | \\r\\n 951 | * `const char *pchComponentNameAndVersion` - The component name and version to match against. The possible options are\\r\\n 952 |   kept as strings in the OpenVR header. The name and versions of the interfaces you are currently targeting (the ones\\r\\n 953 |   you are implementing) and can return from this method are listed below:\\r\\n 954 |     * `IVRDisplayComponent` - A generic display component on a single tracked device. If drivers do not need to access\\r\\n 955 |       the display directly or are not a virtual display, use this.\\r\\n 956 |     * `IVRDriverDirectModeComponent` - This component is used for drivers that implement direct mode entirely on their\\r\\n 957 |       own without allowing the VR Compositor to own the window/device.\\r\\n 958 |     * `IVRCameraComponent` - Represents camera one or more cameras on the device\\r\\n 959 | \\r\\n 960 | See [Device Components](#Device-Components) for more information on device components.\\r\\n 961 | \\r\\n 962 | ```c++\\r\\n 963 | virtual void *GetComponent(const char *pchComponentNameAndVersion) override {\\r\\n 964 |   if (!_stricmp(pchComponentNameAndVersion, vr::IVRVirtualDisplay_Version)) {\\r\\n 965 |     return &m_myVirtualDisplay;\\r\\n 966 |   }\\r\\n 967 |         \\r\\n 968 |   if (!_stricmp(pchComponentNameAndVersion, vr::IVRCameraComponent_Version)) {\\r\\n 969 |     return &m_myCameraComponent;\\r\\n 970 |   }\\r\\n 971 |   \\r\\n 972 |   return nullptr;\\r\\n 973 | }\\r\\n 974 | ```\\r\\n 975 | \\r\\n 976 | <br/>\\r\\n 977 | \\r\\n 978 | ```c++\\r\\n 979 | virtual void DebugRequest( const char *pchRequest, char *pchResponseBuffer, uint32_t unResponseBufferSize ) = 0;\\r\\n 980 | ```\\r\\n 981 | \\r\\n 982 | `DebugRequest` is called when the application requests a debug action from the device. The device **should** respond to\\r\\n 983 | the\\r\\n 984 | request in the buffer provided.\\r\\n 985 | \\r\\n 986 | What is sent from the application to the device is up to the application and device to handle, as is the response.\\r\\n 987 | \\r\\n 988 | * `const char *pchRequest` - The request string. The device **should** respond to the request in the buffer provided.\\r\\n 989 | * `char *pchResponseBuffer` - The buffer to write the response to.\\r\\n 990 | * `uint32_t unResponseBufferSize` - The size of the buffer provided.\\r\\n 991 | \\r\\n 992 | <br/>\\r\\n 993 | \\r\\n 994 | ```c++\\r\\n 995 | virtual DriverPose_t GetPose() = 0;\\r\\n 996 | ```\\r\\n 997 | \\r\\n 998 | This method is deprecated and is not called by the runtime. The device **must** implement this method, but the return\\r\\n 999 | value has no effect on behavior.\\r\\n1000 | \\r\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\ndocs\\\\Driver_API_Documentation.md\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:32:48 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n78,696 (39%)\\n\\n# Current Cost\\n$0.60\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":145,\"cacheWrites\":8710,\"cacheReads\":78561,\"cost\":0.058417800000000006}"},{"ts":1744500776718,"type":"say","say":"text","text":"I've gathered a lot of information about the OpenVR driver architecture and how to implement a custom driver. Let me continue reading to find more information about how to access IMU data and how to implement a custom driver that wraps the existing lighthouse driver.\n\nLet me continue reading the Driver API Documentation to understand more about how to implement a custom driver component and access IMU data:","partial":false},{"ts":1744500778699,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"docs/Driver_API_Documentation.md\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\docs\\\\Driver_API_Documentation.md\",\"reason\":\" (lines 1000-1500)\"}","partial":false},{"ts":1744500888837,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'docs/Driver_API_Documentation.md'] Result:\\n\\n<file><path>docs/Driver_API_Documentation.md</path>\\n<content lines=\\\"1000-1500\\\">\\n1000 | \\r\\n1001 | ### Device Components\\r\\n1002 | \\r\\n1003 | HMDs have a variety of different ways of interacting with the runtime. They may choose to have their own compositor, let\\r\\n1004 | the runtime submit frames directly to the device on their behalf, or need ways to access the final composited\\r\\n1005 | backbuffer.\\r\\n1006 | \\r\\n1007 | OpenVR provides a set of display \\\"component\\\" interfaces that can be used to implement these different behaviors.\\r\\n1008 | \\r\\n1009 | The options are:\\r\\n1010 | \\r\\n1011 | * `IVRDisplayComponent` - Recommended. The driver will provide information about the display to the runtime on\\r\\n1012 |   initialization, such as distortion and the runtime will then own the display and submit the frames directly to it.\\r\\n1013 |     * This takes advantage of \\\"direct mode\\\" (not to be confused with `IVRDriverDirectModeComponent`) which allows the\\r\\n1014 |       runtime to skip the windowing system level and work directly on the display level.\\r\\n1015 | * `IVRDriverDirectModeComponent` - Only recommended if the driver is doing its own compositing, or if it is impossible\\r\\n1016 |   to provide distortion data. Image texture handoff in driver direct mode happens before compositing and allows the\\r\\n1017 |   driver to own the display.\\r\\n1018 | * `IVRVirtualDisplay` - Only recommended if you can provide your distortion data, but for some reason cannot provide the\\r\\n1019 |   output, such as transmitting the frames wirelessly. Provides the driver with a final composited backbuffer intended\\r\\n1020 |   for the headset's display.\\r\\n1021 | * `IVRCameraComponent` - The device implements a camera.\\r\\n1022 | \\r\\n1023 | See [ITrackedDeviceServerDriver](#ITrackedDeviceServerDriver) for more information and how to implement\\r\\n1024 | the `GetComponent` method.\\r\\n1025 | \\r\\n1026 | #### IVRDisplayComponent\\r\\n1027 | \\r\\n1028 | `IVRDisplayComponent` is a component that represents a display on a device which the runtime calls to get information\\r\\n1029 | about the display.\\r\\n1030 | \\r\\n1031 | The runtime will then submit composited frames to the display by directly interacting with it.\\r\\n1032 | \\r\\n1033 | <br/>\\r\\n1034 | \\r\\n1035 | ```c++\\r\\n1036 | virtual void GetWindowBounds( int32_t *pnX, int32_t *pnY, uint32_t *pnWidth, uint32_t *pnHeight ) = 0;\\r\\n1037 | ```\\r\\n1038 | \\r\\n1039 | `GetWindowBounds` is called by the runtime when the VR display is in extended mode (i.e. a part of the desktop), which\\r\\n1040 | SteamVR determines by calling `IsDisplayOnDesktop`. The function **should** provide the size and position that the\\r\\n1041 | window needs to be on the desktop, such that it fills the extended display.\\r\\n1042 | \\r\\n1043 | * `int32_t *pnX` - The number of pixels from the left of the window to the place to where you want rendered.\\r\\n1044 | * `int32_t *pnY` - The number of pixels from the top of the window to the place to where you want rendered.\\r\\n1045 | * `uint32_t *pnWidth` - The width of the window in pixels.\\r\\n1046 | * `uint32_t *pnHeight` - The height of the window in pixels.\\r\\n1047 | \\r\\n1048 | <br/>\\r\\n1049 | \\r\\n1050 | ```c++\\r\\n1051 | virtual bool IsDisplayOnDesktop() = 0;\\r\\n1052 | ```\\r\\n1053 | \\r\\n1054 | `IsDisplayOnDesktop` is called by the runtime to determine if the window is extending the desktop.\\r\\n1055 | \\r\\n1056 | HMDs **should not** use this extended mode (returning `true` from this function) and instead make a direct-mode HMD.\\r\\n1057 | See [IVRDriverDirectModeComponent](#IVRDriverDirectModeComponent) for more information on direct-mode HMDs.\\r\\n1058 | \\r\\n1059 | <br/>\\r\\n1060 | \\r\\n1061 | ```c++\\r\\n1062 | virtual bool IsDisplayRealDisplay() = 0;\\r\\n1063 | ```\\r\\n1064 | \\r\\n1065 | `IsDisplayRealDisplay` is called by the runtime to determine if the display is a real display.\\r\\n1066 | \\r\\n1067 | Virtual devices **should** return `false` here, to prevent the runtime trying to directly interact with a display that\\r\\n1068 | doesn't actually exist.\\r\\n1069 | \\r\\n1070 | <br/>\\r\\n1071 | \\r\\n1072 | ```c++\\r\\n1073 | virtual void GetRecommendedRenderTargetSize( uint32_t *pnWidth, uint32_t *pnHeight ) = 0;\\r\\n1074 | ```\\r\\n1075 | \\r\\n1076 | `GetRecommendedRenderTargetSize` is called by the runtime to get the suggested size for the intermediate render target\\r\\n1077 | that the distortion pulls from.\\r\\n1078 | \\r\\n1079 | The values the driver specifies in this method set the value of the resolution in SteamVR settings (to 100%). The values\\r\\n1080 | the driver specifies in this method are not guaranteed to be used, if the user has set a different resolution in SteamVR\\r\\n1081 | settings, or the application picks a different resolution.\\r\\n1082 | \\r\\n1083 | The resolution you specify **should** result in 1:1 pixels with the display at the center of projection after the\\r\\n1084 | distortion function is applied to maximise the detail in the center of the display, where the user looks the most.\\r\\n1085 | \\r\\n1086 | * `uint32_t *pnWidth` - The width of the render target in pixels.\\r\\n1087 | * `uint32_t *pnHeight` - The height of the render target in pixels.\\r\\n1088 | \\r\\n1089 | ```c++ \\r\\n1090 | virtual void GetEyeOutputViewport( EVREye eEye, uint32_t *pnX, uint32_t *pnY, uint32_t *pnWidth, uint32_t *pnHeight ) = 0;\\r\\n1091 | ```\\r\\n1092 | \\r\\n1093 | `GetEyeOutputViewport` is called by the runtime to get the viewport in the frame buffer to draw the output of the\\r\\n1094 | distortion into.\\r\\n1095 | \\r\\n1096 | * `EVREye eEye` - The eye to get the viewport for. The possible options are:\\r\\n1097 |     * `Eye_Left` - The left eye.\\r\\n1098 |     * `Eye_Right` - The right eye.\\r\\n1099 | * `uint32_t *pnX` - The number of pixels from the left of the window to left edge of the viewport. Typically, each eye\\r\\n1100 |   will have half of the window width as its viewport.\\r\\n1101 | * `uint32_t *pnY` - The number of pixels from the top of the window to top edge of the viewport.\\r\\n1102 | * `uint32_t *pnWidth` - The width of the viewport in pixels.\\r\\n1103 | * `uint32_t *pnHeight` - The height of the viewport in pixels.\\r\\n1104 | \\r\\n1105 | ```c++\\r\\n1106 | virtual void GetEyeOutputViewport( EVREye eEye, uint32_t *pnX, uint32_t *pnY, uint32_t *pnWidth, uint32_t *pnHeight ) \\r\\n1107 | {\\r\\n1108 |     *pnY = 0;\\r\\n1109 |     *pnWidth = m_nWindowWidth / 2;\\r\\n1110 |     *pnHeight = m_nWindowHeight;\\r\\n1111 | \\r\\n1112 |     if ( eEye == Eye_Left )\\r\\n1113 |     {\\r\\n1114 |         *pnX = 0;\\r\\n1115 |     }\\r\\n1116 |     else\\r\\n1117 |     {\\r\\n1118 |         *pnX = m_nWindowWidth / 2;\\r\\n1119 |     }\\r\\n1120 | }\\r\\n1121 | ```\\r\\n1122 | \\r\\n1123 | <br/>\\r\\n1124 | \\r\\n1125 | ```c++\\r\\n1126 | virtual void GetProjectionRaw( EVREye eEye, float *pfLeft, float *pfRight, float *pfTop, float *pfBottom ) = 0;\\r\\n1127 | ```\\r\\n1128 | \\r\\n1129 | `GetProjectionRaw` is called by the runtime to get the raw values from the distortion that are used to build your own\\r\\n1130 | projection matrix in case your application is doing something fancy like infinite Z.\\r\\n1131 | \\r\\n1132 | The values represent the tangents of the half-angles from the center view axis.\\r\\n1133 | \\r\\n1134 | Note that “bottom” and “top” are backwards. “Bottom” is the tan angle from the center of projection to the top (+Y) edge\\r\\n1135 | of the display, and “top” is the center of projection to the bottom (-Y) edge of the display.\\r\\n1136 | \\r\\n1137 | * `EVREye eEye` - The eye to get the projection for. The possible options are:\\r\\n1138 |     * `Eye_Left` - The left eye.\\r\\n1139 |     * `Eye_Right` - The right eye.\\r\\n1140 | * `float *pfLeft` - The tangent of the angle between the center view axis and the left clipping plane (-X).\\r\\n1141 | * `float *pfRight` - The tangent of the angle between the center view axis and the right clipping plane (+X).\\r\\n1142 | * `float *pfTop` - The tangent of the angle between the center view axis and the **bottom** clipping plane (-Y).\\r\\n1143 | * `float *pfBottom` - The tangent of the angle between the center view axis and the **top** clipping plane (+Y).\\r\\n1144 | \\r\\n1145 | For example, an HMD with a 90 degree field of view would return the following values:\\r\\n1146 | \\r\\n1147 | ```c++\\r\\n1148 | void GetProjectionRaw( EVREye eEye, float *pfLeft, float *pfRight, float *pfTop, float *pfBottom ) \\r\\n1149 | {\\r\\n1150 |     // 45 degrees is the angle between the forward vector and each side\\r\\n1151 |     // so the values would be the tangent of 45 degrees (which is 1 or tan(45))\\r\\n1152 |     *pfLeft = -1.0f;\\r\\n1153 |     *pfRight = 1.0f;\\r\\n1154 |     *pfTop = -1.0f;\\r\\n1155 |     *pfBottom = 1.0f;\\r\\n1156 | }\\r\\n1157 | ```\\r\\n1158 | \\r\\n1159 | <br/>\\r\\n1160 | \\r\\n1161 | ```c++\\r\\n1162 | virtual DistortionCoordinates_t ComputeDistortion( EVREye eEye, float fU, float fV ) = 0;\\r\\n1163 | ```\\r\\n1164 | \\r\\n1165 | `ComputeDistortion` is called by the runtime and is used to generate the post-distortion UV coordinates for each color\\r\\n1166 | channel. UVs range from 0 to 1 and go from 0,0 in the upper left corner of the source render target to 1,1 in the lower\\r\\n1167 | right and covers a single eye.\\r\\n1168 | \\r\\n1169 | * `EVREye eEye` - The eye to get the distortion for. The possible options are:\\r\\n1170 |     * `Eye_Left` - The left eye.\\r\\n1171 |     * `Eye_Right` - The right eye.\\r\\n1172 | * `float fU` - The current U coordinate.\\r\\n1173 | * `float fV` - The current V coordinate.\\r\\n1174 | \\r\\n1175 | ```c++\\r\\n1176 | virtual bool ComputeInverseDistortion( HmdVector2_t *pResult, EVREye eEye, uint32_t unChannel, float fU, float fV ) = 0;\\r\\n1177 | ```\\r\\n1178 | `ComputeInverseDistortion` is called by the runtime to get the result of the inverse distortion function for the specified eye,\\r\\n1179 | channel and uv.\\r\\n1180 | \\r\\n1181 | Drivers **may** return false from this method to indicate that the runtime should infer an estimate from\\r\\n1182 | the result returned by `IVRDisplayComponent::ComputeDistortion`.\\r\\n1183 | \\r\\n1184 | Returning true from method indicates to the runtime that it should not try to estimate the inverse, and instead use the\\r\\n1185 | values provided by the driver.\\r\\n1186 | \\r\\n1187 | * `HmdVector2_t *pResult` - Driver should write into this with the result for the specified UV.\\r\\n1188 | * `EVREye eEye` - The eye to get the distortion for. The possible options are:\\r\\n1189 |     * `Eye_Left` - The left eye.\\r\\n1190 |     * `Eye_Right` - The right eye.\\r\\n1191 | * `uint32_t unChannel` - Which channel is requested. 0 for red, 1 for blue, 2 for green.\\r\\n1192 | * `float fU` - The current U coordinate.\\r\\n1193 | * `float fV` - The current V coordinate.\\r\\n1194 | \\r\\n1195 | #### IVRDriverDirectModeComponent\\r\\n1196 | \\r\\n1197 | `IVRDriverDirectModeComponent` is used for drivers that implement direct mode entirely on their own without allowing the\\r\\n1198 | VR Compositor to own the window, and for a driver's own compositor to interface with the runtime.\\r\\n1199 | \\r\\n1200 | This is useful for drivers that might want to implement their own compositor.\\r\\n1201 | \\r\\n1202 | Drivers **should** implement `IVRDisplayComponent` and let the compositor own the device, unless they need to have this\\r\\n1203 | control over the display.\\r\\n1204 | \\r\\n1205 | <br />\\r\\n1206 | \\r\\n1207 | ```c++\\r\\n1208 | virtual void CreateSwapTextureSet( uint32_t unPid, const SwapTextureSetDesc_t *pSwapTextureSetDesc, SwapTextureSet_t *pOutSwapTextureSet ) {}\\r\\n1209 | ```\\r\\n1210 | \\r\\n1211 | `CreateSwapTextureSet` is called to allocate textures for applications to render into.\\r\\n1212 | \\r\\n1213 | One of these per eye will be passed back to `SubmitLayer` for each frame.\\r\\n1214 | \\r\\n1215 | * `uint32_t unPid` - pid of the client process creating the texture.\\r\\n1216 | * `const SwapTextureSetDesc_t *pSwapTextureSetDesc` - description of the texture.\\r\\n1217 |     * `uint32_t nWidth` - Width of the texture.\\r\\n1218 |     * `uint32_t nHeight` - Height of the texture.\\r\\n1219 |     * `uint32_t nFormat` - Format of the texture. In `DXGI_FORMAT`.\\r\\n1220 |     * `uint32_t nSampleCount` - Number of samples per pixel.\\r\\n1221 | * `SwapTextureSet_t *pOutSwapTextureSet` - Your allocated textures\\r\\n1222 |     * `vr::SharedTextureHandle_t rSharedTextureHandles[ 3 ]` - _Shared_ handles to the textures\\r\\n1223 |     * `uint32_t VRSwapTextureFlag` - Flags for the texture.\\r\\n1224 |         * `VRSwapTextureFlag_Shared_NTHandle` - Specify that the shared texture resource was created with\\r\\n1225 |           the `SHARED_NTHANDLE` option (Windows)\\r\\n1226 | \\r\\n1227 | ```c++\\r\\n1228 | void CreateSwapTextureSet( uint32_t unPid, const SwapTextureSetDesc_t *pSwapTextureSetDesc, SwapTextureSet_t *pOutSwapTextureSet ) {\\r\\n1229 |     D3D11_TEXTURE2D_DESC desc = {};\\r\\n1230 |     desc.ArraySize = 1;\\r\\n1231 |     desc.Width = pSwapTextureSetDesc->unWidth;\\r\\n1232 |     desc.Height = pSwapTextureSetDesc->unHeight;\\r\\n1233 |     desc.MipLevels = 1;\\r\\n1234 |     desc.SampleDesc.Count = 1;\\r\\n1235 |     desc.SampleDesc.Quality = 0;\\r\\n1236 |     desc.Format = (DXGI_FORMAT)pSwapTextureSetDesc->unFormat;\\r\\n1237 |     desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;\\r\\n1238 |     desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;\\r\\n1239 |     \\r\\n1240 |     for(int i = 0; i < 3; i++) {\\r\\n1241 |         HRESULT hresult = myD3DDevice->CreateTexture2D(&desc, nullptr, &pOutSwapTextureSet->rSharedTextureHandles[i]);\\r\\n1242 |         \\r\\n1243 |         IDXGIResource* pResource = nullptr;\\r\\n1244 |         hresult = pOutSwapTextureSet->rSharedTextureHandles[i]->QueryInterface(__uuidof(IDXGIResource), (void**)&pResource);\\r\\n1245 |         \\r\\n1246 |         HANDLE hSharedHandle = nullptr;\\r\\n1247 |         hresult = pResource->GetSharedHandle(&hSharedHandle);\\r\\n1248 |         pResource->Release();\\r\\n1249 |         \\r\\n1250 |         pOutSwapTextureSet->rSharedTextureHandles[i] = (vr::SharedTextureHandle_t)hSharedHandle;\\r\\n1251 |     }\\r\\n1252 | }\\r\\n1253 | ```\\r\\n1254 | \\r\\n1255 | <br />\\r\\n1256 | \\r\\n1257 | ```c++\\r\\n1258 | virtual void DestroySwapTextureSet( vr::SharedTextureHandle_t sharedTextureHandle ) {};\\r\\n1259 | ```\\r\\n1260 | \\r\\n1261 | `DestroySwapTextureSet` should destroy textures created using CreateSwapTextureSet.\\r\\n1262 | \\r\\n1263 | Only one of the set's handles needs to be used to destroy the entire set.\\r\\n1264 | \\r\\n1265 | * `vr::SharedTextureHandle_t sharedTextureHandle` - Handle to destroy.\\r\\n1266 | \\r\\n1267 | <br />\\r\\n1268 | \\r\\n1269 | ```c++\\r\\n1270 | virtual void DestroyAllSwapTextureSets( uint32_t unPid ) {}\\r\\n1271 | ```\\r\\n1272 | \\r\\n1273 | `DestroyAllSwapTextureSets` should destroy all textures for the given process.\\r\\n1274 | \\r\\n1275 | * `uint32_t unPid` - pid of the process to destroy the textures from.\\r\\n1276 | \\r\\n1277 | <br />\\r\\n1278 | \\r\\n1279 | ```c++\\r\\n1280 | virtual void GetNextSwapTextureSetIndex( vr::SharedTextureHandle_t sharedTextureHandles[ 2 ], uint32_t( *pIndices )[ 2 ] ) {}\\r\\n1281 | ```\\r\\n1282 | \\r\\n1283 | `GetNextSwapTextureSetIndex` is called after `Present` returns, and is used to get the next index to use for rendering.\\r\\n1284 | \\r\\n1285 | * `vr::SharedTextureHandle_t sharedTextureHandles[ 2 ]` - handles to the textures of each eye. Textures **must** have\\r\\n1286 |   been created using `CreateSwapTextureSet`.\\r\\n1287 | * `uint32_t( *pIndices )[ 2 ]` - Your result for the index to use for each eye.\\r\\n1288 | \\r\\n1289 | <br />\\r\\n1290 | \\r\\n1291 | ```c++\\r\\n1292 | virtual void SubmitLayer( const SubmitLayerPerEye_t( &perEye )[ 2 ] ) {}\\r\\n1293 | ```\\r\\n1294 | \\r\\n1295 | `SubmitLayer` is called once per layer to draw for this frame.\\r\\n1296 | \\r\\n1297 | * `const SubmitLayerPerEye_t( &perEye )[ 2 ]` - The layer to draw per eye.\\r\\n1298 |     * `vr::SharedTextureHandle_t sharedTextureHandle` - Handle to the texture to draw. Textures **must** have been\\r\\n1299 |       created using `CreateSwapTextureSet`.\\r\\n1300 |     * `vr::SharedTextureHandle_t hDepthTexture` - Depth texture. Not always provided.\\r\\n1301 |     * `vr::VRTextureBounds_t bounds` - Valid region and depth of provided texture.\\r\\n1302 |     * `vr::HmdMatrix44_t mProjection` - The projection matrix used to render the depth buffer.\\r\\n1303 |     * `vr::HmdMatrix34_t mHmdPose` - Hmd pose that was used to render this layer.\\r\\n1304 | \\r\\n1305 | <br />\\r\\n1306 | \\r\\n1307 | ```c++\\r\\n1308 | virtual void Present( vr::SharedTextureHandle_t syncTexture ) {}\\r\\n1309 | ```\\r\\n1310 | \\r\\n1311 | `Present` is called to submit the queued layers for display.\\r\\n1312 | \\r\\n1313 | ```c++\\r\\n1314 | void Present(vr::SharedTextureHandle_t syncTexture) {\\r\\n1315 |   // Open sync texture only when it changes.\\r\\n1316 |   if (m_syncTexture != syncTexture) {\\r\\n1317 |       m_syncTexture = syncTexture;\\r\\n1318 |       SAFE_RELEASE( m_pSyncTexture );\\r\\n1319 |       if (m_syncTexture) {\\r\\n1320 |           m_pD3D11Device->OpenSharedResource( ( HANDLE )m_syncTexture, __uuidof( ID3D11Texture2D ), ( void ** )&m_pSyncTexture );\\r\\n1321 |       }\\r\\n1322 |   }\\r\\n1323 |   \\r\\n1324 |   IDXGIKeyedMutex *pSyncMutex = NULL;\\r\\n1325 |   if (m_pSyncTexture != NULL && SUCCEEDED(m_pSyncTexture->QueryInterface(__uuidof(IDXGIKeyedMutex), (void **)&pSyncMutex))) {\\r\\n1326 |       pSyncMutex->AcquireSync(0, 10);\\r\\n1327 |   }\\r\\n1328 | \\r\\n1329 |   //...\\r\\n1330 |   \\r\\n1331 |   if (pSyncMutex) {\\r\\n1332 |       pSyncMutex->ReleaseSync( 0 );\\r\\n1333 |       pSyncMutex->Release();\\r\\n1334 |   }\\r\\n1335 | }\\r\\n1336 | ```\\r\\n1337 | \\r\\n1338 | <br />\\r\\n1339 | \\r\\n1340 | ```c++\\r\\n1341 | virtual void PostPresent( const Throttling_t *pThrottling ) {}\\r\\n1342 | ```\\r\\n1343 | \\r\\n1344 | `PostPresent` is an optional method for a driver to implement, and is called after `Present` returns and after the\\r\\n1345 | compositor is aware the driver has acquired the sync texture to allow the driver to take more time until vsync after\\r\\n1346 | they've successfully acquired the sync texture in `Present`.\\r\\n1347 | \\r\\n1348 | * `const Throttling_t *pThrottling` - Throttling information set by the user\\r\\n1349 |     * `uint32_t nFramesToThrottle` - Set from the settings key `k_pch_SteamVR_FramesToThrottle_Int32` under an app key.\\r\\n1350 |     * `uint32_t  nAdditionalFramesToPredict` - Set from the settings key `k_pch_SteamVR_AdditionalFramesToPredict_Int32`\\r\\n1351 |       under an app key.\\r\\n1352 | \\r\\n1353 | <br/>\\r\\n1354 | \\r\\n1355 | ```c++\\r\\n1356 | virtual void GetFrameTiming( DriverDirectMode_FrameTiming *pFrameTiming ) {}\\r\\n1357 | ```\\r\\n1358 | \\r\\n1359 | `GetFrameTiming` is an optional method for a driver to implement and is called to get additional frame timing stats from\\r\\n1360 | the driver.\\r\\n1361 | \\r\\n1362 | * `DriverDirectMode_FrameTiming *pFrameTiming` - Frame timing data provided by the driver\\r\\n1363 |     * `uint32_t nSize` - Size of the struct\\r\\n1364 |     * `uint32_t nNumFramePresents` - Number of times the frame was presented\\r\\n1365 |     * `uint32_t nNumMisPresented` - Number of times the frame was presented on a vsync other than it was predicted to\\r\\n1366 |     * `uint32_t nNumDroppedFrames` - Number of times previous frame was scanned out (i.e. compositor missed vsync).\\r\\n1367 |     * `uint32_t m_nReprojectionFlags` - Flags for reprojection information.\\r\\n1368 |         * `VRCompositor_ReprojectionMotion_Enabled` - Motion smoothing is enabled in the UI for the currently running\\r\\n1369 |           application\\r\\n1370 |         * `VRCompositor_ReprojectionMotion_ForcedOn` - Motion smoothing is forced on in the UI for the currently running\\r\\n1371 |           application\\r\\n1372 |         * `VRCompositor_ReprojectionMotion_AppThrottled` - Application is requesting throttling\\r\\n1373 |           via `ForceInterleavedReprojectionOn`.\\r\\n1374 | \\r\\n1375 | #### IVRVirtualDisplay\\r\\n1376 | \\r\\n1377 | Used for drivers that implement a virtual display and need to access the final composited backbuffer image without\\r\\n1378 | transmitting to a real display, such as for transmitting wirelessly.\\r\\n1379 | \\r\\n1380 | From the perspective of the runtime, the compositor is interfacing with a virtual, rather than actual, display. This\\r\\n1381 | makes it a critical piece of the render pipeline, and drivers **must** get the timing correct in order to continue\\r\\n1382 | providing a proper experience to the user.\\r\\n1383 | \\r\\n1384 | As `IVRVirtualDisplay` is expected to be implemented as a _device component_, it **must** implement\\r\\n1385 | a [ITrackedDeviceServerDriver](#itrackeddeviceserverdriver).\\r\\n1386 | \\r\\n1387 | The following properties **must** be set for the device to have a virtual display component:\\r\\n1388 | \\r\\n1389 | * It is added to the runtime as a `vr::TrackedDeviceClass_DisplayRedirect` device class. (see below).\\r\\n1390 | * `redirectsDisplay` is set to `true` in [driver.vrdrivermanifest](#drivervrdrivermanifest).\\r\\n1391 | \\r\\n1392 | ```c++\\r\\n1393 |   vr::VRServerDriverHost()->TrackedDeviceAdded(\\\"my_serial_ABC123\\\", vr::TrackedDeviceClass_DisplayRedirect, &myVirtualDisplayDevice);\\r\\n1394 | ```\\r\\n1395 | \\r\\n1396 | <br />\\r\\n1397 | \\r\\n1398 | ```c++\\r\\n1399 | virtual void Present( const PresentInfo_t *pPresentInfo, uint32_t unPresentInfoSize ) = 0;\\r\\n1400 | ```\\r\\n1401 | \\r\\n1402 | `Present` is called once per frame after all rendering has been submitted to the GPU and provides the final backbuffer\\r\\n1403 | to display.\\r\\n1404 | \\r\\n1405 | `Present` **should** avoid any blocking calls on any operations such as reading the texture, and instead queue these\\r\\n1406 | commands to return as soon as possible. `WaitForPresent` is provided for calling the blocking operations.\\r\\n1407 | \\r\\n1408 | * `const PresentInfo_t *pPresentInfo` - Contains information about backbuffer.\\r\\n1409 |     * `SharedTextureHandle_t backbufferTextureHandle` - Handle to the backbuffer texture.\\r\\n1410 |     * `EVSync vsync` - Vsync information\\r\\n1411 |         * `VSync_None` - No vsync\\r\\n1412 |         * `VSync_WaitRender` - Block following render work until vsync occurs.\\r\\n1413 |         * `VSync_NoWaitRender` - Do not block following render work, allowing work to get started early.\\r\\n1414 |     * `uint64_t nFrameId` - Frame ID of the current frame.\\r\\n1415 |     * `double flVSyncTimeInSeconds` - Time in seconds when vsync occurred.\\r\\n1416 | * `uint32_t unPresentInfoSize` - Size of the current `PresentInfo_t` struct.\\r\\n1417 | \\r\\n1418 | <br />\\r\\n1419 | \\r\\n1420 | ```c++\\r\\n1421 | virtual void WaitForPresent() = 0;\\r\\n1422 | ```\\r\\n1423 | \\r\\n1424 | `WaitForPresent` is called to allow the driver to perform blocking calls on operations that might have been queued\\r\\n1425 | in `Present`.\\r\\n1426 | \\r\\n1427 | <br />\\r\\n1428 | \\r\\n1429 | ```c++\\r\\n1430 | virtual bool GetTimeSinceLastVsync( float *pfSecondsSinceLastVsync, uint64_t *pulFrameCounter ) = 0;\\r\\n1431 | ```\\r\\n1432 | \\r\\n1433 | `GetTimeSinceLastVsync` is called to provide timing data for synchronizing with the display.\\r\\n1434 | \\r\\n1435 | `GetTimeSinceLastVsync` is called after `WaitForPresent` returns. It **should** return the time, in seconds, since the\\r\\n1436 | last _virtual_ vsync event.\\r\\n1437 | \\r\\n1438 | * `float *pfSecondsSinceLastVsync` - The time, in seconds, since the last _virtual_ vsync event. This is the offset from\\r\\n1439 |   the physical device timing by the additional latency introduced by the virtual driver, specified by the driver in\\r\\n1440 |   the `vr::Prop_SecondsFromVsyncToPhotons_Float` property.\\r\\n1441 | * `uint64_t *pulFrameCounter` - Current frame count. This is a monotonically increasing value and **should** reflect the\\r\\n1442 |   virtual vsync count, rather than the number of frames presented in order for the runtime to detect dropped frames.\\r\\n1443 | \\r\\n1444 | <br />\\r\\n1445 | \\r\\n1446 | See this repository for an example `IVRVirtualDisplay` implementation: https://github.com/ValveSoftware/virtual_display.\\r\\n1447 | \\r\\n1448 | ## IVRServerDriverHost\\r\\n1449 | \\r\\n1450 | `IVRServerDriverHost` allows the driver to notify the runtime about a state change to the driver or a device.\\r\\n1451 | \\r\\n1452 | A pointer is returned to the implementation of `IVRServerDriverHost` in the runtime from\\r\\n1453 | calling `vr::VRServerDriverHost()`.\\r\\n1454 | \\r\\n1455 | <br />\\r\\n1456 | \\r\\n1457 | ```c++\\r\\n1458 | virtual bool TrackedDeviceAdded( const char *pchDeviceSerialNumber, ETrackedDeviceClass eDeviceClass, ITrackedDeviceServerDriver *pDriver ) = 0;\\r\\n1459 | ```\\r\\n1460 | \\r\\n1461 | `TrackedDeviceAdded` **should** be called whenever a driver wishes to add a device to the runtime.\\r\\n1462 | \\r\\n1463 | * `const char *pchDeviceSerialNumber` - A string that is a unique and immutable serial number of the device that you are\\r\\n1464 |   about to add to the server. A device's serial number **cannot** change after the device has been added to the runtime.\\r\\n1465 | * `ETrackedDeviceClass eDeviceClass` - The type of device that is about to activate.\\r\\n1466 |     * `TrackedDeviceClass_HMD` - Head Mounted Display.\\r\\n1467 |     * `TrackedDeviceClass_Controller` - Tracked controllers.\\r\\n1468 |     * `TrackedDeviceClass_GenericTracker` - Generic trackers, similar to controllers but without a defined handed role.\\r\\n1469 |     * `TrackedDeviceClass_TrackingReference` - Tracking References, such as cameras and base stations that serve as\\r\\n1470 |       tracking reference points.\\r\\n1471 |     * `TrackedDeviceClass_DisplayRedirect` - Accessories that aren't necessarily tracked themselves, but may redirect\\r\\n1472 |       video output from other tracked devices. See [IVRVirtualDisplay](#ivrvirtualdisplay).\\r\\n1473 | * `ITrackedDeviceServerDriver *pDriver` - A pointer to the `ITrackedDeviceServerDriver` implementation for this class.\\r\\n1474 | \\r\\n1475 | The serial number of the device **must not** change throughout the session. The serial number represents a unique\\r\\n1476 | identifier for each device.\\r\\n1477 | \\r\\n1478 | The pointer provided for `ITrackedDeviceServerDriver` **must** remain valid\\r\\n1479 | until `IServerTrackedDeviceProvider::Cleanup` is called.\\r\\n1480 | \\r\\n1481 | Returns true if:\\r\\n1482 | \\r\\n1483 | * The device has a valid serial number.\\r\\n1484 | * There is not already a device with the same serial number in the system.\\r\\n1485 | * The device is within the same driver as the HMD active in the system, **or** `activateMultipleDrivers` is true.\\r\\n1486 | * There is not already an HMD in system or the device isn't an HMD.\\r\\n1487 | \\r\\n1488 | If `TrackedDeviceAdded` returns true, then the device has been queued to activate, but there is no guarantee that the\\r\\n1489 | device will be able to be successfully activated from the return value of this method.\\r\\n1490 | \\r\\n1491 | <br/>\\r\\n1492 | \\r\\n1493 | ```c++\\r\\n1494 | virtual void TrackedDevicePoseUpdated( uint32_t unWhichDevice, const DriverPose_t & newPose, uint32_t unPoseStructSize ) = 0;\\r\\n1495 | ```\\r\\n1496 | \\r\\n1497 | `TrackedDevicePoseUpdated` **should** be called whenever a device wishes to update its pose.\\r\\n1498 | \\r\\n1499 | * `uint32_t unWhichDevice` - The device index that should be updated\\r\\n1500 | * `const DriverPose_t & newPose` - The pose of the device\\r\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\ndocs\\\\Driver_API_Documentation.md\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:34:48 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n87,420 (44%)\\n\\n# Current Cost\\n$0.66\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":145,\"cacheWrites\":9392,\"cacheReads\":87271,\"cost\":0.0635883}"},{"ts":1744500892818,"type":"say","say":"text","text":"I've gathered a lot of information about the OpenVR driver architecture and how to implement a custom driver. Let me continue reading to find more information about how to access IMU data and how to implement a custom driver that wraps the existing lighthouse driver.\n\nLet me continue reading the Driver API Documentation to understand more about how to implement a custom driver component and access IMU data:","partial":false},{"ts":1744500894879,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"docs/Driver_API_Documentation.md\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\docs\\\\Driver_API_Documentation.md\",\"reason\":\" (lines 1500-2000)\"}","partial":false},{"ts":1744500898409,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'docs/Driver_API_Documentation.md'] Result:\\n\\n<file><path>docs/Driver_API_Documentation.md</path>\\n<content lines=\\\"1500-2000\\\">\\n1500 | * `const DriverPose_t & newPose` - The pose of the device\\r\\n1501 | * `uint32_t unPoseStructSize` - The size of DriverPose_t\\r\\n1502 | \\r\\n1503 | <br/>\\r\\n1504 | \\r\\n1505 | ```c++\\r\\n1506 | virtual void VsyncEvent( double vsyncTimeOffsetSeconds ) = 0;\\r\\n1507 | ```\\r\\n1508 | \\r\\n1509 | `VsyncEvent` notifies the server that vsync has occurred on the display attached to the device. This is only\\r\\n1510 | permitted on devices of the HMD class.\\r\\n1511 | \\r\\n1512 | * `double vsyncTimeOffsetSeconds` - The time offset of the vsync event in seconds.\\r\\n1513 | \\r\\n1514 | <br/>\\r\\n1515 | \\r\\n1516 | ```c++\\r\\n1517 | virtual void VendorSpecificEvent( uint32_t unWhichDevice, vr::EVREventType eventType, const VREvent_Data_t & eventData, double eventTimeOffset ) = 0;\\r\\n1518 | ```\\r\\n1519 | \\r\\n1520 | `VendorSpecificEvent` sends an event to the global event queue. The device that calls this function **can** choose to\\r\\n1521 | send a *defined* event within `vr::EVREventType`, or use a custom, reserved, event type\\r\\n1522 | between `VREvent_VendorSpecific_Reserved_Start` and `VREvent_VendorSpecific_Reserved_End`.\\r\\n1523 | \\r\\n1524 | * `uint32_t unWhichDevice` - The device index that triggered this event. This **must** be a valid device index.\\r\\n1525 | * `vr::EVREventType eventType` - The event type. The value of `eventType` **must** be greater than 0 and less\\r\\n1526 |   than `VREvent_VendorSpecific_Reserved_End`.\\r\\n1527 | * `const VREvent_Data_t & eventData` - The data of the event.\\r\\n1528 | * `double eventTimeOffset` - Time offset of the event from now, in seconds.\\r\\n1529 | \\r\\n1530 | <br/>\\r\\n1531 | \\r\\n1532 | ```c++\\r\\n1533 | virtual bool IsExiting() = 0;\\r\\n1534 | ```\\r\\n1535 | \\r\\n1536 | Returns true if the runtime is exiting, false if it is not.\\r\\n1537 | \\r\\n1538 | <br/>\\r\\n1539 | \\r\\n1540 | ```c++\\r\\n1541 | virtual bool PollNextEvent( VREvent_t *pEvent, uint32_t uncbVREvent ) = 0;\\r\\n1542 | ```\\r\\n1543 | \\r\\n1544 | Polls the next event in the global event queue. The function **must** return true if there is an event on the event\\r\\n1545 | queue, and false if there are none.\\r\\n1546 | \\r\\n1547 | Once the event has been read off the queue, it is removed.\\r\\n1548 | \\r\\n1549 | * `VREvent_t *pEvent` - A pointer to where the method should fill the event.\\r\\n1550 | * `uint32_t uncbVREvent` - Size in bytes of the VREvent_t struct.\\r\\n1551 | \\r\\n1552 | Drivers **should** poll for events every frame. This makes it ideal to use\\r\\n1553 | in `IServerTrackedDeviceProvider::MyRunFrame`.\\r\\n1554 | \\r\\n1555 | Events are time sensitive, and may be removed shortly after being added to the queue. They **must** exist for at least\\r\\n1556 | one frame after the event was added to the queue.\\r\\n1557 | \\r\\n1558 | `PollNextEvent` **can** be continually called, until it returns `false`, where there are no more events on the queue.\\r\\n1559 | \\r\\n1560 | ```c++\\r\\n1561 | vr::VREvent_t vrEvent;\\r\\n1562 | while ( vr::VRServerDriverHost()->PollNextEvent( &vrEvent, sizeof( vrEvent )))\\r\\n1563 | {\\r\\n1564 |     switch ( vrEvent.eventType )\\r\\n1565 |     {\\r\\n1566 |         case vr::VREvent_Input_HapticVibration:\\r\\n1567 |         {\\r\\n1568 |             if ( vrEvent.data.hapticVibration.componentHandle == m_compMyHaptic )\\r\\n1569 |             {\\r\\n1570 |             ... send data to hardware\\r\\n1571 |             }\\r\\n1572 |         }\\r\\n1573 |     break;\\r\\n1574 |     }\\r\\n1575 | }\\r\\n1576 | ```\\r\\n1577 | \\r\\n1578 | <br/>\\r\\n1579 | \\r\\n1580 | ```c++\\r\\n1581 | virtual void GetRawTrackedDevicePoses( float fPredictedSecondsFromNow, TrackedDevicePose_t *pTrackedDevicePoseArray, uint32_t unTrackedDevicePoseArrayCount ) = 0;\\r\\n1582 | ```\\r\\n1583 | \\r\\n1584 | `GetRawTrackedDevicePoses` provides access to all active device poses.\\r\\n1585 | \\r\\n1586 | Device poses **will** be in their raw tracking space. This tracking space is uniquely defined by each driver providing\\r\\n1587 | poses for its devices.\\r\\n1588 | \\r\\n1589 | * `float fPredictedSecondsFromNow` - How far in time to predict the pose of the device. Negative numbers for the past,\\r\\n1590 |   positive for predicting in the future.\\r\\n1591 | * `TrackedDevicePose_t *pTrackedDevicePoseArray` - A user-specified-size array that will be filled with device poses\\r\\n1592 | * `uint32_t unTrackedDevicePoseArrayCount` - Length of the pose array supplied.\\r\\n1593 | \\r\\n1594 | `pTrackedDevicePoseArray` **will** be filled with poses of devices, with the index of the array correlating to the\\r\\n1595 | device index stored in the runtime.\\r\\n1596 | \\r\\n1597 | The HMD pose **will** always be at index 0.\\r\\n1598 | \\r\\n1599 | `GetRawTrackedDevicePoses` **will** fill `pTrackedDevicePoseArray` to the specified `unTrackedDevicePoseArrayCount`, or\\r\\n1600 | up until there are no more devices.\\r\\n1601 | \\r\\n1602 | ```c++\\r\\n1603 | vr::TrackedDevicePose_t GetDevicePose( vr::TrackedDeviceIndex_t unDeviceIndex )\\r\\n1604 | {\\r\\n1605 |     vr::TrackedDevicePose_t poses[unDeviceIndex];\\r\\n1606 |     vr::VRServerDriverHost()->GetRawTrackedDevicePoses( 0.0, &pose, unDeviceIndex );\\r\\n1607 |     return poses[unDeviceIndex];\\r\\n1608 | }\\r\\n1609 | ```\\r\\n1610 | \\r\\n1611 | `vr::TrackedDevicePose_t` contains a `HmdMatrix34_t mDeviceToAbsoluteTracking`, a 3x4 matrix, that contains a 3x3\\r\\n1612 | rotation matrix and a position vector (in the end column).\\r\\n1613 | \\r\\n1614 | The functions below can be used to extract a position, and rotation (as a quaternion) from the 3x4 matrix:\\r\\n1615 | \\r\\n1616 | ```c++\\r\\n1617 | vr::HmdVector3_t GetPosition(const vr::HmdMatrix34_t& matrix) {\\r\\n1618 |   return {\\r\\n1619 |       matrix.m[0][3],\\r\\n1620 |       matrix.m[1][3],\\r\\n1621 |       matrix.m[2][3]\\r\\n1622 |   };\\r\\n1623 | }\\r\\n1624 | \\r\\n1625 | vr::HmdQuaternion_t GetRotation(const vr::HmdMatrix34_t& matrix) {\\r\\n1626 |   vr::HmdQuaternion_t q{};\\r\\n1627 | \\r\\n1628 |   q.w = sqrt(fmax(0, 1 + matrix.m[0][0] + matrix.m[1][1] + matrix.m[2][2])) / 2;\\r\\n1629 |   q.x = sqrt(fmax(0, 1 + matrix.m[0][0] - matrix.m[1][1] - matrix.m[2][2])) / 2;\\r\\n1630 |   q.y = sqrt(fmax(0, 1 - matrix.m[0][0] + matrix.m[1][1] - matrix.m[2][2])) / 2;\\r\\n1631 |   q.z = sqrt(fmax(0, 1 - matrix.m[0][0] - matrix.m[1][1] + matrix.m[2][2])) / 2;\\r\\n1632 | \\r\\n1633 |   q.x = copysign(q.x, matrix.m[2][1] - matrix.m[1][2]);\\r\\n1634 |   q.y = copysign(q.y, matrix.m[0][2] - matrix.m[2][0]);\\r\\n1635 |   q.z = copysign(q.z, matrix.m[1][0] - matrix.m[0][1]);\\r\\n1636 | \\r\\n1637 |   return q;\\r\\n1638 | }\\r\\n1639 | ```\\r\\n1640 | \\r\\n1641 | <br/>\\r\\n1642 | \\r\\n1643 | ```c++\\r\\n1644 | virtual void RequestRestart( const char *pchLocalizedReason, const char *pchExecutableToStart, const char *pchArguments, const char *pchWorkingDirectory ) = 0;\\r\\n1645 | ```\\r\\n1646 | \\r\\n1647 | `RequestRestart` requests that SteamVR be restarted.\\r\\n1648 | \\r\\n1649 | The method **can** be called to open an executable when the runtime is restarted.\\r\\n1650 | \\r\\n1651 | * `const char *pchLocalizedReason` - Required. The reason why the runtime needs to be restarted. **Should** be in the\\r\\n1652 |   current locale of the user. Localized strings within the runtime start with '#'.\\r\\n1653 | * `const char *pchExecutableToStart` - Optional. The file name of the executable to start on runtime restart.\\r\\n1654 |   Pass `nullptr` to just restart the runtime.\\r\\n1655 | * `const char *pchArguments` - Optional (Required if `pchExecutableToStart` set). The arguments for the executable to\\r\\n1656 |   start on runtime restart. Pass `nullptr` to just restart the runtime.\\r\\n1657 | * `const char *pchWorkingDirectory` - Optional (Required if `pchExecutableToStart` set). The working directory for the\\r\\n1658 |   executable to start on runtime restart. Pass `nullptr` to just restart the runtime.\\r\\n1659 | \\r\\n1660 | <br/>\\r\\n1661 | \\r\\n1662 | ```c++\\r\\n1663 | virtual uint32_t GetFrameTimings( Compositor_FrameTiming *pTiming, uint32_t nFrames ) = 0;\\r\\n1664 | ```\\r\\n1665 | \\r\\n1666 | `GetFrameTimings` provides access for copying a range of the compositor's timing data.\\r\\n1667 | \\r\\n1668 | Intended for driver direct mode components for making throttling decisions.\\r\\n1669 | \\r\\n1670 | Frames are returned in ascending order (oldest to newest) with the last being the most recent frame.\\r\\n1671 | \\r\\n1672 | * `Compositor_FrameTiming *pTiming` - where to fill timing data to. Only the first entry's `m_nSize` will be set, and\\r\\n1673 |   others can be inferred from that.\\r\\n1674 | * `uint32_t nFrames` - number of frame timings to request.\\r\\n1675 | \\r\\n1676 | Returns total number of entries filled out.\\r\\n1677 | \\r\\n1678 | <br/>\\r\\n1679 | \\r\\n1680 | ```c++\\r\\n1681 | virtual void SetDisplayEyeToHead( uint32_t unWhichDevice, const HmdMatrix34_t & eyeToHeadLeft, const HmdMatrix34_t & eyeToHeadRight ) = 0;\\r\\n1682 | ```\\r\\n1683 | \\r\\n1684 | `SetDisplayEyeToHead` notifies the server that a tracked device's display component transforms have been updated.\\r\\n1685 | \\r\\n1686 | * `uint32_t unWhichDevice` - The device to update. This device **must** be a `TrackedDeviceClass_HMD`, and **should** be\\r\\n1687 |   device index 0.\\r\\n1688 | * `const HmdMatrix34_t & eyeToHeadLeft` - The transform for the left eye.\\r\\n1689 | * `const HmdMatrix34_t & eyeToHeadRight` - The transform for the right eye.\\r\\n1690 | \\r\\n1691 | <br/>\\r\\n1692 | \\r\\n1693 | ```c++\\r\\n1694 | virtual void SetDisplayProjectionRaw( uint32_t unWhichDevice, const HmdRect2_t & eyeLeft, const HmdRect2_t & eyeRight ) = 0;\\r\\n1695 | ```\\r\\n1696 | \\r\\n1697 | `SetDisplayProjectionRaw` notifies the server that a tracked device's display projection has changed.\\r\\n1698 | \\r\\n1699 | * `uint32_t unWhichDevice` - The device to update. This device **must** be a `TrackedDeviceClass_HMD`, and **should** be\\r\\n1700 |   device index 0.\\r\\n1701 | * `const HmdRect2_t & eyeLeft` - The display projections for the left eye.\\r\\n1702 | * `const HmdRect2_t & eyeRight` - The display projections for the right eye.\\r\\n1703 | \\r\\n1704 | <br/>\\r\\n1705 | \\r\\n1706 | ```c++\\r\\n1707 | virtual void SetRecommendedRenderTargetSize( uint32_t unWhichDevice, uint32_t nWidth, uint32_t nHeight ) = 0;\\r\\n1708 | ```\\r\\n1709 | \\r\\n1710 | `SetRecommendedRenderTargetSize` notifies the server that a tracked device's recommended render target resolution has\\r\\n1711 | changed.\\r\\n1712 | \\r\\n1713 | * `uint32_t unWhichDevice` - The device to update. This device **must** be a `TrackedDeviceClass_HMD`, and **should** be\\r\\n1714 |   device index 0.\\r\\n1715 | * `uint32_t nWidth` - Resolution width, in pixels.\\r\\n1716 | * `uint32_t nHeight` - Resolution height, in pixels.\\r\\n1717 | \\r\\n1718 | ## IVRDriverLog\\r\\n1719 | \\r\\n1720 | The `IVRDriverLog` interface **can** be used for drivers to log to a shared runtime log file.\\r\\n1721 | \\r\\n1722 | SteamVR provides a web interface for viewing logs in realtime (SteamVR Menu > Developer > Web Console), or can be\\r\\n1723 | accessed from this URL: `http://localhost:27062/console/index.html`.\\r\\n1724 | \\r\\n1725 | A text file containing the last session's log is available here:\\r\\n1726 | \\r\\n1727 | * `<steam_install_dir>\\\\logs\\\\vrserver.txt`.\\r\\n1728 |     * Most commonly, the full path to this is: `C:\\\\Program Files (x86)\\\\Steam\\\\logs\\\\vrserver.txt`.\\r\\n1729 | \\r\\n1730 | A text file from the second to last session's log is available here:\\r\\n1731 | \\r\\n1732 | * `<steam_install_dir>\\\\logs\\\\vrserver.previous.txt`.\\r\\n1733 |     * Most commonly, the full path to this is: `C:\\\\Program Files (x86)\\\\Steam\\\\logs\\\\vrserver.previous.txt`.\\r\\n1734 | \\r\\n1735 | Messages from a driver **will** be formatted like so:\\r\\n1736 | \\r\\n1737 | `<date> - <driver_name>: <log_message>`.\\r\\n1738 | \\r\\n1739 | <br>\\r\\n1740 | \\r\\n1741 | ```c++\\r\\n1742 | virtual void Log( const char *pchLogMessage ) = 0;\\r\\n1743 | ```\\r\\n1744 | \\r\\n1745 | `Log` logs a message to the shared runtime log file.\\r\\n1746 | \\r\\n1747 | * `const char *pchLogMessage` - The message to log to the file. **Must** be null-terminated.\\r\\n1748 | \\r\\n1749 | A wrapper for this interface is provided in `samples/utils/driverlog` to make the logging interface behave\\r\\n1750 | like a `printf` function.\\r\\n1751 | \\r\\n1752 | ## IVRWatchdogProvider\\r\\n1753 | \\r\\n1754 | `IVRWatchdogProvider` provides an interface that is loaded into `steam.exe` to receive driver-defined events that should\\r\\n1755 | wake the runtime. For example, this could be turning on controllers, or putting the HMD on.\\r\\n1756 | \\r\\n1757 | `steam.exe` **must** be running for the watchdog to be active.\\r\\n1758 | \\r\\n1759 | `IVRWatchdogProvider` **must** be built into a 32-bit DLL, as `steam.exe` is 32-bit.\\r\\n1760 | \\r\\n1761 | ```c++\\r\\n1762 | virtual EVRInitError Init( IVRDriverContext *pDriverContext ) = 0;\\r\\n1763 | ```\\r\\n1764 | \\r\\n1765 | `Init` is called on SteamVR exit when the DLL is loaded into `steam.exe`. A driver **should** spin up a thread here to\\r\\n1766 | listen for hardware events.\\r\\n1767 | \\r\\n1768 | `Init` **will** initialize the watchdog driver context. You **can** use the macro `VR_INIT_WATCHDOG_DRIVER_CONTEXT`\\r\\n1769 | provided by the OpenVR API to do this.\\r\\n1770 | \\r\\n1771 | <br/>\\r\\n1772 | \\r\\n1773 | ```c++\\r\\n1774 | virtual void Cleanup() = 0;\\r\\n1775 | ```\\r\\n1776 | \\r\\n1777 | `Cleanup` is called right before the watchdog is unloaded to clean up any resources it has required while being active.\\r\\n1778 | \\r\\n1779 | ### IVRWatchdogHost\\r\\n1780 | \\r\\n1781 | This interface is provided by the runtime to allow a driver to wake up the runtime.\\r\\n1782 | \\r\\n1783 | <br/>\\r\\n1784 | \\r\\n1785 | ```c++\\r\\n1786 | virtual void WatchdogWakeUp( vr::ETrackedDeviceClass eDeviceClass ) = 0;\\r\\n1787 | ```\\r\\n1788 | \\r\\n1789 | When the `IVRWatchdogProvider` would like to wake the runtime, the watchdog **should** call this function, specifying\\r\\n1790 | the `ETrackedDeviceClass` that caused the runtime to start (HMD, Controller, etc.)\\r\\n1791 | \\r\\n1792 | * `vr::ETrackedDeviceClass eDeviceClass` - The device class that caused the runtime to start.\\r\\n1793 | \\r\\n1794 | ## Device Inputs\\r\\n1795 | \\r\\n1796 | It is impossible to predict what kinds of inputs devices might have in the future. It is also infeasible to expect all\\r\\n1797 | application developers to have explicit support for all devices, and to continue support their applications with devices\\r\\n1798 | released further into the future.\\r\\n1799 | \\r\\n1800 | To solve this problem, the OpenVR API creates a divide between physical device *inputs*, and in-application *actions*.\\r\\n1801 | \\r\\n1802 | A device exposes the set of inputs it has. For example, a device might have a joystick, a trigger button and a\\r\\n1803 | thumbpad.\\r\\n1804 | \\r\\n1805 | An application exposes the set of actions it has support for. For example, an action might be firing a gun, or invoking\\r\\n1806 | a teleport.\\r\\n1807 | \\r\\n1808 | *Binding profiles* then link these inputs to actions. For example, the trigger button on an index controller\\r\\n1809 | could be bound to a gun trigger pull action.\\r\\n1810 | \\r\\n1811 | What are defined as inputs or actions are up to the developers. However, there are certain restrictions on the\\r\\n1812 | data that can be submitted as an input and received as an action.\\r\\n1813 | \\r\\n1814 | Each controller device type **should** expose _one_ input profile, which represents the set of input components a device\\r\\n1815 | has available to be bound.\\r\\n1816 | \\r\\n1817 | ### Input Profiles\\r\\n1818 | \\r\\n1819 | Input profiles are expected to be a _valid_ JSON file, and **should** be\\r\\n1820 | located: `<driver_name>/resources/input/<device_name>_profile.json`.\\r\\n1821 | \\r\\n1822 | This file location **must** be specified by setting `vr::ETrackedDeviceProperty::Prop_InputProfilePath_String` property\\r\\n1823 | for each device. See [device properties](#device-properties) for information on properties.\\r\\n1824 | \\r\\n1825 | #### Input sources\\r\\n1826 | \\r\\n1827 | An *input source* is a single piece of hardware used for input on a device. For example, a joystick or a button.\\r\\n1828 | \\r\\n1829 | An *input component* is a single bit of an input that the hardware can measure. For example, a button click or the\\r\\n1830 | joystick Y value.\\r\\n1831 | \\r\\n1832 | *Input components* can be grouped into one *input source*, to allow the user to manipulate them as a logical\\r\\n1833 | group. For example, a joystick (the input source) can measure X,Y and click values (the input components).\\r\\n1834 | \\r\\n1835 | An *input source* is identified by the path `/input/<input_source>`.\\r\\n1836 | \\r\\n1837 | An input component is identified by the path `/input/<input_source>/<input_component>`.\\r\\n1838 | \\r\\n1839 | For example, the input source `/input/joystick` contains the input components `/input/joystick/x`, `/input/joystick/y`\\r\\n1840 | and optionally `/input/joystick/click`, and `/input/joystick/touch`.\\r\\n1841 | \\r\\n1842 | Devices **should not** simulate one kind of input with another (for instance applying a threshold to provide\\r\\n1843 | a `/input/trigger/click` value when no physical switch exists on the hardware.) This will allow SteamVR to provide the\\r\\n1844 | user the ability to set the scalar to analog conversion behavior per application instead of using a global hard-coded\\r\\n1845 | value.\\r\\n1846 | \\r\\n1847 | ### Input Profile JSON\\r\\n1848 | \\r\\n1849 | The input profile JSON file contains input and binding information for each device.\\r\\n1850 | \\r\\n1851 | The list of keys that can be specified in the JSON file are:\\r\\n1852 | \\r\\n1853 | * `jsonid` - Required. This **must** be set to `input_profile`.\\r\\n1854 | * `controller_type` - Required if `Prop_ControllerType_String` has not been specified by the device. This is the\\r\\n1855 |   controller type that this profile is for. This is used to match the profile to the device.\\r\\n1856 | * `compatibility_mode_controller_type` - **(deprecated in v1.26)** Specifies that the device should emulate the specified device type when a binding is unavailable.\\r\\n1857 |   Within a binding it will set the following values:\\r\\n1858 |     * `simulated_controller_type` to the specified controller type.\\r\\n1859 |     * `simulate_rendermodel` to `true`.\\r\\n1860 |     * `simulate_hmd` to `true`.\\r\\n1861 | * `remapping` - **(v1.26+)** Optional. A json file that details how to convert bindings from one controller type to another. Used when an application doesn't specify a binding for this device type. See: [Automatic Rebinding](#automatic-rebinding).\\r\\n1862 | * `device_class` - Optional. Inferred from the device's `Prop_DeviceClass_Int32` property.\\r\\n1863 | * `hand_priority` - Optional. If `Prop_ControllerHandSelectionPriority_Int32` has not been previously set,\\r\\n1864 |   the value specified here **will** be used for that property, otherwise ignored if the property has already been set.\\r\\n1865 | * `legacy_binding` - Recommended. A fallback to `config/legacy_bindings_generic.json` will be set if this is not. The\\r\\n1866 |   legacy bindings file is the same format as other input binding files, and can be built with the SteamVR binding UI and\\r\\n1867 |   then exported.\\r\\n1868 | * `tracker_types` - Optional. If the input profile is intended to be used with a tracker, a path to another input\\r\\n1869 |   profile **can** be specified. Key is an enum of `ETrackerRole`, and the value is the path to the input profile for the\\r\\n1870 |   specified tracker role.\\r\\n1871 | * `input_bindingui_mode` - Recommended. How to render the device in the bindings UI. A fallback to `hmd` will be set if\\r\\n1872 |   the device's class is `TrackedDeviceClass_HMD`, or set to `controller_handed` otherwise.\\r\\n1873 |     * `controller_handed` - The device type is typically used as a pair, one in each hand. The device can optionally be\\r\\n1874 |       specific to a left or right hand. When using the binding UI with this style of device 2 controllers will be\\r\\n1875 |       displayed.\\r\\n1876 |     * `hmd` - The device is an HMD and wants the binding UI to be in HMD mode when configuring it for input.\\r\\n1877 |     * `single_device` - The device should be on a page by itself, as there is only one device being used at a time by\\r\\n1878 |       the\\r\\n1879 |       user. Examples are xbox-style game controllers, gun style controllers or treadmills.\\r\\n1880 | * `input_bindingui_left` - Strongly Recommended. The path to the image to render for the left hand in the bindings UI.\\r\\n1881 |   Will fall back to a null image if not set.\\r\\n1882 |     * `image` - Path to the image. For example, `{indexcontroller}/icons/indexcontroller_left.svg`. **Must** be an SVG\\r\\n1883 |       or PNG. The binding UI has no fixed size and will scale to the output device so using the SVG format ensures the\\r\\n1884 |       best presentation of your controller. The image **should** display a\\r\\n1885 |       canted view of the controller to show the best view of all the inputs on the device.\\r\\n1886 |     * `transform` is a string that is passed to the CSS transform in the binding UI. Drivers **can** use this to mirror\\r\\n1887 |       the\\r\\n1888 |       device image using the string `scale( -1, 1)`, so a single image can be used for both left and right hands.\\r\\n1889 | * `input_bindingui_right` - Strongly Recommended. The path to the image to render for the right hand in the bindings UI.\\r\\n1890 |   Will fall back to a null image if not set.\\r\\n1891 |     * `image` - Path to the image. For example, `{indexcontroller}/icons/indexcontroller_right.svg`. **Must** be an SVG\\r\\n1892 |       or PNG. The binding UI has no fixed size and will scale to the output device so using the SVG format ensures the\\r\\n1893 |       best presentation of your controller. The image **should** display\\r\\n1894 |       a canted view of the controller to show the best view of all the inputs on the device.\\r\\n1895 |     * `transform` is a string that is passed to the CSS transform in the binding UI. Drivers **can** use this to mirror\\r\\n1896 |       the\\r\\n1897 |       device image using the string `scale( -1, 1)`, so a single image can be used for both left and right hands.\\r\\n1898 | * `input_source`\\r\\n1899 |     * `<input_source_path>` - Path to the input source. Paths **must** be in the format\\r\\n1900 |       of `/<input/pose/finger>/<my_name>`. `finger` **must** be treated as a trigger.\\r\\n1901 |         * `type` - Required. The types available are:\\r\\n1902 |             * `joystick` - The input is a joystick or thumbstick. Input components for this are created automatically,\\r\\n1903 |               listed below:\\r\\n1904 |                 * `x`\\r\\n1905 |                 * `y`\\r\\n1906 |             * `button` - The input is a button with a boolean value.\\r\\n1907 |             * `trigger` - The input is a trigger with a scalar value.\\r\\n1908 |             * `trackpad` - The input is a trackpad. It is different from joystick in that it has a force state.\\r\\n1909 |             * `skeleton` - The input is a skeletal animation source.\\r\\n1910 |             * `haptic` - The input is a haptic component. There can only be one of these bound per device.\\r\\n1911 |             * `pose` - The input is a pose. These are created automatically from the components in the device's\\r\\n1912 |               rendermodel and are also specified here to bind them to an application. Pose names specified here **must**\\r\\n1913 |               match those in the rendermodel file.\\r\\n1914 |                 * `/pose/raw` - Required. The raw pose of the device. This **must** be specified in the input profile\\r\\n1915 |                   and does not need a rendermodel to be set.\\r\\n1916 |         * `binding_image_point` - Recommended. Draws a line in the UI from the input on the side to the image specified\\r\\n1917 |           in `image`. Will fall back to [50, 50].\\r\\n1918 |         * `order` - Optional. The order of the input in the UI. Defaults to 0. Commonly used sources (such as a primary\\r\\n1919 |           trigger) **should** be listed before less used sources. Priority is in ascending order.\\r\\n1920 |         * `click` - Optional. Represents that the input can sense being clicked. Valid for types\\r\\n1921 |           of `joystick`, `button`, `trigger`.\\r\\n1922 |         * `value` - Optional. Represents that the input can sense a scalar value ranging from 0-1. Valid types\\r\\n1923 |           are `trigger`.\\r\\n1924 |         * `touch` - Optional. Represents that the input can sense being touched, but not clicked. Valid for types\\r\\n1925 |           of `joystick`, `button`, `trigger`, `trackpad`.\\r\\n1926 |         * `force` - Optional. Represents that the input can sense force. Valid for types\\r\\n1927 |           of `joystick`, `trigger`, `trackpad`.\\r\\n1928 |         * `input_activity_path` - Optional. The path to the input component that causes the input to count as \\\"active\\\".\\r\\n1929 |           If this is not set, the component that will cause the input source to count as active is (in order):\\r\\n1930 |             * `touch`\\r\\n1931 |             * `click`\\r\\n1932 |             * `force`\\r\\n1933 |             * `value`\\r\\n1934 |             * `x`\\r\\n1935 |         * `input_activity_threshold` - Float. The threshold for this input to count as \\\"active\\\". Defaults to 0. Will\\r\\n1936 |           count as active if value is strictly greater than threshold.\\r\\n1937 |         * `value_source` - Optional. Only valid for `/input/pinch`. The path to the input component to use as the value\\r\\n1938 |           for the current component. The input component pointed to **must** have a `value` component.\\r\\n1939 |         * `force_source` - Optional. Only valid for `/input/pinch`. The path to the input component to use as the force\\r\\n1940 |           value for the current component. The input component pointed to **must** have a `force` component.\\r\\n1941 |         * `capsense_source` - Optional. Only valid for `/input/pinch`. The path to the input component to use as the\\r\\n1942 |           capsense value for the current component. The input component pointed to **must** be a `/input/finger` source.\\r\\n1943 | * `default_bindings` - Optional. An array that lists any binding profiles that should ship with the driver. These link\\r\\n1944 |   in-game actions to the inputs on the device. See [Default Bindings](#default-bindings) for more information.\\r\\n1945 |     * `app_key` - Required. Names the app that the binding will apply to. If this is a steam app, it will be prefixed\\r\\n1946 |       with `steam.app.` with the appId appended.\\r\\n1947 |     * `binding_url` - Required. Path to the bindings profile, relative to the current directory.\\r\\n1948 | \\r\\n1949 | To set an *input component* for a given *input source*, add the *input component name* to the `<input source path>`\\r\\n1950 | object as a key, and set the value to true. For example, a joystick, given the name `thumbstick`, which can\\r\\n1951 | sense `click` and `touch`, **might** look like this:\\r\\n1952 | \\r\\n1953 | ```json\\r\\n1954 | {\\r\\n1955 |   \\\"/input/thumbstick\\\": {\\r\\n1956 |     \\\"type\\\": \\\"joystick\\\",\\r\\n1957 |     \\\"click\\\": true,\\r\\n1958 |     \\\"touch\\\": true,\\r\\n1959 |     \\\"binding_image_point\\\": [\\r\\n1960 |       31,\\r\\n1961 |       26\\r\\n1962 |     ],\\r\\n1963 |     \\\"order\\\": 4\\r\\n1964 |   }\\r\\n1965 | }\\r\\n1966 | ```\\r\\n1967 | \\r\\n1968 | This then creates *input component* paths to:\\r\\n1969 | \\r\\n1970 | * `/input/thumbstick/x`\\r\\n1971 | * `/input/thumbstick/y`\\r\\n1972 | * `/input/thumbstick/click`\\r\\n1973 | * `/input/thumbstick/touch`\\r\\n1974 | \\r\\n1975 | #### Reserved input sources\\r\\n1976 | \\r\\n1977 | There are some input sources that are reserved for specific purposes internal to SteamVR. The values of the sources\\r\\n1978 | defined below **will not** be for applications to bind to, but devices **can** create handles to them (_without_\\r\\n1979 | defining them in the input profile) to allow the user to bind to them.\\r\\n1980 | \\r\\n1981 | * `/input/system/click` - A boolean value that is used to bring up or close the SteamVR dashboard.\\r\\n1982 | * `/proximity` - A boolean value that is true when the user has the headset on. Used for putting the device in/out of\\r\\n1983 |   standby.\\r\\n1984 | \\r\\n1985 | The component path `/input/system/click` is a special case that is used to summon or dismiss the SteamVR dashboard. The\\r\\n1986 | value of this component **will not** be available to applications. This component **does not** need to be set in the\\r\\n1987 | input profile.\\r\\n1988 | \\r\\n1989 | ## Binding Profiles\\r\\n1990 | \\r\\n1991 | Binding profiles, which link input components from an input profile to in-game actions are specified in separate files\\r\\n1992 | to input or action profiles.\\r\\n1993 | \\r\\n1994 | These profiles can either be implemented by game developers, and shipped per-game, or shipped with the driver, using\\r\\n1995 | the `default_bindings` section in the [Input Profile](#input-profiles).\\r\\n1996 | \\r\\n1997 | Depending on who publishes the bindings, there is a certain priority in which binding profiles are chosen. In this\\r\\n1998 | order, binding profiles will be chosen:\\r\\n1999 | \\r\\n2000 | 1. A binding set by the user.\\r\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\ndocs\\\\Driver_API_Documentation.md\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:34:58 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n96,812 (48%)\\n\\n# Current Cost\\n$0.73\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":145,\"cacheWrites\":9614,\"cacheReads\":96663,\"cost\":0.06723839999999999}"},{"ts":1744500903644,"type":"say","say":"text","text":"I've gathered a lot of information about the OpenVR driver architecture and how to implement a custom driver. Let me continue reading to find more information about how to access IMU data and how to implement a custom driver that wraps the existing lighthouse driver.\n\nLet me continue reading the Driver API Documentation to understand more about how to implement a custom driver component and access IMU data:","partial":false},{"ts":1744500905615,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"docs/Driver_API_Documentation.md\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\docs\\\\Driver_API_Documentation.md\",\"reason\":\" (lines 2000-2500)\"}","partial":false},{"ts":1744500910886,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'docs/Driver_API_Documentation.md'] Result:\\n\\n<file><path>docs/Driver_API_Documentation.md</path>\\n<content lines=\\\"2000-2500\\\">\\n2000 | 1. A binding set by the user.\\r\\n2001 | 2. A binding shipped with an application by an application developer.\\r\\n2002 | 3. A binding set on the partner.steamworks site.\\r\\n2003 | 4. A default binding set by the driver.\\r\\n2004 | 5. A binding from the targeted compatibility mode device (if compatibility mode enabled).\\r\\n2005 |    See [Device Emulation](#device-emulation).\\r\\n2006 | 6. A binding that has been converted using a remapping layout (if [Automatic Rebinding](#automatic-rebinding) is enabled.)\\r\\n2007 | \\r\\n2008 | Binding profiles can be generated using the SteamVR Bindings web interface.\\r\\n2009 | Enabling `Enable Debugging Options in the input bindings user interface` in SteamVR developer settings will allow you to\\r\\n2010 | export a JSON file containing your chosen bindings for the application to `Document/steamvr/input/exports`, with the\\r\\n2011 | file name prefixed with the application's appid on Steam.\\r\\n2012 | \\r\\n2013 | You can copy this file to your driver's resources folder (typically `input\\\\bindings\\\\`), then register the file in\\r\\n2014 | the `default_bindings` section in the Input Profile.\\r\\n2015 | \\r\\n2016 | ### Default Bindings\\r\\n2017 | \\r\\n2018 | Device **can** provide a default set of bindings for applications.\\r\\n2019 | \\r\\n2020 | The collection of bindings should be provided as an array. Each binding is a pairing of a Steam application key and the\\r\\n2021 | associated binding file's name.\\r\\n2022 | \\r\\n2023 | There may be multiple sources that provide possible bindings. The system will pick a binding for an application in the\\r\\n2024 | following order (where lower numbered items are selected first):\\r\\n2025 | \\r\\n2026 | 1. A binding set by the user.\\r\\n2027 | 2. A binding shipped with an application by an application developer.\\r\\n2028 | 3. A binding set on the partner.steamworks site.\\r\\n2029 | 4. A default binding set by the driver writer. This is what is described in this article.\\r\\n2030 | 5. A binding from the targeted compatibility mode device (if compatibility mode enabled).\\r\\n2031 |    See [Device Emulation](#device-emulation).\\r\\n2032 | 6. A binding that has been converted using a remapping layout (if [Automatic Rebinding](#automatic-rebinding) is enabled.)\\r\\n2033 | \\r\\n2034 | Default bindings are set in the input profile, under the `default_bindings` key in the root object.\\r\\n2035 | \\r\\n2036 | * `default_bindings` - Array of objects. Each object **must** contain the keys:\\r\\n2037 |     * `app_key` - Required. Names the app that the binding will apply to. If this is a steam app, it will be prefixed\\r\\n2038 |       with `steam.app.` with the appId appended.\\r\\n2039 |     * `binding_url` - Required. Path to the bindings profile, relative to the current directory.\\r\\n2040 | \\r\\n2041 | ```json\\r\\n2042 | {\\r\\n2043 |   \\\"default_bindings\\\": [\\r\\n2044 |     {\\r\\n2045 |       \\\"app_key\\\": \\\"openvr.tool.steamvr_environments\\\",\\r\\n2046 |       \\\"binding_url\\\": \\\"bindings/openvr.tool.steamvr_environments_my_controller.json\\\"\\r\\n2047 |     },\\r\\n2048 |     {\\r\\n2049 |       \\\"app_key\\\": \\\"openvr.component.vrcompositor\\\",\\r\\n2050 |       \\\"binding_url\\\": \\\"bindings/openvr.component.vrcompositor_my_controller.json\\\"\\r\\n2051 |     },\\r\\n2052 |     {\\r\\n2053 |       \\\"app_key\\\": \\\"steam.app.546560\\\",\\r\\n2054 |       \\\"binding_url\\\": \\\"bindings/steam.app.546560_my_controller.json\\\"\\r\\n2055 |     }\\r\\n2056 |   ]\\r\\n2057 | }\\r\\n2058 | ```\\r\\n2059 | \\r\\n2060 | ## Driver Input\\r\\n2061 | \\r\\n2062 | Drivers can update the *input components* they have created in their [Input Profiles](#Input-Profiles).\\r\\n2063 | \\r\\n2064 | The `IVRDriverInput` interface is used to create and update input-related components.\\r\\n2065 | \\r\\n2066 | ### Creating Components\\r\\n2067 | \\r\\n2068 | Drivers **should** create handles to all *input components* in their input profile. Drivers **must** create handles to\\r\\n2069 | input components they wish to update. The handles can then be used to update the *input component*'s state.\\r\\n2070 | \\r\\n2071 | <br/>\\r\\n2072 | \\r\\n2073 | ```c++\\r\\n2074 | virtual EVRInputError CreateBooleanComponent( PropertyContainerHandle_t ulContainer, const char *pchName, VRInputComponentHandle_t *pHandle ) = 0;\\r\\n2075 | ```\\r\\n2076 | \\r\\n2077 | `CreateBooleanComponent` creates an input component to represent a single boolean value on a controller or other tracked\\r\\n2078 | device.\\r\\n2079 | \\r\\n2080 | Sets the value pointed to by `pHandle` to a valid component handle on success.\\r\\n2081 | \\r\\n2082 | After creating a component the driver **can** update it with repeated calls to `UpdateBooleanComponent`.\\r\\n2083 | \\r\\n2084 | * `PropertyContainerHandle_t ulContainer` - The property container handle of the device that is the parent of this\\r\\n2085 |   component.\\r\\n2086 | * `const char *pchName` - The name of the component. All names should be in the form `/input/<name>/<component>`.\\r\\n2087 | * `VRInputComponentHandle_t *pHandle` - Points to the handle value to set with the new component's handle.\\r\\n2088 | \\r\\n2089 | Returns `VRInputError_None` on success.\\r\\n2090 | \\r\\n2091 | <br/>\\r\\n2092 | \\r\\n2093 | ```c++\\r\\n2094 | virtual EVRInputError CreateScalarComponent( PropertyContainerHandle_t ulContainer, const char *pchName, VRInputComponentHandle_t *pHandle, EVRScalarType eType, EVRScalarUnits eUnits ) = 0;\\r\\n2095 | ```\\r\\n2096 | \\r\\n2097 | `CreateScalarComponent` creates an input component to represent a single scalar value on a controller or other tracked\\r\\n2098 | device.\\r\\n2099 | \\r\\n2100 | Sets the value pointed to by pHandle to a valid component handle on success.\\r\\n2101 | \\r\\n2102 | After creating a component the driver **can** update it with repeated calls to UpdateScalarComponent.\\r\\n2103 | \\r\\n2104 | * `PropertyContainerHandle_t ulContainer` - The property container handle of the device that is the parent of this\\r\\n2105 |   component.\\r\\n2106 | * `const char *pchName` - The name of the component. All names should be in the form `/input/<name>/<component>`.\\r\\n2107 | * `VRInputComponentHandle_t *pHandle` - Points to the handle value to set with the new component's handle.\\r\\n2108 | * `EVRScalarType eType` - The type of scale used for this value. **Must** be one of:\\r\\n2109 |     - `VRScalarType_Absolute` - The scalar values are updated with values on an absolute scale. Joysticks, trackpads,\\r\\n2110 |       and triggers are all examples of absolute scalar values.\\r\\n2111 |     - `VRScalarType_Relative` - The scalar values are updated with incremental values since the last update. Mice and\\r\\n2112 |       trackballs are examples of relative scalar values.\\r\\n2113 | * `EVRScalarUnits eUnits` - Specifies the unit of measurement for the scalar values. Must be one of:\\r\\n2114 |     - `VRScalarUnits_NormalizedOneSided` - Scalar values range from 0 to 1 inclusively. Triggers and throttles generally\\r\\n2115 |       use this value.\\r\\n2116 |     - `VRScalarUnits_NormalizedTwoSided` - Scalar values range from -1 to 1 inclusively. Joysticks and trackpads\\r\\n2117 |       generally use this value.\\r\\n2118 | \\r\\n2119 | Returns `VRInputError_None` on success.\\r\\n2120 | \\r\\n2121 | <br/>\\r\\n2122 | \\r\\n2123 | ```c++\\r\\n2124 | virtual EVRInputError CreateHapticComponent( PropertyContainerHandle_t ulContainer, const char *pchName, VRInputComponentHandle_t *pHandle ) = 0\\r\\n2125 | ```\\r\\n2126 | \\r\\n2127 | `CreateHapticComponent` creates an output component to represent a single haptic on a controller or other tracked\\r\\n2128 | device. Sets the value pointed to by pHandle to a valid component handle on success.\\r\\n2129 | \\r\\n2130 | When the application requests a haptic event, the driver will receive an event of type `VREvent_Input_HapticVibration`\\r\\n2131 | and the details of the haptic event will be in the hapticVibration member of the event data union.\\r\\n2132 | \\r\\n2133 | Applications that use the current haptic API **must only** target the first haptic component created on a given tracked\\r\\n2134 | device.\\r\\n2135 | \\r\\n2136 | * `PropertyContainerHandle_t ulContainer` - The property container handle of the device that is the parent of this\\r\\n2137 |   component.\\r\\n2138 | * `const char *pchName` - The name of the component. All names should be in the form `/input/<name>/<component>`.\\r\\n2139 | * `VRInputComponentHandle_t *pHandle` - Points to the handle value to set with the new component's handle.\\r\\n2140 | \\r\\n2141 | <br/>\\r\\n2142 | \\r\\n2143 | ```c++\\r\\n2144 | virtual EVRInputError CreateSkeletonComponent( PropertyContainerHandle_t ulContainer, const char *pchName, const char *pchSkeletonPath, const char *pchBasePosePath, EVRSkeletalTrackingLevel eSkeletalTrackingLevel, const VRBoneTransform_t *pGripLimitTransforms, uint32_t unGripLimitTransformCount, VRInputComponentHandle_t *pHandle ) = 0;\\r\\n2145 | ```\\r\\n2146 | \\r\\n2147 | `CreateSkeletonComponent` creates an input component to represent skeletal data for the hand for the controller or\\r\\n2148 | tracked device. Returns and sets the value pointed to by pHandle to a valid component handle on success.\\r\\n2149 | \\r\\n2150 | After creating a component the driver **can** update it with repeated calls to UpdateSkeletalComponent.\\r\\n2151 | \\r\\n2152 | More information on using this component for hand tracking is provided in the [Skeletal Input](#Skeletal-Input) section.\\r\\n2153 | \\r\\n2154 | * `ulContainer` - The property container handle of the device that is the parent of this component.\\r\\n2155 | * `pchName` - The name of the component. This **must** be set to one of:\\r\\n2156 |     * `/input/skeleton/right` - The skeleton for the right hand.\\r\\n2157 |     * `/input/skeleton/left` - The skeleton for the left hand.\\r\\n2158 | \\r\\n2159 | * `pchSkeletonPath` - The path to the skeleton to use. This **must** be set to one of:\\r\\n2160 |     * `/skeleton/hand/right` - The skeleton for the right hand.\\r\\n2161 |     * `/skeleton/hand/left` - The skeleton for the left hand.\\r\\n2162 | \\r\\n2163 | * `pchBasePosePath` - The path of the location on the controller model that the skeleton should use as its origin. The\\r\\n2164 |   locations are set in the rendermodel file. See `The JSON File`. For example `/pose/raw`.\\r\\n2165 | * `eSkeletalTrackingLevel` - This value lets applications understand the capabilities of the controller as far as how it\\r\\n2166 |   tracks the pose of the user's body.\\r\\n2167 |     * `VRSkeletalTracking_Estimated` - Body part location can't be directly determined by the device. Any skeletal pose\\r\\n2168 |       provided by the device is estimated by assuming the position required to active buttons, triggers, joysticks, or\\r\\n2169 |       other input sensors. E.g. Vive wands, gamepads.\\r\\n2170 |     * `VRSkeletalTracking_Partial` - Body part location can be measured directly but with fewer degrees of freedom than\\r\\n2171 |       the actual body part. Certain body part positions may be unmeasured by the device and estimated from other input\\r\\n2172 |       data. E.g. Index controllers, gloves that only measure finger curl.\\r\\n2173 |     * `VRSkeletalTracking_Full` - Body part location can be measured directly throughout the entire range of motion of\\r\\n2174 |       the body part. E.g. mocap suits, gloves that measure rotation of each finger segment and (optionally) splay.\\r\\n2175 | * `pGripLimitTransforms` - Array of vr::VRBoneTransform_t containing the parent-space transforms for the grip limit\\r\\n2176 |   pose. The size should match the number of bones in the skeleton that was specified in pchSkeletonPath. If this is\\r\\n2177 |   null, then the system will set the default fist pose as the grip limit. This **should** be any array of 31 bones.\\r\\n2178 | * `unGripLimitTransformCount` - The number of elements in pGripLimitTransforms. This **should** be `31`.\\r\\n2179 | * `pHandle` - Pointer to the where the handle for the newly created component should be written.\\r\\n2180 | \\r\\n2181 | ### Updating Components\\r\\n2182 | \\r\\n2183 | Drivers **should** update a component every time its value changes. A driver **can** update the component even if the\\r\\n2184 | value hasn't changed, and does no harm to do so.\\r\\n2185 | \\r\\n2186 | <br/>\\r\\n2187 | \\r\\n2188 | ```c++\\r\\n2189 | virtual EVRInputError UpdateBooleanComponent( VRInputComponentHandle_t ulComponent, bool bNewValue, double fTimeOffset ) = 0;\\r\\n2190 | ```\\r\\n2191 | \\r\\n2192 | `UpdateBooleanComponent` updates the value of a boolean component. This should be called whenever the current state of a\\r\\n2193 | boolean input component changes.\\r\\n2194 | \\r\\n2195 | * `VRInputComponentHandle_t ulComponent` - The component handle of the component to update.\\r\\n2196 | * `bool bNewValue` - The new boolean value of the component.\\r\\n2197 | * `double fTimeOffset` - The time of the state change in the component relative to now. Negative times are in the past\\r\\n2198 |   and positive times are in the future. This time offset should include transmission latency from the physical hardware.\\r\\n2199 | \\r\\n2200 | <br/>\\r\\n2201 | \\r\\n2202 | ```c++\\r\\n2203 | virtual EVRInputError UpdateScalarComponent( VRInputComponentHandle_t ulComponent, float fNewValue, double fTimeOffset ) = 0;\\r\\n2204 | ```\\r\\n2205 | \\r\\n2206 | `UpdateScalarComponent` updates the value of a scalar component. This should be called whenever the current state of an\\r\\n2207 | input component changes.\\r\\n2208 | \\r\\n2209 | * `VRInputComponentHandle_t ulComponent` - The component handle of the component to update.\\r\\n2210 | * `float fNewValue` - The new scalar value of the component.\\r\\n2211 | * `double fTimeOffset` - The time of the state change in the component relative to now. Negative times are in the past\\r\\n2212 |   and positive times are in the future. This time offset should include transmission latency from the physical hardware.\\r\\n2213 | \\r\\n2214 | <br/>\\r\\n2215 | \\r\\n2216 | ```c++\\r\\n2217 | virtual EVRInputError UpdateSkeletonComponent( VRInputComponentHandle_t ulComponent, EVRSkeletalMotionRange eMotionRange, const VRBoneTransform_t *pTransforms, uint32_t unTransformCount ) = 0;\\r\\n2218 | ```\\r\\n2219 | \\r\\n2220 | `UpdateSkeletonComponent` updates the pose of a skeletal component to be the values in the given list of transforms.\\r\\n2221 | \\r\\n2222 | More information on using this component for hand tracking is provided in the [Skeletal Input](#Skeletal-Input) section.\\r\\n2223 | \\r\\n2224 | * `ulComponent` - Handle for the skeletal component to update.\\r\\n2225 | * `eMotionRange` - Which skeletal data stream you are providing data for. More info on this below. Options are:\\r\\n2226 |     * `VRSkeletalMotionRange_WithController` - The range of motion of the skeleton takes into account any physical\\r\\n2227 |       limits imposed by the controller itself. This will tend to be the most accurate pose compared to the user's actual\\r\\n2228 |       hand pose, but might not allow a closed fist for example.\\r\\n2229 |     * `VRSkeletalMotionRange_WithoutController` - Retarget the range of motion provided by the input device to make the\\r\\n2230 |       hand appear to move as if it was not holding a controller. eg: map \\\"hand grasping controller\\\" to \\\"closed fist\\\".\\r\\n2231 | * `pTransforms` - Array of bone transforms in parent space for the currently detected pose of the user's hand. This *\\r\\n2232 |   *should** be any array of 31 bones.\\r\\n2233 | * `unTransformCount` - The number of transforms in pTransforms. Must match the number of bones in the skeleton that is\\r\\n2234 |   used by this skeletal component, otherwise it will return an error. This **should** be `31`.\\r\\n2235 | \\r\\n2236 | ```c++\\r\\n2237 | //Make sure that these are also accessible when needed to update the components\\r\\n2238 | vr::VRInputComponentHandle_t trackpadX;\\r\\n2239 | vr::VRInputComponentHandle_t trackpadY;\\r\\n2240 | vr::VRInputComponentHandle_t trackpadTouch;\\r\\n2241 | vr::VRInputComponentHandle_t trackpadClick;\\r\\n2242 | \\r\\n2243 | vr::VRDriverInput()->CreateScalarComponent(props, \\\"/input/trackpad/x\\\", &trackpadX, vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedTwoSided);\\r\\n2244 | vr::VRDriverInput()->CreateScalarComponent(props, \\\"/input/trackpad/y\\\", &trackpadY, vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedTwoSided);\\r\\n2245 | vr::VRDriverInput()->CreateBooleanComponent(props, \\\"/input/trackpad/touch\\\", &trackpadTouch);\\r\\n2246 | vr::VRDriverInput()->CreateBooleanComponent(props, \\\"/input/trackpad/click\\\", &trackpadClick);\\r\\n2247 | \\r\\n2248 | //... some time later when the hardware sends data\\r\\n2249 | \\r\\n2250 | vr::VRDriverInput()->UpdateScalarComponent(trackpadX, myData.trackpadX, 0);\\r\\n2251 | vr::VRDriverInput()->UpdateScalarComponent(trackpadY, myData.trackpadY, 0);\\r\\n2252 | \\r\\n2253 | vr::VRDriverInput()->UpdateBooleanComponent(trackpadTouch, myData.trackpadTouch, 0);\\r\\n2254 | vr::VRDriverInput()->UpdateBooleanComponent(trackpadClick, myData.trackpadClick, 0);\\r\\n2255 | ```\\r\\n2256 | \\r\\n2257 | ## Events\\r\\n2258 | \\r\\n2259 | It is up to the driver to decide when it wants to pull the most recent events from the queue. Typically, you'll want to\\r\\n2260 | process all events that happened within a frame at once, so your method might look something like:\\r\\n2261 | \\r\\n2262 | ```c++\\r\\n2263 |     vr::VREvent_t vrEvent;\\r\\n2264 | while ( vr::VRServerDriverHost()->PollNextEvent( &vrEvent, sizeof( vrEvent )))\\r\\n2265 | {\\r\\n2266 | //decide however you want to process the current event\\r\\n2267 | }\\r\\n2268 | ```\\r\\n2269 | \\r\\n2270 | Common events that a driver might listen for are:\\r\\n2271 | \\r\\n2272 | * `VREvent_Input_HapticVibration` - Sent when a haptic event is triggered by an application. See\\r\\n2273 |   the [Haptic Events](#Haptic-Events) section for more information.\\r\\n2274 | * `VREvent_OtherSectionSettingChanged` - Sent when a section in a non-runtime specified settings section has changed\\r\\n2275 |   via [IVRSettings](#IVRSettings). This might prompt the driver to reload its settings.\\r\\n2276 | \\r\\n2277 | ### Haptic Events\\r\\n2278 | \\r\\n2279 | Haptic events sent from applications **can** be received by a driver through `IVRServerDriverHost::PollNextEvent`.\\r\\n2280 | \\r\\n2281 | A haptic event is received under the event type `vr::EVREventType::VREvent_Input_HapticVibration`.\\r\\n2282 | \\r\\n2283 | The driver **must** then check the `componentHandle` property to get the component for which the event was intended for.\\r\\n2284 | This handle is created from `IVRDriverInput::CreateHapticComponent`.\\r\\n2285 | \\r\\n2286 | A haptic event contains a few extra properties:\\r\\n2287 | \\r\\n2288 | * `fDurationSeconds` - How long the haptic event should last for, in seconds.\\r\\n2289 | * `fFrequency` - The frequency of the haptic event. In Hz.\\r\\n2290 |     * From the application, this represents how the haptic vibration feels. The lower the frequency, the more the device\\r\\n2291 |       should \\\"rumble\\\".\\r\\n2292 | * `fAmplitude` - The intensity of the haptic event. A higher amplitude means a greater strength to the haptic vibration.\\r\\n2293 | \\r\\n2294 | Drivers **should** handle the properties with the following:\\r\\n2295 | \\r\\n2296 | * If `fFrequency` or `fAmplitude` equal or are less than `0`, no haptic should trigger.\\r\\n2297 | * Clamp `fDurationSeconds` to a minimum of 0 seconds, and a maximum of 10 seconds\\r\\n2298 |     * If `fDurationSeconds` is 0, a driver **should** pulse their haptic component _once_.\\r\\n2299 |     * This is subject to change\\r\\n2300 | * Clamp `fAmplitude` to between 0 and 1.\\r\\n2301 | * Clamp `fFrequency` to a minimum of `1000000.f / 65535.f` and a maximum of `1000000.f / 300.f`\\r\\n2302 |     * This is subject to change.\\r\\n2303 | \\r\\n2304 | Haptic events **can** be converted to represent a pulse by doing the following:\\r\\n2305 | \\r\\n2306 | * The period of a pulse, in seconds, can be calculated with `1.f / fFrequency`\\r\\n2307 | * The pulse duration can be calculated by interpolating `fAmplitude` between a set minimum pulse duration, a maximum of\\r\\n2308 |   half the total pulse duration (or a set maximum), whichever is less.\\r\\n2309 | * The amount of pulses to trigger can be calculated by multiplying `fDurationSeconds * fFrequency`.\\r\\n2310 |   If `fDurationSeconds` is 0, then the amount of pulses to trigger is 1.\\r\\n2311 |     * This is subject to change\\r\\n2312 | \\r\\n2313 | ```c++\\r\\n2314 | switch (vrEvent.eventType) {\\r\\n2315 |   case vr::VREvent_Input_HapticVibration: {\\r\\n2316 |     if (vrEvent.data.hapticVibration.componentHandle == m_compMyHaptic) {\\r\\n2317 |       // This is where you would send a signal to your hardware to trigger actual haptic feedback\\r\\n2318 |       \\r\\n2319 |       const float pulse_period = 1.f / vrEvent.data.hapticVibration.fFrequency\\r\\n2320 |       const float frequency = std::clamp(1000000.f / 65535.f, 1000000.f / 300.f, pulse_period);\\r\\n2321 |       const float amplitude = std::clamp(0.f, 1.f, vrEvent.data.hapticVibration.fAmplitude);\\r\\n2322 |       const float duration = std::clamp(0.f, 10.f, vrEvent.data.hapticVibration.fDurationSeconds);\\r\\n2323 |       \\r\\n2324 |       if(duration == 0.f) {\\r\\n2325 |         // Trigger a single pulse of the haptic component\\r\\n2326 |       } else {\\r\\n2327 |         const float pulse_count = fDurationSeconds * fFrequency;\\r\\n2328 |         const float pulse_duration = Lerp(my_minimum_duration, my_maximum_duration, amplitude);\\r\\n2329 |         const float pulse_interval = pulse_period - pulse_duration;\\r\\n2330 |       }\\r\\n2331 |     }\\r\\n2332 |   }\\r\\n2333 |   break;\\r\\n2334 | }\\r\\n2335 | ```\\r\\n2336 | \\r\\n2337 | ## Device Properties\\r\\n2338 | \\r\\n2339 | OpenVR exposes a set of properties, contained within `ETrackedDeviceProperty`, that provide information about devices to\\r\\n2340 | the runtime.\\r\\n2341 | \\r\\n2342 | Properties can be retrieved and set through the [IVRProperties](#ivrproperties) interface or, more\\r\\n2343 | commonly, [CVRPropertyHelpers](#cvrpropertyhelpers), which is a helper class that wraps the `IVRProperties` interface.\\r\\n2344 | \\r\\n2345 | A number of these properties are inferred from calls the driver has previously made to the server, while others **must**\\r\\n2346 | or **should** be set by the device manually.\\r\\n2347 | \\r\\n2348 | The list of properties that are defined by server, and so do not have to be set by the driver are:\\r\\n2349 | \\r\\n2350 | * `Prop_SerialNumber_String` - inferred from the call to `IVRServerDriverHost::TrackedDeviceAdded`.\\r\\n2351 | * `Prop_TrackingSystemName_String` - inferred from the driver name.\\r\\n2352 | * `Prop_DeviceClass_Int32` - inferred from the call to `IVRServerDriverHost::TrackedDeviceAdded`.\\r\\n2353 | * `Prop_HasDisplayComponent_Bool` - HMD. Inferred from what the device returns from\\r\\n2354 |   its `IServerTrackedDeviceDriver::GetComponent` method.\\r\\n2355 | * `Prop_HasCameraComponent_Bool` - HMD. Inferred from what the device returns from\\r\\n2356 |   its `IServerTrackedDeviceDriver::GetComponent` method.\\r\\n2357 | * `Prop_HasDriverDirectModeComponent_Bool` - HMD. Inferred from what the device returns from\\r\\n2358 |   its `IServerTrackedDeviceDriver::GetComponent` method.\\r\\n2359 | * `Prop_HasVirtualDisplayComponent_Bool` - HMD. Inferred from what the device returns from\\r\\n2360 |   its `IServerTrackedDeviceDriver::GetComponent` method.\\r\\n2361 | * `Prop_DisplayFrequency_Float` - HMD. If 0 after `IServerTrackedDeviceDriver::Activate` is called, the runtime will set\\r\\n2362 |   this to the refresh rate that the display reports.\\r\\n2363 | * `Prop_SecondsFromVsyncToPhotons_Float` - HMD. If 0 after `IServerTrackedDeviceDriver::Activate` is called, the runtime\\r\\n2364 |   will set this to the reciprocal of the refresh rate of the display, which is the value for the majority of low\\r\\n2365 |   persistence displays.\\r\\n2366 | \\r\\n2367 | Properties for a _controller_ device that **must** be set by the device are:\\r\\n2368 | \\r\\n2369 | * `Prop_ControllerType_String` - A string representing the type of controller, for example `knuckles`\\r\\n2370 |   or `vive_controller`.\\r\\n2371 |     * Controller types **should** be ASCII and short. This is not the human-readable name, it is the internal name that\\r\\n2372 |       will\\r\\n2373 |       be stored in data and log files.\\r\\n2374 | * `Prop_InputProfilePath_String` - A string that points to the\\r\\n2375 | \\r\\n2376 | A number of properties of a _controller_ **should** be set. These are:\\r\\n2377 | \\r\\n2378 | * `Prop_ControllerRoleHint_Int32` - The role of the controller (left/right/etc.). This **should** be one of the values\\r\\n2379 |   from `ETrackedControllerRole`.\\r\\n2380 | * `Prop_InputProfilePath_String` - The path to the input profile for the controller. This **should** be the path to the\\r\\n2381 |   input profile JSON file for the controller.\\r\\n2382 | * `Prop_ManufacturerName_String` - The name of the manufacturer of this device.\\r\\n2383 | * `Prop_ModelNumber_String` - The model number of this device. This is string that can be used to set icons for a device\\r\\n2384 |   and is non-unique.\\r\\n2385 | * `Prop_DeviceProvidesBatteryStatus_Bool` - Whether the device supports retrieving the current battery percentage. This\\r\\n2386 |   property dictates whether the user will see battery icons within the VR Monitor and Dashboard. If this property is set\\r\\n2387 |   to `true`, the following properties **should** also be set:\\r\\n2388 |     * `Prop_DeviceBatteryPercentage_Float` - The current battery percentage. This **must** be a value between 0-1\\r\\n2389 |       inclusive. This **should** be updated whenever the device's battery percentage changes.\\r\\n2390 |     * `Prop_DeviceIsCharging_Bool` - Whether the device is currently charging. This **should** be updated when the\\r\\n2391 |       device starts or stops charging.\\r\\n2392 | \\r\\n2393 | ### Implementing Properties\\r\\n2394 | \\r\\n2395 | Properties **should** be set when the device's `IServerTrackedDeviceDriver::Activate` is called.\\r\\n2396 | \\r\\n2397 | Device properties **should** be set with the `CVRPropertyHelpers` class the OpenVR Driver header provides. This class is\\r\\n2398 | returned from calling `vr::VRProperties()`.\\r\\n2399 | \\r\\n2400 | `CVRPropertyHelpers` provides a wrapper around `IVRProperties`, with methods to simplify submitting different property\\r\\n2401 | types to the runtime.\\r\\n2402 | \\r\\n2403 | See [CVRPropertyHelpers](#cvrpropertyhelpers) for the recommended interface to use for manipulating device properties.\\r\\n2404 | \\r\\n2405 | ### IVRProperties\\r\\n2406 | \\r\\n2407 | <br />\\r\\n2408 | \\r\\n2409 | ```c++\\r\\n2410 | virtual ETrackedPropertyError ReadPropertyBatch( PropertyContainerHandle_t ulContainerHandle, PropertyRead_t *pBatch, uint32_t unBatchEntryCount ) = 0;\\r\\n2411 | ```\\r\\n2412 | \\r\\n2413 | `ReadPropertyBatch` reads a set of properties atomically.\\r\\n2414 | \\r\\n2415 | * `ulContainerHandle` - The handle of the container to read properties from.\\r\\n2416 | * `pBatch` - An array of `PropertyRead_t` structs, each containing a property name and a buffer to write the property\\r\\n2417 |   value to.\\r\\n2418 |     * `ETrackedDeviceProperty prop` - The property to read.\\r\\n2419 |     * `void *pvBuffer` - The buffer to read the property into.\\r\\n2420 |     * `uint32_t unBufferSize` - The size of the buffer.\\r\\n2421 |     * `PropertyTypeTag_t unTag` - The \\\"type\\\" in this property. Tags commonly used are provided below, but\\r\\n2422 |       more `PropertyTypeTag_t` constants are defined in the header.\\r\\n2423 |         * `k_unFloatPropertyTag` - `float` data type\\r\\n2424 |         * `k_unInt32PropertyTag` - `int32_t` data type\\r\\n2425 |         * `k_unUint64PropertyTag` - `uint64_t` data type\\r\\n2426 |         * `k_unBoolPropertyTag` - `bool` data type\\r\\n2427 |         * `k_unStringPropertyTag` - `char *` data type\\r\\n2428 |     * `uint32_t unRequiredBufferSize` - The size of the buffer that is needed to store this data.\\r\\n2429 |     * `ETrackedPropertyError eError` - The error code the runtime returned for this property.\\r\\n2430 | * `unBatchEntryCount` - The number of entries in the `pBatch` array.\\r\\n2431 | \\r\\n2432 | <br />\\r\\n2433 | \\r\\n2434 | ```c++\\r\\n2435 | virtual ETrackedPropertyError WritePropertyBatch( PropertyContainerHandle_t ulContainerHandle, PropertyWrite_t *pBatch, uint32_t unBatchEntryCount ) = 0;\\r\\n2436 | ```\\r\\n2437 | \\r\\n2438 | `WritePropertyBatch` writes a set of properties atomically.\\r\\n2439 | \\r\\n2440 | * `ulContainerHandle` - The handle of the container to write properties to.\\r\\n2441 | * `pBatch` - An array of `PropertyWrite_t` structs, each containing a property name and a buffer to read the property\\r\\n2442 |   value from.\\r\\n2443 |     * `ETrackedDeviceProperty prop` - The property to write.\\r\\n2444 |     * `EPropertyWriteType writeType` - The type of write being performed. This can be:\\r\\n2445 |         * `PropertWrite_Set` - Set the property to the value in `pvBuffer`.\\r\\n2446 |         * `PropertyWrite_Erase` - Remove the value in the property.\\r\\n2447 |         * `PropertyWrite_SetError` - Sets the error return value for a property to `ETrackedPropertyError` and clears\\r\\n2448 |           its data if there was any.\\r\\n2449 |     * `ETrackedPropertyError eSetError` - What error code to set the property to return if `writeType`\\r\\n2450 |       is `PropertyWrite_SetError`.\\r\\n2451 |     * `void *pvBuffer` - The buffer to write the property from.\\r\\n2452 |     * `uint32_t unBufferSize` - The size of the buffer.\\r\\n2453 |     * `PropertyTypeTag_t unTag` - The \\\"type\\\" in this property. Tags commonly used are provided below, but\\r\\n2454 |       more `PropertyTypeTag_t` constants are defined in the header.\\r\\n2455 |         * `k_unFloatPropertyTag` - `float` data type\\r\\n2456 |         * `k_unInt32PropertyTag` - `int32_t` data type\\r\\n2457 |         * `k_unUint64PropertyTag` - `uint64_t` data type\\r\\n2458 |         * `k_unBoolPropertyTag` - `bool` data type\\r\\n2459 |         * `k_unStringPropertyTag` - `char *` data type\\r\\n2460 |     * `ETrackedPropertyError eError` - The error code the runtime returned for this property.\\r\\n2461 | \\r\\n2462 | <br />\\r\\n2463 | \\r\\n2464 | ```c++\\r\\n2465 | virtual const char *GetPropErrorNameFromEnum( ETrackedPropertyError error ) = 0;\\r\\n2466 | ```\\r\\n2467 | \\r\\n2468 | `GetPropErrorNameFromEnum` returns a string that corresponds with the specified property error.\\r\\n2469 | \\r\\n2470 | The string will be the name of the error enum value for all valid error codes.\\r\\n2471 | \\r\\n2472 | * `ETrackedPropertyError error` - The error code to get the string for.\\r\\n2473 | \\r\\n2474 | <br/>\\r\\n2475 | \\r\\n2476 | ```c++\\r\\n2477 | virtual PropertyContainerHandle_t TrackedDeviceToPropertyContainer( TrackedDeviceIndex_t nDevice ) = 0;\\r\\n2478 | ```\\r\\n2479 | \\r\\n2480 | `TrackedDeviceToPropertyContainer` returns the property container handle for the specified tracked device index.\\r\\n2481 | \\r\\n2482 | * `TrackedDeviceIndex_t nDevice` - The tracked device index to get the property container handle for.\\r\\n2483 | \\r\\n2484 | ### CVRPropertyHelpers\\r\\n2485 | \\r\\n2486 | Functions in this interface are wrappers around the `IVRProperties` interface. They provide a simpler interface for\\r\\n2487 | setting and getting properties, which typed methods.\\r\\n2488 | \\r\\n2489 | #### Getting properties\\r\\n2490 | \\r\\n2491 | The `GetXXXProperty` methods can be used to get properties, where `XXX` specifies the type.\\r\\n2492 | \\r\\n2493 | `GetStringProperty` is polymorphic. A driver can either have an `std::string` returned from this method, or pass in\\r\\n2494 | a `char *` and `uint32_t` (for size of buffer) to have the property value written to the buffer.\\r\\n2495 | \\r\\n2496 | <br />\\r\\n2497 | \\r\\n2498 | ```c++\\r\\n2499 | T GetTProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, ETrackedPropertyError *pError = 0L );\\r\\n2500 | ```\\r\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\ndocs\\\\Driver_API_Documentation.md\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:35:10 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n106,426 (53%)\\n\\n# Current Cost\\n$0.79\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":144,\"cacheWrites\":10098,\"cacheReads\":106277,\"cost\":0.07192259999999999}"},{"ts":1744500913999,"type":"say","say":"text","text":"I've gathered a lot of information about the OpenVR driver architecture and how to implement a custom driver. Let me continue reading to find more information about how to access IMU data and how to implement a custom driver that wraps the existing lighthouse driver.\n\nLet me continue reading the Driver API Documentation to understand more about how to implement a custom driver component and access IMU data:","partial":false},{"ts":1744500915877,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"docs/Driver_API_Documentation.md\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\docs\\\\Driver_API_Documentation.md\",\"reason\":\" (lines 2500-3000)\"}","partial":false},{"ts":1744500919368,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'docs/Driver_API_Documentation.md'] Result:\\n\\n<file><path>docs/Driver_API_Documentation.md</path>\\n<content lines=\\\"2500-3000\\\">\\n2500 | ```\\r\\n2501 | \\r\\n2502 | `GetTProperty` gets a property.\\r\\n2503 | \\r\\n2504 | * `PropertyContainerHandle_t ulContainerHandle` - The handle of the container to read the property from.\\r\\n2505 | * `ETrackedDeviceProperty prop` - The property to get.\\r\\n2506 | * `ETrackedPropertyError *pError` - The error code the runtime returned for this property.\\r\\n2507 | \\r\\n2508 | Returns the value of the property as type `T`.\\r\\n2509 | \\r\\n2510 | ```c++\\r\\n2511 | //unObjectId is the device id of your device, passed in from ITrackedDeviceServerDriver::Activate.\\r\\n2512 | vr::PropertyContainerHandle_t ulPropertyContainer = vr::VRProperties()->TrackedDeviceToPropertyContainer( unObjectId );\\r\\n2513 | \\r\\n2514 | vr::ETrackedPropertyError err;\\r\\n2515 | \\r\\n2516 | std::string my_device_serial_number = vr::VRProperties()->GetStringProperty(my_device_container_handle, vr::Prop_SerialNumber_String, &err);\\r\\n2517 | \\r\\n2518 | float my_device_battery_percentage = vr::VRProperties()->GetFloatProperty(my_device_container_handle, vr::Prop_DeviceBatteryPercentage_Float, &err);\\r\\n2519 | \\r\\n2520 | bool my_device_is_charging = vr::VRProperties()->GetBoolProperty(my_device_container_handle, vr::Prop_DeviceIsCharging_Bool, &err);\\r\\n2521 | \\r\\n2522 | ETrackedDeviceClass my_device_class = vr::VRProperties()->GetInt32Property(my_device_container_handle, vr::Prop_DeviceClass_Int32, &err);\\r\\n2523 | ```\\r\\n2524 | \\r\\n2525 | #### Setting Properties\\r\\n2526 | \\r\\n2527 | ```c++\\r\\n2528 | ETrackedPropertyError SetTProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, T tNewValue );\\r\\n2529 | ```\\r\\n2530 | \\r\\n2531 | `SetTProperty` sets a property to the specified value.\\r\\n2532 | \\r\\n2533 | * `PropertyContainerHandle_t ulContainerHandle` - The handle of the container to read the property from.\\r\\n2534 | * `ETrackedDeviceProperty prop` - The property to set.\\r\\n2535 | * `T tNewValue` - The value to set the property to.\\r\\n2536 | \\r\\n2537 | ```c++\\r\\n2538 | //unObjectId is the device id of your device, passed in from ITrackedDeviceServerDriver::Activate.\\r\\n2539 | vr::PropertyContainerHandle_t ulPropertyContainer = vr::VRProperties()->TrackedDeviceToPropertyContainer( unObjectId );\\r\\n2540 | \\r\\n2541 | \\r\\n2542 | vr::VRProperties()->SetStringProperty( ulPropertyContainer, vr::Prop_ModelNumber_String, m_sModelNumber.c_str());\\r\\n2543 | vr::VRProperties()->SetStringProperty( ulPropertyContainer, vr::Prop_RenderModelName_String, m_sModelNumber.c_str());\\r\\n2544 | \\r\\n2545 | // return a constant that's not 0 (invalid) or 1 (reserved for Oculus)\\r\\n2546 | vr::VRProperties()->SetUint64Property( ulPropertyContainer, vr::Prop_CurrentUniverseId_Uint64, 2 );\\r\\n2547 | \\r\\n2548 | // avoid \\\"not fullscreen\\\" warnings from vrmonitor\\r\\n2549 | vr::VRProperties()->SetBoolProperty( ulPropertyContainer, vr::Prop_IsOnDesktop_Bool, false );\\r\\n2550 | \\r\\n2551 | // our sample device isn't actually tracked, so set this property to avoid having the icon blink in the status window\\r\\n2552 | vr::VRProperties()->SetBoolProperty( ulPropertyContainer, vr::Prop_NeverTracked_Bool, true );\\r\\n2553 | \\r\\n2554 | // set the device to be a right-handed controller. This will also allow bindings to be used\\r\\n2555 | vr::VRProperties()->SetInt32Property( ulPropertyContainer, vr::Prop_ControllerRoleHint_Int32, vr::TrackedControllerRole_RightHand );\\r\\n2556 | \\r\\n2557 | // this file tells the UI what to show the user for binding this controller as well as what default bindings should\\r\\n2558 | // be for legacy or other apps\\r\\n2559 | vr::VRProperties()->SetStringProperty( m_ulPropertyContainer, vr::Prop_InputProfilePath_String, \\\"{sample}/input/mycontroller_profile.json\\\" );\\r\\n2560 | ```\\r\\n2561 | \\r\\n2562 | #### Property Utilities\\r\\n2563 | \\r\\n2564 | A number of extra utilities are provided to help with manipulating properties.\\r\\n2565 | \\r\\n2566 | <br />\\r\\n2567 | \\r\\n2568 | ```c++\\r\\n2569 | ETrackedPropertyError SetPropertyError( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop, ETrackedPropertyError eError );\\r\\n2570 | ```\\r\\n2571 | \\r\\n2572 | `SetPropertyError` sets the error return value for a property. This value will be returned on all subsequent requests to\\r\\n2573 | get the property and will erase the current value of the property.\\r\\n2574 | \\r\\n2575 | * `PropertyContainerHandle_t ulContainerHandle` - The handle of the container to erase the property from.\\r\\n2576 | * `ETrackedDeviceProperty prop` - The property to erase.\\r\\n2577 | * `ETrackedPropertyError eError` - The error code to set for this property.\\r\\n2578 | \\r\\n2579 | <br/>\\r\\n2580 | \\r\\n2581 | ```c++\\r\\n2582 | ETrackedPropertyError EraseProperty( PropertyContainerHandle_t ulContainerHandle, ETrackedDeviceProperty prop );\\r\\n2583 | ```\\r\\n2584 | \\r\\n2585 | `EraseProperty` clears any value or error set for the property.\\r\\n2586 | \\r\\n2587 | * `PropertyContainerHandle_t ulContainerHandle` - The handle of the container to erase the property from.\\r\\n2588 | * `ETrackedDeviceProperty prop` - The property to erase.\\r\\n2589 | \\r\\n2590 | <br/>\\r\\n2591 | \\r\\n2592 | ```c++\\r\\n2593 | bool IsPropertySet( PropertyContainerHandle_t ulContainer, ETrackedDeviceProperty prop, ETrackedPropertyError *peError = nullptr );\\r\\n2594 | ```\\r\\n2595 | \\r\\n2596 | `IsPropertySet` returns true if the specified property is set on the specified container.\\r\\n2597 | \\r\\n2598 | * `PropertyContainerHandle_t ulContainer` - The handle of the container of the property to check is set.\\r\\n2599 | * `ETrackedDeviceProperty prop` - The property to check is set.\\r\\n2600 | \\r\\n2601 | ## IVRSettings\\r\\n2602 | \\r\\n2603 | The `IVRSettings` interface is used to get and set settings. All settings are global, and can be accessed\\r\\n2604 | through this interface.\\r\\n2605 | \\r\\n2606 | SteamVR maintains a file listing user specified settings, in the `steamvr.vrsettings` file found\\r\\n2607 | within `C:\\\\Program Files (x86)\\\\Steam\\\\config`.\\r\\n2608 | \\r\\n2609 | `IVRSettings` first looks for settings within `steamvr.vrsettings`. If it finds the requested setting, it returns it. If\\r\\n2610 | it does not find the setting, it then looks for the setting in the driver's `default.vrsettings`.\\r\\n2611 | \\r\\n2612 | Settings stored in `steamvr.vrsettings` are persisted between computers through Steam\\r\\n2613 | Cloud.\\r\\n2614 | \\r\\n2615 | A driver can then access these settings through the `IVRSettings::GetXXX()` methods of `IVRSettings`.\\r\\n2616 | \\r\\n2617 | ```c++\\r\\n2618 | char my_setting_string[4096];\\r\\n2619 | vr::VRSettings()->GetString( \\\"<my_driver_name>_section\\\", \\\"my_driver_settings_string_key\\\", buf, sizeof( buf ) );\\r\\n2620 | \\r\\n2621 | float my_setting_float = vr::VRSettings()->GetFloat( \\\"<my_driver_name>_section\\\", \\\"my_driver_settings_float_key\\\" );\\r\\n2622 | \\r\\n2623 | int32_t my_setting_int = vr::VRSettings()->GetInt32( \\\"<my_driver_name>_section\\\", \\\"my_driver_settings_int_key\\\" );\\r\\n2624 | \\r\\n2625 | bool my_setting_bool = vr::VRSettings()->GetBool( \\\"<my_driver_name>_section\\\", \\\"my_driver_settings_bool_key\\\" );\\r\\n2626 | ```\\r\\n2627 | \\r\\n2628 | Setting settings can be done through the `IVRSettings::SetXXX()` methods of `IVRSettings`.\\r\\n2629 | \\r\\n2630 | The values of the keys set through these methods are written to `steamvr.vrsettings`, and `default.vrsettings` remains\\r\\n2631 | unchanged.\\r\\n2632 | \\r\\n2633 | ```c++\\r\\n2634 | vr::VRSettings()->SetString( \\\"<my_driver_name>_section\\\", \\\"my_driver_settings_string_key\\\", \\\"Hi World!\\\" );\\r\\n2635 | vr::VRSettings()->SetFloat( \\\"<my_driver_name>_section\\\", \\\"my_driver_settings_float_key\\\", 2.0 );\\r\\n2636 | vr::VRSettings()->SetInt32( \\\"<my_driver_name>_section\\\", \\\"my_driver_settings_int_key\\\", 2 );\\r\\n2637 | vr::VRSettings()->SetBool( \\\"<my_driver_name>_section\\\", \\\"my_driver_settings_bool_key\\\", true );\\r\\n2638 | ```\\r\\n2639 | \\r\\n2640 | Updating a section will trigger an event than can be received from the [IVRServerDriverHost](#IVRServerDriverHost)\\r\\n2641 | interface.\\r\\n2642 | \\r\\n2643 | When a setting is updated, it will trigger an event. The possible events are:\\r\\n2644 | \\r\\n2645 |     VREvent_BackgroundSettingHasChanged            \\r\\n2646 |     VREvent_CameraSettingsHaveChanged            \\r\\n2647 |     VREvent_ReprojectionSettingHasChanged        \\r\\n2648 |     VREvent_ModelSkinSettingsHaveChanged        \\r\\n2649 |     VREvent_EnvironmentSettingsHaveChanged        \\r\\n2650 |     VREvent_PowerSettingsHaveChanged            \\r\\n2651 |     VREvent_EnableHomeAppSettingsHaveChanged    \\r\\n2652 |     VREvent_SteamVRSectionSettingChanged        \\r\\n2653 |     VREvent_LighthouseSectionSettingChanged        \\r\\n2654 |     VREvent_NullSectionSettingChanged            \\r\\n2655 |     VREvent_UserInterfaceSectionSettingChanged    \\r\\n2656 |     VREvent_NotificationsSectionSettingChanged    \\r\\n2657 |     VREvent_KeyboardSectionSettingChanged        \\r\\n2658 |     VREvent_PerfSectionSettingChanged            \\r\\n2659 |     VREvent_DashboardSectionSettingChanged        \\r\\n2660 |     VREvent_WebInterfaceSectionSettingChanged    \\r\\n2661 |     VREvent_TrackersSectionSettingChanged        \\r\\n2662 |     VREvent_LastKnownSectionSettingChanged        \\r\\n2663 |     VREvent_DismissedWarningsSectionSettingChanged\\r\\n2664 |     VREvent_GpuSpeedSectionSettingChanged        \\r\\n2665 |     VREvent_WindowsMRSectionSettingChanged        \\r\\n2666 |     VREvent_OtherSectionSettingChanged            \\r\\n2667 | \\r\\n2668 | If you have modified your own driver properties, it will trigger an event of `VREvent_OtherSectionSettingChanged`. The\\r\\n2669 | other sections listed are reserved sections that SteamVR uses internally for its own settings.\\r\\n2670 | \\r\\n2671 | ## IVRResources\\r\\n2672 | \\r\\n2673 | `IVRResources` provides functionality from the runtime to locate and load files for a driver.\\r\\n2674 | \\r\\n2675 | <br />\\r\\n2676 | \\r\\n2677 | ```c++\\r\\n2678 | virtual uint32_t LoadSharedResource( const char *pchResourceName, char *pchBuffer, uint32_t unBufferLen ) = 0;\\r\\n2679 | ```\\r\\n2680 | \\r\\n2681 | `LoadSharedResource` loads the specified _shared_ resource into the provided buffer if large enough.\\r\\n2682 | \\r\\n2683 | Shared resources are stored within SteamVR.\\r\\n2684 | \\r\\n2685 | Returns the size, in bytes of the buffer required to hold the specified resource.\\r\\n2686 | \\r\\n2687 | * `const char *pchResourceName` - The name of the resource to load.\\r\\n2688 | * `char *pchBuffer` - The buffer to load the resource into.\\r\\n2689 | * `uint32_t unBufferLen` - The size of the buffer.\\r\\n2690 | \\r\\n2691 | <br />\\r\\n2692 | \\r\\n2693 | ```c++\\r\\n2694 | virtual uint32_t GetResourceFullPath( const char *pchResourceName, const char *pchResourceTypeDirectory, VR_OUT_STRING() char *pchPathBuffer, uint32_t unBufferLen ) = 0;\\r\\n2695 | ```\\r\\n2696 | \\r\\n2697 | `GetResourceFullPath` resolves an absolute path into the buffer from the specific resource name and directory.\\r\\n2698 | \\r\\n2699 | Getting the current directory within a shared library can be difficult, so this function can help with locating\\r\\n2700 | driver-relative resources.\\r\\n2701 | \\r\\n2702 | Returns the size, in bytes of the buffer required to hold the specified resource.\\r\\n2703 | \\r\\n2704 | Driver-specific files can be loaded from this method.\\r\\n2705 | \\r\\n2706 | * `const char *pchResourceName` - The name of the resource to load.\\r\\n2707 | * `const char *pchResourceTypeDirectory` - The directory to load the resource from. This can be a named directory for\\r\\n2708 |   drivers, i.e. `{sample}/resources`\\r\\n2709 | * `VR_OUT_STRING() char *pchPathBuffer` - The absolute path to the resource\\r\\n2710 | * `uint32_t unBufferLen` - The length, in bytes of the provided buffer.\\r\\n2711 | \\r\\n2712 | ## IVRDriverSpatialAnchors\\r\\n2713 | \\r\\n2714 | `IVRDriverSpatialAnchors` provides an interface for drivers to interact with spatial anchors: a driver-specified\\r\\n2715 | descriptor for a physical location.\\r\\n2716 | \\r\\n2717 | Note: No drivers currently implement this interface and **should** only be used for prototyping.\\r\\n2718 | \\r\\n2719 | You **must** declare support for spatial anchors in your `driver.vrdrivermanifest`.\\r\\n2720 | See [driver.vrdrivermanifest](#drivervrdrivermanifest).\\r\\n2721 | \\r\\n2722 | The driver **should** monitor for `VREvent_SpatialAnchors_RequestPoseUpdate` events (for new descriptors from\\r\\n2723 | applications that need `UpdateSpatialAnchorPose`) and for `VREvent_SpatialAnchors_RequestDescriptorUpdate` events (for\\r\\n2724 | new poses that need `UpdateSpatialAnchorDescriptor`).\\r\\n2725 | \\r\\n2726 | For automatic pose updates over time, the driver **should** keep track of the handles it has seen and provide updates\\r\\n2727 | when conditions change.\\r\\n2728 | \\r\\n2729 | <br />\\r\\n2730 | \\r\\n2731 | ```c++\\r\\n2732 | virtual EVRSpatialAnchorError UpdateSpatialAnchorPose( SpatialAnchorHandle_t unHandle, const SpatialAnchorDriverPose_t *pPose ) = 0;\\r\\n2733 | ```\\r\\n2734 | \\r\\n2735 | `UpdateSpatialAnchorPose` updates a pose for a spatial anchor.\\r\\n2736 | \\r\\n2737 | `UpdateSpatialAnchorPose` **should** be called when an event notifies the driver that a new descriptor has been\\r\\n2738 | registered by an application.\\r\\n2739 | \\r\\n2740 | `UpdateSpatialAnchorPose` **should** be called on all active handles whenever driver state changes in a way that changes\\r\\n2741 | how physical world locations map to virtual coordinates (e.g. anything that would cause a universe ID change).\\r\\n2742 | \\r\\n2743 | `UpdateSpatialAnchorPose` **can** be called for any anchor whenever the driver has better information about the best\\r\\n2744 | virtual coordinate to represent the anchor.\\r\\n2745 | \\r\\n2746 | `UpdateSpatialAnchorPose` fires an event when it is called for the first time (to alert whoever submitted the\\r\\n2747 | descriptor).\\r\\n2748 | \\r\\n2749 | Returns `EVRSpatialAnchorError`, which is hopefully `VRSpatialAnchorError_Success`.\\r\\n2750 | \\r\\n2751 | * `SpatialAnchorHandle_t unHandle` - The handle of the anchor to update.\\r\\n2752 | * `const SpatialAnchorDriverPose_t *pPose` - The new pose for the anchor.\\r\\n2753 |     * `vr::HmdQuaternion_t qWorldRotation` - The orientation of the anchor in world space as provided by `DriverPose_t`.\\r\\n2754 |       Right-handed coordinate system.\\r\\n2755 |     * `vr::HmdVector3d_t vWorldTranslation` - The translation of the anchor in world space as provided\\r\\n2756 |       by `DriverPose_t`. Right-handed coordinate system.\\r\\n2757 |     * `uint64_t ulRequiredUniverseId` - The universe the spatial anchor is in. This **should** be the same as the one\\r\\n2758 |       provided in the device's property `Prop_CurrentUniverseId_Uint64`. Note: 0 is invalid, and 1 is reserved for\\r\\n2759 |       Oculus as universe ids.\\r\\n2760 |     * `double fValidDuration` - The duration, in seconds, that the pose of the spatial anchor is valid for. This **can**\\r\\n2761 |       be used so the driver does not have to keep track of the duration of time the spacial anchor's pose is valid for.\\r\\n2762 |       When the time expires, the runtime **will** start\\r\\n2763 |       generating `VREvent_SpatialAnchors_RequestPoseUpdate` when the pose is read by an application to let the driver\\r\\n2764 |       know it is still worth updating.\\r\\n2765 |         * A value of `-1` results in never receiving an update request for this pose. The driver **can** still update\\r\\n2766 |           poses for this anchor at any time.\\r\\n2767 |         * A value of `0` results in an update request *after* each time the pose is read.\\r\\n2768 |             * This can be very high if the application gets the pose at the framerate.\\r\\n2769 |         * If the driver knows there is no reason to update the pose for some amount of time, it can set that time here\\r\\n2770 |           and receive the update request reminder later.\\r\\n2771 |         * If the driver plans to automatically update this pose for some amount of time (as it gets better information\\r\\n2772 |           about the virtual location of this anchor), it **can** set that duration here to indicate no \\\"update\\r\\n2773 |           requested\\\" reminders are needed. When that automatic update period expires, any\\r\\n2774 |           future interest in the pose will be indicated by a pose update request.\\r\\n2775 |         * A driver **can** always update the pose at any time, _including_ during the valid duration.\\r\\n2776 | \\r\\n2777 | <br />\\r\\n2778 | \\r\\n2779 | ```c++\\r\\n2780 | virtual EVRSpatialAnchorError SetSpatialAnchorPoseError( SpatialAnchorHandle_t unHandle, EVRSpatialAnchorError eError, double fValidDuration ) = 0;\\r\\n2781 | ```\\r\\n2782 | \\r\\n2783 | `SetSpatialAnchorPoseError` invalidates any pose associated with the handle and cause future calls\\r\\n2784 | to `GetSpatialAnchorPose` (on both the client and driver side) to return the specified error.\\r\\n2785 | \\r\\n2786 | * `SpatialAnchorHandle_t unHandle` - The handle of the anchor to update.\\r\\n2787 | * `EVRSpatialAnchorError eError` - The error to return for the anchor. **Must** be one of:\\r\\n2788 |     * `VRSpatialAnchorError_NotYetAvailable`\\r\\n2789 |     * `VRSpatialAnchorError_NotAvailableInThisUniverse`\\r\\n2790 |     * `VRSpatialAnchorError_PermanentlyUnavailable`\\r\\n2791 | * `double fValidDuration` - How long, in seconds, this error is valid for. See definition of `fValidDuration` above for\\r\\n2792 |   more details.\\r\\n2793 | \\r\\n2794 | <br />\\r\\n2795 | \\r\\n2796 | ```c++\\r\\n2797 | virtual EVRSpatialAnchorError UpdateSpatialAnchorDescriptor( SpatialAnchorHandle_t unHandle, const char *pchDescriptor ) = 0;\\r\\n2798 | ```\\r\\n2799 | \\r\\n2800 | `UpdateSpatialAnchorDescriptor` updates the descriptor for a spatial anchor.\\r\\n2801 | \\r\\n2802 | `UpdateSpatialAnchorDescriptor` **should** be called when an event notifies the driver that a new pose has been\\r\\n2803 | registered by an application.\\r\\n2804 | \\r\\n2805 | `UpdateSpatialAnchorDescriptor` **can** called for any anchor whenever the driver has better or additional information\\r\\n2806 | it wants to include in the anchor descriptor.\\r\\n2807 | \\r\\n2808 | Note, however, that the application **may** never fetch the updated anchor descriptor and **may** request the original\\r\\n2809 | descriptor in a future session having ignored the update.\\r\\n2810 | \\r\\n2811 | The supplied descriptor **should** be _only_ the driver's opaque internal data, not the decorated form that is used by\\r\\n2812 | clients (wrapped by runtime metadata).\\r\\n2813 | \\r\\n2814 | `UpdateSpatialAnchorDescriptor` **will** fire an event every time it is called.\\r\\n2815 | \\r\\n2816 | Returns `EVRSpatialAnchorError`, which is hopefully `VRSpatialAnchorError_Success`.\\r\\n2817 | \\r\\n2818 | * `SpatialAnchorHandle_t unHandle` - The handle of the anchor to update.\\r\\n2819 | * `const char *pchDescriptor` - The new descriptor for the anchor. The descriptor **must not** contain non-ASCII\\r\\n2820 |   characters or the two special characters `~` or `\\\"`.\\r\\n2821 | \\r\\n2822 | <br />\\r\\n2823 | \\r\\n2824 | ```c++\\r\\n2825 | virtual EVRSpatialAnchorError GetSpatialAnchorPose( SpatialAnchorHandle_t unHandle, SpatialAnchorDriverPose_t *pDriverPoseOut ) = 0;\\r\\n2826 | ```\\r\\n2827 | \\r\\n2828 | `GetSpatialAnchorPose` gets the pose for a spatial anchor.\\r\\n2829 | \\r\\n2830 | * `SpatialAnchorHandle_t unHandle` - The handle of the anchor to get.\\r\\n2831 | * `SpatialAnchorDriverPose_t *pDriverPoseOut` - Fills with pose for the anchor. See `UpdateSpatialAnchorPose` for\\r\\n2832 |   details on the pose data.\\r\\n2833 | \\r\\n2834 | <br />\\r\\n2835 | \\r\\n2836 | ```c++\\r\\n2837 | virtual EVRSpatialAnchorError GetSpatialAnchorDescriptor( SpatialAnchorHandle_t unHandle, VR_OUT_STRING() char *pchDescriptorOut, uint32_t *punDescriptorBufferLenInOut, bool bDecorated ) = 0;\\r\\n2838 | ```\\r\\n2839 | \\r\\n2840 | `GetSpatialAnchorDescriptor` gets the descriptor for a spatial anchor for a given spacial anchor handle.\\r\\n2841 | \\r\\n2842 | `GetSpatialAnchorDescriptor` returns `VRSpatialAnchorError_NotYetAvailable` for handles where the driver has not yet\\r\\n2843 | built a descriptor.\\r\\n2844 | \\r\\n2845 | The descriptor returned will be the application-supplied descriptor for previously saved anchors that the application is\\r\\n2846 | requesting poses for.\\r\\n2847 | \\r\\n2848 | If the driver has called `UpdateSpatialAnchorDescriptor` already in this session, it will be the descriptor provided by\\r\\n2849 | the driver.\\r\\n2850 | \\r\\n2851 | * `SpatialAnchorHandle_t unHandle` - The handle of the anchor to get.\\r\\n2852 | * `VR_OUT_STRING() char *pchDescriptorOut` - Fills with the descriptor for the anchor.\\r\\n2853 | * `uint32_t *punDescriptorBufferLenInOut` - The number of bytes written to `pchDescriptorOut`.\\r\\n2854 | * `bool bDecorated` - If `true`, the descriptor returned will be the decorated form that is used by clients (wrapped by\\r\\n2855 |   runtime metadata). Else if `false`, the descriptor returned will be the driver's opaque internal data.\\r\\n2856 | \\r\\n2857 | ## Poses\\r\\n2858 | \\r\\n2859 | A pose contains the state of a device in space at a given moment. It contains properties such as position, rotation,\\r\\n2860 | velocity and angular velocity, as well as some extra information that describes how the device is tracking, and whether\\r\\n2861 | it believes the poses it is giving are actually valid. A pose provided by a driver is given by the `vr::DriverPose_t`\\r\\n2862 | struct.\\r\\n2863 | \\r\\n2864 | The runtime uses the velocities to apply prediction to the pose.\\r\\n2865 | \\r\\n2866 | OpenVR uses the right-handed coordinate system, where X+ points to the right, the Y+ points up, and the Z+ axis points\\r\\n2867 | backwards. `vecPosition`, `vecVelocity`, `vecAcceleration`, `vecAngularVelocity` and `vecAngularAcceleration` **must**be\\r\\n2868 | in this space, either directly, or through setting `qWorldFromDriverRotation` and `qDriverFromHeadRotation` to account\\r\\n2869 | for the transform.\\r\\n2870 | \\r\\n2871 | ```c++\\r\\n2872 | struct DriverPose_t\\r\\n2873 | {\\r\\n2874 |     double poseTimeOffset;\\r\\n2875 | \\r\\n2876 |     vr::HmdQuaternion_t qWorldFromDriverRotation;\\r\\n2877 |     double vecWorldFromDriverTranslation[ 3 ];\\r\\n2878 | \\r\\n2879 |     vr::HmdQuaternion_t qDriverFromHeadRotation;\\r\\n2880 |     double vecDriverFromHeadTranslation[ 3 ];\\r\\n2881 | \\r\\n2882 |     double vecPosition[ 3 ];\\r\\n2883 |     double vecVelocity[ 3 ];\\r\\n2884 |     double vecAcceleration[ 3 ];\\r\\n2885 | \\r\\n2886 |     vr::HmdQuaternion_t qRotation;\\r\\n2887 | \\r\\n2888 |     double vecAngularVelocity[ 3 ];\\r\\n2889 |     double vecAngularAcceleration[ 3 ];\\r\\n2890 | \\r\\n2891 |     ETrackingResult result;\\r\\n2892 | \\r\\n2893 |     bool poseIsValid;\\r\\n2894 |     bool willDriftInYaw;\\r\\n2895 |     bool shouldApplyHeadModel;\\r\\n2896 |     bool deviceIsConnected;\\r\\n2897 | };\\r\\n2898 | ```\\r\\n2899 | \\r\\n2900 | * `double poseTimeOffset` - Time offset of this pose, in seconds from the actual time of the pose, relative to the time\\r\\n2901 |   of submitting the pose to the runtime. This property is used internally in SteamVR for estimating where the device\\r\\n2902 |   _currently_ is in space.\\r\\n2903 | * `vr::HmdQuaternion_t qWorldFromDriverRotation` - See below. This **must** be a valid quaternion (w=1.0) even if the\\r\\n2904 |   driver does not need to use this transform.\\r\\n2905 | * `double vecWorldFromDriverTranslation[ 3 ]` - The transform from the driver's coordinate space to the world coordinate\\r\\n2906 |   space. This transform is applied to the pose before it is used by the runtime. This is useful for drivers that want to\\r\\n2907 |   provide poses in a different coordinate space than the world coordinate space\\r\\n2908 | * `vr::HmdQuaternion_t qDriverFromHeadRotation` - See below. This **must** be a valid quaternion (w=1.0) even if the\\r\\n2909 |   driver does not need to use this transform.\\r\\n2910 | * `double vecDriverFromHeadTranslation[ 3 ];` - The transform from the driver's coordinate space to the head coordinate\\r\\n2911 |   space. The driver is not usually tracking the \\\"head\\\" position, but instead an internal IMU or another reference point\\r\\n2912 |   in the HMD.\\r\\n2913 |   The following two transforms transform positions and orientations to app world space from driver world space, and to\\r\\n2914 |   HMD head space from driver local body space.\\r\\n2915 | * `double vecPosition[ 3 ];` - The position of the device's tracking reference in driver world space, in metres.\\r\\n2916 | * `double vecVelocity[ 3 ];` - The velocity of the device's tracking reference in driver world space, in metres per\\r\\n2917 |   second.\\r\\n2918 |     * Used for prediction of the pose at the time when the application requests a pose for the device.\\r\\n2919 | * `double vecAcceleration[ 3 ];` - The acceleration of the device's tracking reference in driver world space, in m/s^2.\\r\\n2920 |     * This is **not** currently used by SteamVR. The value of this member will have no effect on the pose.\\r\\n2921 | * `vr::HmdQuaternion_t qRotation;` - The orientation of the device's tracking reference in driver world space, as a\\r\\n2922 |   quaternion.\\r\\n2923 | * `double vecAngularVelocity[ 3 ];` - The angular velocity of the device's tracking reference in driver world space, in\\r\\n2924 |   radians per second.\\r\\n2925 |     * Used for prediction of the pose at the time when the application requests a pose for the device.\\r\\n2926 | * `double vecAngularAcceleration[ 3 ];` - The angular acceleration of the device's tracking reference in driver world\\r\\n2927 |   space, in rad/s^2.\\r\\n2928 |     * This is **not** currently used by SteamVR. The value of this member will have no effect on the pose.\\r\\n2929 | * `ETrackingResult result` - The tracking result of the pose. This is used by the runtime to determine whether the pose\\r\\n2930 |   is valid to display, and what icon to show the user.\\r\\n2931 |     * `TrackingResult_Uninitialized` - The pose is invalid, and should not be used.\\r\\n2932 |     * `TrackingResult_Calibrating_InProgress` - The device is still calibrating and not fully ready to track yet.\\r\\n2933 |     * `TrackingResult_Calibrating_OutOfRange` - The pose is valid, but the device is still calibrating (or not connected\\r\\n2934 |       fully yet), and should not\\r\\n2935 |       be used. If this is an HMD, a grey screen will be shown.\\r\\n2936 |     * `TrackingResult_Running_OK` - The pose is valid, and the device is calibrated.\\r\\n2937 |     * `TrackingResult_Running_OutOfRange` - The device is connected, but something is wrong with the pose. If this is an\\r\\n2938 |       HMD, a grey screen will be shown.\\r\\n2939 |     * `TrackingResult_Fallback_RotationOnly` - The pose is valid, but the device is out of range, and should not be\\r\\n2940 |       used.\\r\\n2941 | * `bool poseIsValid;` - Whether the pose is valid. This is used by the runtime to determine whether the pose is valid to\\r\\n2942 |   display, and what icon to show the user.\\r\\n2943 | * `bool willDriftInYaw` - This isn't used by vrserver and can be ignored.\\r\\n2944 | * `bool shouldApplyHeadModel` - Whether the runtime should apply translations between the screen and the center of\\r\\n2945 |   rotation of the head (the neck). Useful for re-projection.\\r\\n2946 | * `bool deviceIsConnected` - Whether the device is connected. This is used by the runtime to determine whether the pose\\r\\n2947 |   is valid to display, and what icon to show the user.\\r\\n2948 | \\r\\n2949 | It is up to the driver to update the pose of its devices. The runtime **will** extrapolate 100ms past the time of\\r\\n2950 | submission, but the driver **should** update the pose of its devices as often as possible, but at least once per frame.\\r\\n2951 | The runtime **will not** extrapolate past 100ms and should the device not update its pose within that time, the runtime\\r\\n2952 | will invalidate the pose.\\r\\n2953 | \\r\\n2954 | When a device wishes to update its pose, it should make a call to `vr::VRServerDriverHost()->TrackedDevicePoseUpdated` (\\r\\n2955 | see [IVRServerDriverHost](#ivrserverdriverhost)) with a struct filled with its pose:\\r\\n2956 | \\r\\n2957 | ```c++\\r\\n2958 | vr::DriverPose_t myPose;\\r\\n2959 | \\r\\n2960 | // ... Fill in myPose ...\\r\\n2961 | \\r\\n2962 | vr::VRServerDriverHost()->TrackedDevicePoseUpdated( myDeviceId, myPose, sizeof( vr::DriverPose_t ));\\r\\n2963 | ```\\r\\n2964 | \\r\\n2965 | It is also possible to fetch poses of other devices. `vr::VRServerDriverHost()->GetRawTrackedDevicePoses` provides\\r\\n2966 | access to device poses for drivers. Poses are in their \\\"raw\\\" tracking space which is uniquely defined by each driver\\r\\n2967 | providing poses for its devices. It is up to clients of this function to correlate poses across different drivers. Poses\\r\\n2968 | are indexed by their device id, and their associated driver and other properties can be looked up via\\r\\n2969 | IVRProperties. `GetRawTrackedDevicePoses` returns an array of poses from id 0 (which is always the HMD) up to a certain\\r\\n2970 | count. See [IVRServerDriverHost](#ivrserverdriverhost) for more information on this method.\\r\\n2971 | \\r\\n2972 | ## Skeletal Input\\r\\n2973 | \\r\\n2974 | If you are developing an OpenVR driver for a device that is capable of detecting what the user's hand is doing, either\\r\\n2975 | implicitly or explicitly, you **can** provide that information to applications as a stream of skeletal animation through\\r\\n2976 | the `IVRDriverInput` API.\\r\\n2977 | \\r\\n2978 | ### Notes on hand tracking compatibility\\r\\n2979 | \\r\\n2980 | There are some games and applications that were created before the announcement of this interface, and so offer their\\r\\n2981 | own hand tracking implementation. These implementations typically tend to bind finger curls to input components\\r\\n2982 | specified\\r\\n2983 | in the input profile, instead of using the skeletal input system. In addition, these games also tend to have hard-coded\\r\\n2984 | check for specific controller types within SteamVR to enable binding finger curls to their hand posing system.\\r\\n2985 | \\r\\n2986 | A non-exhaustive list of well-known applications that do this are provided below:\\r\\n2987 | \\r\\n2988 | * VRChat - Looks for `input/finger/<index/middle/ring/pinky>` trigger input components for individual finger curls on\\r\\n2989 |   controller type of `knuckles` for `controller_type` specified in the input profile.\\r\\n2990 | * Boneworks - Looks for `input/finger/<index/middle/ring/pinky>` trigger input components for individual finger curls on\\r\\n2991 |   controller_type of `knuckles` for `controller_type` specified in the input profile.\\r\\n2992 | * Bonelab - Looks for `input/finger/<index/middle/ring/pinky>` trigger input components for individual finger curls on\\r\\n2993 |   controller_type of `knuckles` for `controller_type` specified in the input profile.\\r\\n2994 | \\r\\n2995 | While a solution to this is to expose your own devices with `knuckles` set as the controller type, this is not\\r\\n2996 | recommended. Doing this means that your devices are restricted to the inputs of the index controller, and users will see\\r\\n2997 | binding profiles for the index controllers in SteamVR bindings.\\r\\n2998 | \\r\\n2999 | The solution driver **should** implement is to [emulate the controllers via SteamVR emulation](#device-emulation). This\\r\\n3000 | changes various properties, such as controller type and rendermodel name, that the applications may be using to enable\\r\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\ndocs\\\\Driver_API_Documentation.md\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:35:19 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n116,523 (58%)\\n\\n# Current Cost\\n$0.87\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":113,\"cacheWrites\":10131,\"cacheReads\":116375,\"cost\":0.07461075}"},{"ts":1744500922376,"type":"say","say":"text","text":"I've gathered a lot of information about the OpenVR driver architecture and how to implement a custom driver. Let me now look for any sample drivers in the codebase that might serve as references for our custom driver implementation.\n\nLet me look for any sample drivers in the codebase that might serve as references for our custom driver implementation:","partial":false},{"ts":1744500923940,"type":"ask","ask":"tool","text":"{\"tool\":\"searchFiles\",\"path\":\"samples/drivers\",\"regex\":\".*\",\"filePattern\":\"\",\"content\":\"Found 11 results.\\n\\n# samples/drivers/vs-openvr_samples.sln\\n  1 | \\n  2 | Microsoft Visual Studio Solution File, Format Version 12.00\\n  3 | # Visual Studio Version 16\\n  4 | VisualStudioVersion = 16.0.33214.272\\n  5 | MinimumVisualStudioVersion = 10.0.40219.1\\n  6 | Project(\\\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\\") = \\\"util_driverlog\\\", \\\"utils\\\\driverlog\\\\util_driverlog.vcxproj\\\", \\\"{89689A91-FB38-4893-BA67-3D6F45EB2712}\\\"\\n  7 | EndProject\\n  8 | Project(\\\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\\") = \\\"util_vrmath\\\", \\\"utils\\\\vrmath\\\\util_vrmath.vcxproj\\\", \\\"{AC31972F-E424-4C19-86EB-7BCF1E9F8460}\\\"\\n  9 | EndProject\\n 10 | Project(\\\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\\") = \\\"barebones\\\", \\\"drivers\\\\barebones\\\\barebones.vcxproj\\\", \\\"{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}\\\"\\n 11 | EndProject\\n 12 | Project(\\\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\\") = \\\"simplecontroller\\\", \\\"drivers\\\\simplecontroller\\\\simplecontroller.vcxproj\\\", \\\"{13391803-5E60-4BED-9B54-F9004412E16C}\\\"\\n 13 | EndProject\\n 14 | Project(\\\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\\") = \\\"simplehmd\\\", \\\"drivers\\\\simplehmd\\\\simplehmd.vcxproj\\\", \\\"{1A008D17-0760-4179-8D42-995C5FF1C8D6}\\\"\\n 15 | EndProject\\n 16 | Project(\\\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\\") = \\\"handskeletonsimulation\\\", \\\"drivers\\\\handskeletonsimulation\\\\handskeletonsimulation.vcxproj\\\", \\\"{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}\\\"\\n 17 | EndProject\\n 18 | Project(\\\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\\") = \\\"simpletrackers\\\", \\\"drivers\\\\simpletrackers\\\\simpletrackers.vcxproj\\\", \\\"{F6FB2D3A-6B65-403D-8F4E-24AA16527098}\\\"\\n 19 | EndProject\\n 20 | Global\\n 21 | \\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\\n 22 | \\t\\tDebug|x64 = Debug|x64\\n 23 | \\t\\tDebug|x86 = Debug|x86\\n 24 | \\t\\tRelease|x64 = Release|x64\\n 25 | \\t\\tRelease|x86 = Release|x86\\n 26 | \\tEndGlobalSection\\n 27 | \\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\\n 28 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Debug|x64.ActiveCfg = Debug|x64\\n 29 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Debug|x64.Build.0 = Debug|x64\\n 30 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Debug|x86.ActiveCfg = Debug|Win32\\n 31 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Debug|x86.Build.0 = Debug|Win32\\n 32 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Release|x64.ActiveCfg = Release|x64\\n 33 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Release|x64.Build.0 = Release|x64\\n 34 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Release|x86.ActiveCfg = Release|Win32\\n 35 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Release|x86.Build.0 = Release|Win32\\n 36 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Debug|x64.ActiveCfg = Debug|x64\\n 37 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Debug|x64.Build.0 = Debug|x64\\n 38 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Debug|x86.ActiveCfg = Debug|Win32\\n 39 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Debug|x86.Build.0 = Debug|Win32\\n 40 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Release|x64.ActiveCfg = Release|x64\\n 41 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Release|x64.Build.0 = Release|x64\\n 42 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Release|x86.ActiveCfg = Release|Win32\\n 43 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Release|x86.Build.0 = Release|Win32\\n 44 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Debug|x64.ActiveCfg = Debug|x64\\n 45 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Debug|x64.Build.0 = Debug|x64\\n 46 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Debug|x86.ActiveCfg = Debug|Win32\\n 47 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Debug|x86.Build.0 = Debug|Win32\\n 48 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Release|x64.ActiveCfg = Release|x64\\n 49 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Release|x64.Build.0 = Release|x64\\n 50 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Release|x86.ActiveCfg = Release|Win32\\n 51 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Release|x86.Build.0 = Release|Win32\\n 52 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Debug|x64.ActiveCfg = Debug|x64\\n 53 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Debug|x64.Build.0 = Debug|x64\\n 54 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Debug|x86.ActiveCfg = Debug|Win32\\n 55 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Debug|x86.Build.0 = Debug|Win32\\n 56 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Release|x64.ActiveCfg = Release|x64\\n 57 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Release|x64.Build.0 = Release|x64\\n 58 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Release|x86.ActiveCfg = Release|Win32\\n 59 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Release|x86.Build.0 = Release|Win32\\n 60 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Debug|x64.ActiveCfg = Debug|x64\\n 61 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Debug|x64.Build.0 = Debug|x64\\n 62 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Debug|x86.ActiveCfg = Debug|Win32\\n 63 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Debug|x86.Build.0 = Debug|Win32\\n 64 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Release|x64.ActiveCfg = Release|x64\\n 65 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Release|x64.Build.0 = Release|x64\\n 66 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Release|x86.ActiveCfg = Release|Win32\\n 67 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Release|x86.Build.0 = Release|Win32\\n 68 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Debug|x64.ActiveCfg = Debug|x64\\n 69 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Debug|x64.Build.0 = Debug|x64\\n 70 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Debug|x86.ActiveCfg = Debug|Win32\\n 71 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Debug|x86.Build.0 = Debug|Win32\\n 72 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Release|x64.ActiveCfg = Release|x64\\n 73 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Release|x64.Build.0 = Release|x64\\n 74 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Release|x86.ActiveCfg = Release|Win32\\n 75 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Release|x86.Build.0 = Release|Win32\\n 76 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Debug|x64.ActiveCfg = Debug|x64\\n 77 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Debug|x64.Build.0 = Debug|x64\\n 78 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Debug|x86.ActiveCfg = Debug|Win32\\n 79 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Debug|x86.Build.0 = Debug|Win32\\n 80 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Release|x64.ActiveCfg = Release|x64\\n 81 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Release|x64.Build.0 = Release|x64\\n 82 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Release|x86.ActiveCfg = Release|Win32\\n 83 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Release|x86.Build.0 = Release|Win32\\n 84 | \\tEndGlobalSection\\n 85 | \\tGlobalSection(SolutionProperties) = preSolution\\n 86 | \\t\\tHideSolutionNode = FALSE\\n 87 | \\tEndGlobalSection\\n 88 | \\tGlobalSection(ExtensibilityGlobals) = postSolution\\n 89 | \\t\\tSolutionGuid = {1085EFDE-F216-4EF1-BB18-106228E5D0DA}\\n 90 | \\tEndGlobalSection\\n 91 | EndGlobal\\n----\\n\\n# samples/drivers/drivers/CMakeLists.txt\\n  1 | add_subdirectory(barebones)\\n  2 | add_subdirectory(handskeletonsimulation)\\n  3 | add_subdirectory(simplecontroller)\\n  4 | add_subdirectory(simplehmd)\\n  5 | add_subdirectory(simpletrackers)\\n----\\n\\n# samples/drivers/README.md\\n  1 | # OpenVR Driver Samples\\n  2 | \\n  3 | ## CMake\\n  4 | \\n  5 | The `CMakeLists.txt` found in this folder shows how to link OpenVR libraries.\\n  6 | \\n  7 | These are added to the targets in each sample.\\n  8 | \\n  9 | ## Samples\\n 10 | \\n 11 | `drivers/` - driver samples. See `drivers/` for information on each of the drivers.\\n 12 | \\n 13 | * `barebones`\\n 14 | * `handskeletonsimulation`\\n 15 | * `simplecontroller`\\n 16 | \\n 17 | `utils/` - utility samples, that can be copied to your own project for ease of development.\\n 18 | \\n 19 | * `driverlog`\\n 20 | * `vrmath`\\n 21 | \\n 22 | ## Building\\n 23 | \\n 24 | There are two options that can be used to build the samples: [CMake](#building-with-cmake)\\n 25 | or [Visual Studio](#building-with-visual-studio).\\n 26 | \\n 27 | This directory contains both a CMakeLists.txt file which can be used to create a Visual Studio solution, or you can use\\n 28 | the Visual Studio solution provided in this directory.\\n 29 | \\n 30 | ### Building with CMake\\n 31 | \\n 32 | To create a solution for the samples, run (in this directory):\\n 33 | \\n 34 | * `cmake -A x64 -B build`\\n 35 | * Navigate into `build/` and open the solution.\\n 36 | * Build the project.\\n 37 | \\n 38 | ### Building with Visual Studio\\n 39 | \\n 40 | Open the `vs-openvr_samples.sln` file in Visual Studio (2019 or 2022).\\n 41 | \\n 42 | Build the project by pressing `Ctrl + Shift + B`.\\n 43 | \\n 44 | ## Build Artifacts\\n 45 | \\n 46 | Building with either CMake or Visual Studio will output the build artifacts to the `output/` directory.\\n 47 | \\n 48 | See `drivers/` for more documentation on linking the drivers to SteamVR.\\n 49 | \\n 50 | Building the project will output the driver binary to `output/drivers/<driver_name>/bin/win64/driver_<driver_name>.dll`\\n----\\n\\n# samples/drivers/drivers/barebones/CMakeLists.txt\\n  1 | set(TARGET_NAME barebones)\\n  2 | \\n  3 | # This is the name of the driver according to SteamVR\\n  4 | set(DRIVER_NAME \\\"driver_${TARGET_NAME}\\\")\\n  5 | \\n  6 | project(${TARGET_NAME})\\n  7 | \\n  8 | add_library(${DRIVER_NAME} SHARED\\n  9 | \\tsrc/hmd_driver_factory.cpp\\n 10 | \\tsrc/device_provider.h\\n 11 | \\tsrc/device_provider.cpp\\n 12 | )\\n 13 | \\n 14 | # This is so we can build directly to \\\"<binary_dir>/<target_name>/<platform>/<arch>/<driver_name>.<dll/so>\\\"\\n 15 | set_target_properties(${DRIVER_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET_NAME}/bin/${ARCH_TARGET}>)\\n 16 | \\n 17 | target_link_libraries(${DRIVER_NAME} PRIVATE ${OPENVR_LIBRARIES} util_driverlog)\\n 18 | target_include_directories(${DRIVER_NAME} PRIVATE ${OPENVR_INCLUDE_DIR})\\n 19 | \\n 20 | # Copy driver assets to output folder\\n 21 | add_custom_command(\\n 22 |         TARGET ${DRIVER_NAME}\\n 23 |         PRE_BUILD\\n 24 |         COMMAND ${CMAKE_COMMAND} -E copy_directory\\n 25 |         ${CMAKE_CURRENT_SOURCE_DIR}/${TARGET_NAME}\\n 26 |         ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET_NAME}\\n 27 | )\\n----\\n\\n# samples/drivers/utils/vrmath/CMakeLists.txt\\n  1 | add_library(util_vrmath INTERFACE vrmath.h)\\n  2 | target_include_directories(util_vrmath INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})\\n  3 | \\n  4 | target_link_libraries(util_vrmath INTERFACE ${OPENVR_LIBRARIES})\\n  5 | target_include_directories(util_vrmath INTERFACE ${OPENVR_INCLUDE_DIR})\\n----\\n\\n# samples/drivers/utils/driverlog/driverlog.h\\n  1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\n  2 | #pragma once\\n  3 | \\n  4 | #include <string>\\n  5 | #include <openvr_driver.h>\\n  6 | \\n  7 | extern void DriverLog( const char *pchFormat, ... );\\n  8 | \\n  9 | extern void DebugDriverLog( const char *pchFormat, ... );\\n----\\n\\n# samples/drivers/utils/driverlog/driverlog.cpp\\n  1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\n  2 | #include \\\"driverlog.h\\\"\\n  3 | \\n  4 | #include <stdarg.h>\\n  5 | #include <stdio.h>\\n  6 | \\n  7 | #if !defined( WIN32 )\\n  8 | #define vsnprintf_s vsnprintf\\n  9 | #endif\\n 10 | \\n 11 | static void DriverLogVarArgs( const char *pMsgFormat, va_list args )\\n 12 | {\\n 13 | \\tchar buf[ 1024 ];\\n 14 | \\tvsnprintf_s( buf, sizeof( buf ), pMsgFormat, args );\\n 15 | \\n 16 | \\tvr::VRDriverLog()->Log( buf );\\n 17 | }\\n 18 | \\n 19 | \\n 20 | void DriverLog( const char *pMsgFormat, ... )\\n 21 | {\\n 22 | \\tva_list args;\\n 23 | \\tva_start( args, pMsgFormat );\\n 24 | \\n 25 | \\tDriverLogVarArgs( pMsgFormat, args );\\n 26 | \\n 27 | \\tva_end( args );\\n 28 | }\\n 29 | \\n 30 | \\n 31 | void DebugDriverLog( const char *pMsgFormat, ... )\\n 32 | {\\n 33 | #ifdef _DEBUG\\n 34 | \\tva_list args;\\n 35 | \\tva_start( args, pMsgFormat );\\n 36 | \\n 37 | \\tDriverLogVarArgs( pMsgFormat, args );\\n 38 | \\n 39 | \\tva_end( args );\\n 40 | #endif\\n 41 | }\\n----\\n\\n# samples/drivers/utils/driverlog/CMakeLists.txt\\n  1 | add_library(util_driverlog STATIC driverlog.h driverlog.cpp)\\n  2 | target_include_directories(util_driverlog PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})\\n  3 | \\n  4 | target_link_libraries(util_driverlog PRIVATE ${OPENVR_LIBRARIES})\\n  5 | target_include_directories(util_driverlog PUBLIC ${OPENVR_INCLUDE_DIR})\\n----\\n\\n# samples/drivers/drivers/handskeletonsimulation/src/hmd_driver_factory.cpp\\n  1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\n  2 | #include \\\"device_provider.h\\\"\\n  3 | #include \\\"openvr_driver.h\\\"\\n  4 | #include <cstring>\\n  5 | \\n  6 | #if defined( _WIN32 )\\n  7 | #define HMD_DLL_EXPORT extern \\\"C\\\" __declspec( dllexport )\\n  8 | #define HMD_DLL_IMPORT extern \\\"C\\\" __declspec( dllimport )\\n  9 | #elif defined( __GNUC__ ) || defined( COMPILER_GCC ) || defined( __APPLE__ )\\n 10 | #define HMD_DLL_EXPORT extern \\\"C\\\" __attribute__( ( visibility( \\\"default\\\" ) ) )\\n 11 | #define HMD_DLL_IMPORT extern \\\"C\\\"\\n 12 | #else\\n 13 | #error \\\"Unsupported Platform.\\\"\\n 14 | #endif\\n 15 | \\n 16 | MyDeviceProvider device_provider;\\n 17 | \\n 18 | //-----------------------------------------------------------------------------\\n 19 | // Purpose: This is exported from the shared library to be called as the entry point into the driver by vrserver.\\n 20 | // You should return a point to your IServerTrackedDeviceProvider here, as well as optionally a watchdog (see other\\n 21 | // samples).\\n 22 | //-----------------------------------------------------------------------------\\n 23 | HMD_DLL_EXPORT void *HmdDriverFactory( const char *pInterfaceName, int *pReturnCode )\\n 24 | {\\n 25 | \\t// This is where we return our device provider, if the HmdDriverFactory call asks for it.\\n 26 | \\tif ( 0 == strcmp( vr::IServerTrackedDeviceProvider_Version, pInterfaceName ) )\\n 27 | \\t{\\n 28 | \\t\\treturn &device_provider;\\n 29 | \\t}\\n 30 | \\n 31 | \\t// Otherwise tell the runtime that we don't have this interface.\\n 32 | \\tif ( pReturnCode )\\n 33 | \\t\\t*pReturnCode = vr::VRInitError_Init_InterfaceNotFound;\\n 34 | \\n 35 | \\treturn NULL;\\n 36 | }\\n----\\n\\n# samples/drivers/drivers/handskeletonsimulation/src/hand_simulation.h\\n  1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\n  2 | #pragma once\\n  3 | \\n  4 | #include \\\"openvr_driver.h\\\"\\n  5 | \\n  6 | // 0-1 values (1 fully curled)\\n  7 | struct MyFingerCurls\\n  8 | {\\n  9 | \\tfloat thumb;\\n 10 | \\tfloat index;\\n 11 | \\tfloat middle;\\n 12 | \\tfloat ring;\\n 13 | \\tfloat pinky;\\n 14 | };\\n 15 | \\n 16 | //-1-1 values (1 fully to the left)\\n 17 | struct MyFingerSplays\\n 18 | {\\n 19 | \\tfloat thumb;\\n 20 | \\tfloat index;\\n 21 | \\tfloat middle;\\n 22 | \\tfloat ring;\\n 23 | \\tfloat pinky;\\n 24 | };\\n 25 | \\n 26 | enum HandSkeletonBone : vr::BoneIndex_t\\n 27 | {\\n 28 | \\teBone_Root = 0,\\n 29 | \\teBone_Wrist,\\n 30 | \\teBone_Thumb0,\\n 31 | \\teBone_Thumb1,\\n 32 | \\teBone_Thumb2,\\n 33 | \\teBone_Thumb3,\\n 34 | \\teBone_IndexFinger0,\\n 35 | \\teBone_IndexFinger1,\\n 36 | \\teBone_IndexFinger2,\\n 37 | \\teBone_IndexFinger3,\\n 38 | \\teBone_IndexFinger4,\\n 39 | \\teBone_MiddleFinger0,\\n 40 | \\teBone_MiddleFinger1,\\n 41 | \\teBone_MiddleFinger2,\\n 42 | \\teBone_MiddleFinger3,\\n 43 | \\teBone_MiddleFinger4,\\n 44 | \\teBone_RingFinger0,\\n 45 | \\teBone_RingFinger1,\\n 46 | \\teBone_RingFinger2,\\n 47 | \\teBone_RingFinger3,\\n 48 | \\teBone_RingFinger4,\\n 49 | \\teBone_PinkyFinger0,\\n 50 | \\teBone_PinkyFinger1,\\n 51 | \\teBone_PinkyFinger2,\\n 52 | \\teBone_PinkyFinger3,\\n 53 | \\teBone_PinkyFinger4,\\n 54 | \\teBone_Aux_Thumb,\\n 55 | \\teBone_Aux_IndexFinger,\\n 56 | \\teBone_Aux_MiddleFinger,\\n 57 | \\teBone_Aux_RingFinger,\\n 58 | \\teBone_Aux_PinkyFinger,\\n 59 | \\teBone_Count\\n 60 | };\\n 61 | \\n 62 | class MyHandSimulation\\n 63 | {\\n 64 | public:\\n 65 | \\tvoid ComputeSkeletonTransforms( vr::ETrackedControllerRole role, const MyFingerCurls &curls, const MyFingerSplays &splays, vr::VRBoneTransform_t *out_transforms );\\n 66 | };\\n----\\n\\n# samples/drivers/drivers/handskeletonsimulation/src/hand_simulation.cpp\\n  1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\n  2 | // Inspired by Moshi Turner's code from Monado https://gitlab.freedesktop.org/monado/monado/-/blob/main/src/xrt/auxiliary/util/u_hand_simulation.c\\n  3 | #include \\\"hand_simulation.h\\\"\\n  4 | #include \\\"vrmath.h\\\"\\n  5 | \\n  6 | struct HandSimSplayableJoint\\n  7 | {\\n  8 | \\tvr::HmdVector2_t swing = { 0.f, 0.f };\\n  9 | \\tfloat twist = 0.f;\\n 10 | };\\n 11 | \\n 12 | struct HandSimJoint\\n 13 | {\\n 14 | \\tfloat rotation = 0.f;\\n 15 | };\\n 16 | \\n 17 | struct HandSimThumb\\n 18 | {\\n 19 | \\tHandSimSplayableJoint metacarpal;\\n 20 | \\tHandSimSplayableJoint proximal;\\n 21 | \\tHandSimJoint distal;\\n 22 | };\\n 23 | \\n 24 | struct HandSimFinger\\n 25 | {\\n 26 | \\tHandSimSplayableJoint metacarpal;\\n 27 | \\tHandSimSplayableJoint proximal;\\n 28 | \\tHandSimJoint intermediate;\\n 29 | \\tHandSimJoint distal;\\n 30 | };\\n 31 | \\n 32 | struct HandSimHand\\n 33 | {\\n 34 | \\tvr::ETrackedControllerRole role; // Whether we're left or right handed\\n 35 | \\n 36 | \\tHandSimThumb thumb;\\n 37 | \\n 38 | \\t// index, middle, ring, pinky (in that order)\\n 39 | \\tHandSimFinger fingers[4];\\n 40 | };\\n 41 | \\n 42 | // rough finger lengths\\n 43 | static const float finger_joint_lengths[5][5] = {\\n 44 | \\t{ 0.05f, 0.05f, 0.035f, 0.025f, 0.f },\\t  // thumb\\n 45 | \\t{ 0.03f, 0.073f, 0.045f, 0.025f, 0.02f }, // index\\n 46 | \\t{ 0.01f, 0.091f, 0.049f, 0.03f, 0.02f },  // middle\\n 47 | \\t{ 0.02f, 0.073f, 0.045f, 0.03f, 0.03f },  // ring\\n 48 | \\t{ 0.03f, 0.067f, 0.03f, 0.025f, 0.02f },  // pinky\\n 49 | };\\n 50 | \\n 51 | //-----------------------------------------------------------------------------\\n 52 | // Purpose: Sets up a default open hand pose which can then be manipulated with curl and splay values.\\n 53 | // Much of this is very approximate.\\n 54 | //-----------------------------------------------------------------------------\\n 55 | static void InitHand(HandSimHand& out_hand)\\n 56 | {\\n 57 | \\t// Default curls for each of the fingers\\n 58 | \\tfor (auto& finger : out_hand.fingers)\\n 59 | \\t{\\n 60 | \\t\\tfinger.metacarpal.swing.v[1] = 0.f;\\n 61 | \\t\\tfinger.metacarpal.twist = 0.f;\\n 62 | \\n 63 | \\t\\tfinger.proximal.swing.v[1] = DEG_TO_RAD(10);\\n 64 | \\t\\tfinger.intermediate.rotation = DEG_TO_RAD(5.f);\\n 65 | \\n 66 | \\t\\tfinger.intermediate.rotation = DEG_TO_RAD(5.f);\\n 67 | \\t\\tfinger.distal.rotation = DEG_TO_RAD(5.f);\\n 68 | \\t}\\n 69 | \\n 70 | \\t// Curl, splay and \\\"twist\\\" the thumb into a default position\\n 71 | \\tout_hand.thumb.metacarpal.swing.v[0] = DEG_TO_RAD(10);\\n 72 | \\tout_hand.thumb.metacarpal.swing.v[1] = DEG_TO_RAD(40);\\n 73 | \\tout_hand.thumb.metacarpal.twist = DEG_TO_RAD(70);\\n 74 | \\n 75 | \\tout_hand.thumb.proximal.swing.v[0] = 0.f;\\n 76 | \\tout_hand.thumb.proximal.swing.v[1] = 0.f;\\n 77 | \\tout_hand.thumb.proximal.twist = 0.f;\\n 78 | \\n 79 | \\tout_hand.thumb.distal.rotation = 0.f;\\n 80 | \\n 81 | \\t// Metacarpal splays for each of the fingers. Do this to add some spread to the fingers' metacarpal (the joints that connect to the wrist).\\n 82 | \\tout_hand.fingers[0].metacarpal.swing.v[1] = DEG_TO_RAD(13.f);\\n 83 | \\tout_hand.fingers[1].metacarpal.swing.v[1] = DEG_TO_RAD(-0.f);\\n 84 | \\tout_hand.fingers[2].metacarpal.swing.v[1] = DEG_TO_RAD(-15.f);\\n 85 | \\tout_hand.fingers[3].metacarpal.swing.v[1] = DEG_TO_RAD(-27.f);\\n 86 | \\n 87 | \\t// Proximal splays for each of the fingers. Do this to add some spread to the finger's proximal joints. These joints are also the ones that splay with the values provided.\\n 88 | \\tout_hand.fingers[0].proximal.swing.v[1] = DEG_TO_RAD(3.f);\\n 89 | \\tout_hand.fingers[1].proximal.swing.v[1] = DEG_TO_RAD(0.f);\\n 90 | \\tout_hand.fingers[2].proximal.swing.v[1] = DEG_TO_RAD(-1.f);\\n 91 | \\tout_hand.fingers[3].proximal.swing.v[1] = DEG_TO_RAD(-2.f);\\n 92 | }\\n 93 | \\n 94 | //-----------------------------------------------------------------------------\\n 95 | // Purpose: All fingers (expect thumb) have basically the same properties in terms of curl and splay.\\n 96 | // You can splay only the proximal, and curl the proximal, intermediate and distal joints.\\n 97 | // This applies the curl and splay to these joints.\\n 98 | //-----------------------------------------------------------------------------\\n 99 | static void ApplyGenericFingerTransform(const float curl, const float splay, HandSimFinger& out_finger)\\n100 | {\\n101 | \\tout_finger.metacarpal.swing.v[0] += DEG_TO_RAD(curl * 5.f); // the metacarpal only curls a little\\n102 | \\n103 | \\tout_finger.proximal.swing.v[0] += DEG_TO_RAD(curl * 90.f);\\n104 | \\tout_finger.proximal.swing.v[1] += DEG_TO_RAD(splay * 15.f);\\n105 | \\n106 | \\tout_finger.intermediate.rotation += DEG_TO_RAD(curl * 80.f);\\n107 | \\tout_finger.distal.rotation += DEG_TO_RAD(curl * 80.f);\\n108 | }\\n109 | \\n110 | \\n111 | //-----------------------------------------------------------------------------\\n112 | // Purpose: Takes an orientation and length of a joint and converts it to a vr::VRBoneTransform_t\\n113 | // We have to do convert the quaternion as we use vr::HmdQuaternion_t for our representation, but OpenVR wants vr::HmdQuaternionf_t\\n114 | //-----------------------------------------------------------------------------\\n115 | static void ComputeBoneTransform(const vr::ETrackedControllerRole role, const vr::HmdQuaternion_t& orientation, const vr::HmdVector3_t& position, vr::VRBoneTransform_t& out_transform)\\n116 | {\\n117 | \\t// Note that we use vr::HmdQuaternion_t but the Skeletal Input API needs vr::HmdQuaternionf_t, so we'll use this helper to convert\\n118 | \\tHmdQuaternion_ConvertQuaternion(orientation, out_transform.orientation);\\n119 | \\n120 | \\t// Fit the HmdVector3_t into the HmdVector4_t that the Skeletal Input API accepts\\n121 | \\tHmdVector3_CovertVector(position, out_transform.position);\\n122 | \\tout_transform.position.v[3] = 1.f;\\n123 | \\n124 | \\t//\\\"up\\\" axis is flipped between hands, so inverse the joint length for the right hand, as we base all our computations of the left skeleton pose.\\n125 | \\tif (role == vr::TrackedControllerRole_RightHand)\\n126 | \\t{\\n127 | \\t\\tout_transform.position.v[0] *= -1.f;\\n128 | \\t}\\n129 | }\\n130 | \\n131 | \\n132 | //-----------------------------------------------------------------------------\\n133 | // Purpose: This is just a little helper function to make our calls when trying to compute each bone a little simpler by specifying just a float for joint length, instead of the whole vector\\n134 | //-----------------------------------------------------------------------------\\n135 | static void ComputeBoneTransform(const vr::ETrackedControllerRole role, const vr::HmdQuaternion_t& orientation, const float joint_length, vr::VRBoneTransform_t& out_transform)\\n136 | {\\n137 | \\tComputeBoneTransform(role, orientation, { joint_length, 0.f, 0.f }, out_transform);\\n138 | }\\n139 | \\n140 | //-----------------------------------------------------------------------------\\n141 | // Purpose: Takes an orientation and length of a joint and converts it to a vr::VRBoneTransform_t, but with the orientation applied to the offset\\n142 | // We have to do convert the quaternion as we use vr::HmdQuaternion_t for our representation, but OpenVR wants vr::HmdQuaternionf_t\\n143 | //-----------------------------------------------------------------------------\\n144 | static void ComputeBoneTransformMetacarpal(const vr::ETrackedControllerRole role, const vr::HmdQuaternion_t& orientation, const float joint_length, vr::VRBoneTransform_t& out_transform)\\n145 | {\\n146 | \\tconst vr::HmdVector3_t offset = { joint_length, 0.f, 0.f };\\n147 | \\n148 | \\t/*\\n149 | \\tThe Skeletal Input API is designed to be used with common industry tools, such as Maya, to make it easier to move content from 3D editors into VR.\\n150 | \\tThe way that FBX handles conversion to a different coordinate system is to transform the root bone (wrist), then counter-transform the root's children to account for the root's change, but then\\n151 | \\tleave the local coordinate systems of the remaining bones as-is This means that the metacarpals will be rotated 90 degrees from the wrist if trying to build a skeleton programmatically. So, we\\n152 | \\tapply this extra rotation to the metacarpals to account for this.\\n153 | \\t*/\\n154 | \\tvr::HmdQuaternion_t magic = { 0.5f, 0.5f, -0.5f, 0.5f };\\n155 | \\n156 | \\tvr::HmdQuaternion_t bone_orientation = magic * orientation;\\n157 | \\n158 | \\t// Rotate the offset vector by the orientation\\n159 | \\tvr::HmdVector3_t bone_position = offset * bone_orientation;\\n160 | \\n161 | \\t//\\\"up\\\" axis is flipped between hands, so we need to inverse the x and y axis for the right hand, as all our calculations are based on the left hand currently.\\n162 | \\tif (role == vr::TrackedControllerRole_RightHand)\\n163 | \\t{\\n164 | \\t\\tstd::swap(bone_orientation.w, bone_orientation.x);\\n165 | \\t\\tstd::swap(bone_orientation.y, bone_orientation.z);\\n166 | \\n167 | \\t\\tbone_orientation.x *= -1.f;\\n168 | \\t\\tbone_orientation.z *= -1.f;\\n169 | \\t}\\n170 | \\n171 | \\t// pass off to put the position and orientation we've calculated into the skeleton\\n172 | \\tComputeBoneTransform(role, bone_orientation, bone_position, out_transform);\\n173 | }\\n174 | \\n175 | //-----------------------------------------------------------------------------\\n176 | // Purpose: Get the OpenVR bone index from a finger (index=0, middle=1...) and the bone position in the finger. Used in ComputeSkeletalTransforms\\n177 | //-----------------------------------------------------------------------------\\n178 | static int CalculateBoneTransformPositionFromFinger(int finger, int bone_in_finger)\\n179 | {\\n180 | \\tconst int bone_transform_finger_start_offset = eBone_IndexFinger0;\\n181 | \\n182 | \\tconst int result = bone_transform_finger_start_offset + finger * 5 + bone_in_finger;\\n183 | \\n184 | \\treturn result;\\n185 | }\\n186 | \\n187 | //-----------------------------------------------------------------------------\\n188 | // Purpose: Given the curls and splays, convert this to a vr::VRBoneTransform_t array\\n189 | //-----------------------------------------------------------------------------\\n190 | static void ComputeSkeletalTransforms(const HandSimHand& hand, vr::VRBoneTransform_t* out_transforms)\\n191 | {\\n192 | \\t// Do the thumb separately as it's special and not like the other fingers\\n193 | \\tComputeBoneTransformMetacarpal(\\n194 | \\t\\thand.role, HmdQuaternion_FromSwingTwist(hand.thumb.metacarpal.swing, hand.thumb.metacarpal.twist), finger_joint_lengths[0][0], out_transforms[eBone_Thumb0]);\\n195 | \\tComputeBoneTransform(hand.role, HmdQuaternion_FromSwingTwist(hand.thumb.proximal.swing, hand.thumb.metacarpal.twist), finger_joint_lengths[0][1], out_transforms[eBone_Thumb1]);\\n196 | \\tComputeBoneTransform(hand.role, HmdQuaternion_FromEulerAngles(hand.thumb.distal.rotation, 0.f, 0.f), finger_joint_lengths[0][2], out_transforms[eBone_Thumb2]);\\n197 | \\tComputeBoneTransform(hand.role, HmdQuaternion_Identity, finger_joint_lengths[0][3], out_transforms[eBone_Thumb3]);\\n198 | \\n199 | \\t// index, middle, ring, pinky\\n200 | \\t// We can do these all together as they all require the same calculations\\n201 | \\tfor (int finger = 0; finger < 4; finger++)\\n202 | \\t{\\n203 | \\t\\tComputeBoneTransformMetacarpal(hand.role, HmdQuaternion_FromSwingTwist(hand.fingers[finger].metacarpal.swing, hand.fingers[finger].metacarpal.twist),\\n204 | \\t\\t\\tfinger_joint_lengths[finger + 1][0], out_transforms[CalculateBoneTransformPositionFromFinger(finger, 0)]);\\n205 | \\n206 | \\t\\tComputeBoneTransform(hand.role, HmdQuaternion_FromSwingTwist(hand.fingers[finger].proximal.swing, hand.fingers[finger].proximal.twist), finger_joint_lengths[finger + 1][1],\\n207 | \\t\\t\\tout_transforms[CalculateBoneTransformPositionFromFinger(finger, 1)]);\\n208 | \\n209 | \\t\\tComputeBoneTransform(hand.role, HmdQuaternion_FromEulerAngles(hand.fingers[finger].intermediate.rotation, 0.f, 0.f), finger_joint_lengths[finger + 1][2],\\n210 | \\t\\t\\tout_transforms[CalculateBoneTransformPositionFromFinger(finger, 2)]);\\n211 | \\n212 | \\t\\tComputeBoneTransform(hand.role, HmdQuaternion_FromEulerAngles(hand.fingers[finger].distal.rotation, 0.f, 0.f), finger_joint_lengths[finger + 1][3],\\n213 | \\t\\t\\tout_transforms[CalculateBoneTransformPositionFromFinger(finger, 3)]);\\n214 | \\n215 | \\t\\tComputeBoneTransform(hand.role, HmdQuaternion_Identity, finger_joint_lengths[finger + 1][4], out_transforms[CalculateBoneTransformPositionFromFinger(finger, 4)]);\\n216 | \\t}\\n217 | }\\n218 | \\n219 | void MyHandSimulation::ComputeSkeletonTransforms(vr::ETrackedControllerRole role, const MyFingerCurls& curls, const MyFingerSplays& splays, vr::VRBoneTransform_t* out_transforms)\\n220 | {\\n221 | \\t// This is where we store our internal representation of curls and splays for the hand.\\n222 | \\tHandSimHand hand{};\\n223 | \\n224 | \\t// Set the handed-ness of the current skeleton (left or right hand)\\n225 | \\thand.role = role;\\n226 | \\n227 | \\t// root bone. This is just 0s. It's aligned to /pose/raw.\\n228 | \\tout_transforms[0] = { { 0.000000f, 0.000000f, 0.000000f, 1.000000f }, { 1.000000f, -0.000000f, -0.000000f, 0.000000f } };\\n229 | \\n230 | \\t// wrist bone. This was taken from the index controller pose.\\n231 | \\n232 | \\tout_transforms[1] = { { -0.034038f, 0.036503f, 0.164722f, 1.000000f }, { -0.055147f, -0.078608f, -0.920279f, 0.379296f } };\\n233 | \\n234 | \\t//\\\"up\\\" axis is flipped between hands so invert\\n235 | \\tif (role == vr::TrackedControllerRole_RightHand)\\n236 | \\t{\\n237 | \\t\\tout_transforms[1].position.v[0] *= -1.f;\\n238 | \\n239 | \\t\\tout_transforms[1].orientation.y *= -1.f;\\n240 | \\t\\tout_transforms[1].orientation.z *= -1.f;\\n241 | \\t}\\n242 | \\n243 | \\t// Initialize a default hand pose\\n244 | \\tInitHand(hand);\\n245 | \\n246 | \\t// We need to apply the curls and splays separately to the thumb as it's special\\n247 | \\thand.thumb.metacarpal.swing.v[0] += DEG_TO_RAD(curls.thumb * 5.f);\\n248 | \\thand.thumb.metacarpal.swing.v[1] += DEG_TO_RAD(splays.thumb * 5.f);\\n249 | \\thand.thumb.metacarpal.twist = 0.f;\\n250 | \\n251 | \\thand.thumb.proximal.swing.v[0] += DEG_TO_RAD(curls.thumb * 90.f);\\n252 | \\thand.thumb.proximal.swing.v[1] += DEG_TO_RAD(splays.thumb * 20.f);\\n253 | \\thand.thumb.proximal.twist = 0.f;\\n254 | \\n255 | \\thand.thumb.distal.rotation += DEG_TO_RAD(curls.thumb * 90.f);\\n256 | \\n257 | \\t// But we can batch up the fingers with a generic apply function.\\n258 | \\tApplyGenericFingerTransform(curls.index, splays.index, hand.fingers[0]);\\n259 | \\tApplyGenericFingerTransform(curls.middle, splays.middle, hand.fingers[1]);\\n260 | \\tApplyGenericFingerTransform(curls.ring, splays.ring, hand.fingers[2]);\\n261 | \\tApplyGenericFingerTransform(curls.pinky, splays.pinky, hand.fingers[3]);\\n262 | \\n263 | \\t// Now compute\\n264 | \\tComputeSkeletalTransforms(hand, out_transforms);\\n265 | }\\n----\"}","partial":false},{"ts":1744500940511,"type":"say","say":"api_req_started","text":"{\"request\":\"[search_files for '.*'] Result:\\n\\nFound 11 results.\\n\\n# samples/drivers/vs-openvr_samples.sln\\n  1 | \\n  2 | Microsoft Visual Studio Solution File, Format Version 12.00\\n  3 | # Visual Studio Version 16\\n  4 | VisualStudioVersion = 16.0.33214.272\\n  5 | MinimumVisualStudioVersion = 10.0.40219.1\\n  6 | Project(\\\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\\") = \\\"util_driverlog\\\", \\\"utils\\\\driverlog\\\\util_driverlog.vcxproj\\\", \\\"{89689A91-FB38-4893-BA67-3D6F45EB2712}\\\"\\n  7 | EndProject\\n  8 | Project(\\\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\\") = \\\"util_vrmath\\\", \\\"utils\\\\vrmath\\\\util_vrmath.vcxproj\\\", \\\"{AC31972F-E424-4C19-86EB-7BCF1E9F8460}\\\"\\n  9 | EndProject\\n 10 | Project(\\\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\\") = \\\"barebones\\\", \\\"drivers\\\\barebones\\\\barebones.vcxproj\\\", \\\"{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}\\\"\\n 11 | EndProject\\n 12 | Project(\\\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\\") = \\\"simplecontroller\\\", \\\"drivers\\\\simplecontroller\\\\simplecontroller.vcxproj\\\", \\\"{13391803-5E60-4BED-9B54-F9004412E16C}\\\"\\n 13 | EndProject\\n 14 | Project(\\\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\\") = \\\"simplehmd\\\", \\\"drivers\\\\simplehmd\\\\simplehmd.vcxproj\\\", \\\"{1A008D17-0760-4179-8D42-995C5FF1C8D6}\\\"\\n 15 | EndProject\\n 16 | Project(\\\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\\") = \\\"handskeletonsimulation\\\", \\\"drivers\\\\handskeletonsimulation\\\\handskeletonsimulation.vcxproj\\\", \\\"{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}\\\"\\n 17 | EndProject\\n 18 | Project(\\\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\\\") = \\\"simpletrackers\\\", \\\"drivers\\\\simpletrackers\\\\simpletrackers.vcxproj\\\", \\\"{F6FB2D3A-6B65-403D-8F4E-24AA16527098}\\\"\\n 19 | EndProject\\n 20 | Global\\n 21 | \\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\\n 22 | \\t\\tDebug|x64 = Debug|x64\\n 23 | \\t\\tDebug|x86 = Debug|x86\\n 24 | \\t\\tRelease|x64 = Release|x64\\n 25 | \\t\\tRelease|x86 = Release|x86\\n 26 | \\tEndGlobalSection\\n 27 | \\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\\n 28 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Debug|x64.ActiveCfg = Debug|x64\\n 29 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Debug|x64.Build.0 = Debug|x64\\n 30 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Debug|x86.ActiveCfg = Debug|Win32\\n 31 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Debug|x86.Build.0 = Debug|Win32\\n 32 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Release|x64.ActiveCfg = Release|x64\\n 33 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Release|x64.Build.0 = Release|x64\\n 34 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Release|x86.ActiveCfg = Release|Win32\\n 35 | \\t\\t{89689A91-FB38-4893-BA67-3D6F45EB2712}.Release|x86.Build.0 = Release|Win32\\n 36 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Debug|x64.ActiveCfg = Debug|x64\\n 37 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Debug|x64.Build.0 = Debug|x64\\n 38 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Debug|x86.ActiveCfg = Debug|Win32\\n 39 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Debug|x86.Build.0 = Debug|Win32\\n 40 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Release|x64.ActiveCfg = Release|x64\\n 41 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Release|x64.Build.0 = Release|x64\\n 42 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Release|x86.ActiveCfg = Release|Win32\\n 43 | \\t\\t{AC31972F-E424-4C19-86EB-7BCF1E9F8460}.Release|x86.Build.0 = Release|Win32\\n 44 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Debug|x64.ActiveCfg = Debug|x64\\n 45 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Debug|x64.Build.0 = Debug|x64\\n 46 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Debug|x86.ActiveCfg = Debug|Win32\\n 47 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Debug|x86.Build.0 = Debug|Win32\\n 48 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Release|x64.ActiveCfg = Release|x64\\n 49 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Release|x64.Build.0 = Release|x64\\n 50 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Release|x86.ActiveCfg = Release|Win32\\n 51 | \\t\\t{D0D5AEFD-71C3-4DB8-8642-D7580E326B1F}.Release|x86.Build.0 = Release|Win32\\n 52 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Debug|x64.ActiveCfg = Debug|x64\\n 53 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Debug|x64.Build.0 = Debug|x64\\n 54 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Debug|x86.ActiveCfg = Debug|Win32\\n 55 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Debug|x86.Build.0 = Debug|Win32\\n 56 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Release|x64.ActiveCfg = Release|x64\\n 57 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Release|x64.Build.0 = Release|x64\\n 58 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Release|x86.ActiveCfg = Release|Win32\\n 59 | \\t\\t{13391803-5E60-4BED-9B54-F9004412E16C}.Release|x86.Build.0 = Release|Win32\\n 60 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Debug|x64.ActiveCfg = Debug|x64\\n 61 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Debug|x64.Build.0 = Debug|x64\\n 62 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Debug|x86.ActiveCfg = Debug|Win32\\n 63 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Debug|x86.Build.0 = Debug|Win32\\n 64 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Release|x64.ActiveCfg = Release|x64\\n 65 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Release|x64.Build.0 = Release|x64\\n 66 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Release|x86.ActiveCfg = Release|Win32\\n 67 | \\t\\t{1A008D17-0760-4179-8D42-995C5FF1C8D6}.Release|x86.Build.0 = Release|Win32\\n 68 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Debug|x64.ActiveCfg = Debug|x64\\n 69 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Debug|x64.Build.0 = Debug|x64\\n 70 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Debug|x86.ActiveCfg = Debug|Win32\\n 71 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Debug|x86.Build.0 = Debug|Win32\\n 72 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Release|x64.ActiveCfg = Release|x64\\n 73 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Release|x64.Build.0 = Release|x64\\n 74 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Release|x86.ActiveCfg = Release|Win32\\n 75 | \\t\\t{D98CC267-D810-4D5E-B7E6-AAF9D8CA4C3A}.Release|x86.Build.0 = Release|Win32\\n 76 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Debug|x64.ActiveCfg = Debug|x64\\n 77 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Debug|x64.Build.0 = Debug|x64\\n 78 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Debug|x86.ActiveCfg = Debug|Win32\\n 79 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Debug|x86.Build.0 = Debug|Win32\\n 80 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Release|x64.ActiveCfg = Release|x64\\n 81 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Release|x64.Build.0 = Release|x64\\n 82 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Release|x86.ActiveCfg = Release|Win32\\n 83 | \\t\\t{F6FB2D3A-6B65-403D-8F4E-24AA16527098}.Release|x86.Build.0 = Release|Win32\\n 84 | \\tEndGlobalSection\\n 85 | \\tGlobalSection(SolutionProperties) = preSolution\\n 86 | \\t\\tHideSolutionNode = FALSE\\n 87 | \\tEndGlobalSection\\n 88 | \\tGlobalSection(ExtensibilityGlobals) = postSolution\\n 89 | \\t\\tSolutionGuid = {1085EFDE-F216-4EF1-BB18-106228E5D0DA}\\n 90 | \\tEndGlobalSection\\n 91 | EndGlobal\\n----\\n\\n# samples/drivers/drivers/CMakeLists.txt\\n  1 | add_subdirectory(barebones)\\n  2 | add_subdirectory(handskeletonsimulation)\\n  3 | add_subdirectory(simplecontroller)\\n  4 | add_subdirectory(simplehmd)\\n  5 | add_subdirectory(simpletrackers)\\n----\\n\\n# samples/drivers/README.md\\n  1 | # OpenVR Driver Samples\\n  2 | \\n  3 | ## CMake\\n  4 | \\n  5 | The `CMakeLists.txt` found in this folder shows how to link OpenVR libraries.\\n  6 | \\n  7 | These are added to the targets in each sample.\\n  8 | \\n  9 | ## Samples\\n 10 | \\n 11 | `drivers/` - driver samples. See `drivers/` for information on each of the drivers.\\n 12 | \\n 13 | * `barebones`\\n 14 | * `handskeletonsimulation`\\n 15 | * `simplecontroller`\\n 16 | \\n 17 | `utils/` - utility samples, that can be copied to your own project for ease of development.\\n 18 | \\n 19 | * `driverlog`\\n 20 | * `vrmath`\\n 21 | \\n 22 | ## Building\\n 23 | \\n 24 | There are two options that can be used to build the samples: [CMake](#building-with-cmake)\\n 25 | or [Visual Studio](#building-with-visual-studio).\\n 26 | \\n 27 | This directory contains both a CMakeLists.txt file which can be used to create a Visual Studio solution, or you can use\\n 28 | the Visual Studio solution provided in this directory.\\n 29 | \\n 30 | ### Building with CMake\\n 31 | \\n 32 | To create a solution for the samples, run (in this directory):\\n 33 | \\n 34 | * `cmake -A x64 -B build`\\n 35 | * Navigate into `build/` and open the solution.\\n 36 | * Build the project.\\n 37 | \\n 38 | ### Building with Visual Studio\\n 39 | \\n 40 | Open the `vs-openvr_samples.sln` file in Visual Studio (2019 or 2022).\\n 41 | \\n 42 | Build the project by pressing `Ctrl + Shift + B`.\\n 43 | \\n 44 | ## Build Artifacts\\n 45 | \\n 46 | Building with either CMake or Visual Studio will output the build artifacts to the `output/` directory.\\n 47 | \\n 48 | See `drivers/` for more documentation on linking the drivers to SteamVR.\\n 49 | \\n 50 | Building the project will output the driver binary to `output/drivers/<driver_name>/bin/win64/driver_<driver_name>.dll`\\n----\\n\\n# samples/drivers/drivers/barebones/CMakeLists.txt\\n  1 | set(TARGET_NAME barebones)\\n  2 | \\n  3 | # This is the name of the driver according to SteamVR\\n  4 | set(DRIVER_NAME \\\"driver_${TARGET_NAME}\\\")\\n  5 | \\n  6 | project(${TARGET_NAME})\\n  7 | \\n  8 | add_library(${DRIVER_NAME} SHARED\\n  9 | \\tsrc/hmd_driver_factory.cpp\\n 10 | \\tsrc/device_provider.h\\n 11 | \\tsrc/device_provider.cpp\\n 12 | )\\n 13 | \\n 14 | # This is so we can build directly to \\\"<binary_dir>/<target_name>/<platform>/<arch>/<driver_name>.<dll/so>\\\"\\n 15 | set_target_properties(${DRIVER_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY $<1:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET_NAME}/bin/${ARCH_TARGET}>)\\n 16 | \\n 17 | target_link_libraries(${DRIVER_NAME} PRIVATE ${OPENVR_LIBRARIES} util_driverlog)\\n 18 | target_include_directories(${DRIVER_NAME} PRIVATE ${OPENVR_INCLUDE_DIR})\\n 19 | \\n 20 | # Copy driver assets to output folder\\n 21 | add_custom_command(\\n 22 |         TARGET ${DRIVER_NAME}\\n 23 |         PRE_BUILD\\n 24 |         COMMAND ${CMAKE_COMMAND} -E copy_directory\\n 25 |         ${CMAKE_CURRENT_SOURCE_DIR}/${TARGET_NAME}\\n 26 |         ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET_NAME}\\n 27 | )\\n----\\n\\n# samples/drivers/utils/vrmath/CMakeLists.txt\\n  1 | add_library(util_vrmath INTERFACE vrmath.h)\\n  2 | target_include_directories(util_vrmath INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})\\n  3 | \\n  4 | target_link_libraries(util_vrmath INTERFACE ${OPENVR_LIBRARIES})\\n  5 | target_include_directories(util_vrmath INTERFACE ${OPENVR_INCLUDE_DIR})\\n----\\n\\n# samples/drivers/utils/driverlog/driverlog.h\\n  1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\n  2 | #pragma once\\n  3 | \\n  4 | #include <string>\\n  5 | #include <openvr_driver.h>\\n  6 | \\n  7 | extern void DriverLog( const char *pchFormat, ... );\\n  8 | \\n  9 | extern void DebugDriverLog( const char *pchFormat, ... );\\n----\\n\\n# samples/drivers/utils/driverlog/driverlog.cpp\\n  1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\n  2 | #include \\\"driverlog.h\\\"\\n  3 | \\n  4 | #include <stdarg.h>\\n  5 | #include <stdio.h>\\n  6 | \\n  7 | #if !defined( WIN32 )\\n  8 | #define vsnprintf_s vsnprintf\\n  9 | #endif\\n 10 | \\n 11 | static void DriverLogVarArgs( const char *pMsgFormat, va_list args )\\n 12 | {\\n 13 | \\tchar buf[ 1024 ];\\n 14 | \\tvsnprintf_s( buf, sizeof( buf ), pMsgFormat, args );\\n 15 | \\n 16 | \\tvr::VRDriverLog()->Log( buf );\\n 17 | }\\n 18 | \\n 19 | \\n 20 | void DriverLog( const char *pMsgFormat, ... )\\n 21 | {\\n 22 | \\tva_list args;\\n 23 | \\tva_start( args, pMsgFormat );\\n 24 | \\n 25 | \\tDriverLogVarArgs( pMsgFormat, args );\\n 26 | \\n 27 | \\tva_end( args );\\n 28 | }\\n 29 | \\n 30 | \\n 31 | void DebugDriverLog( const char *pMsgFormat, ... )\\n 32 | {\\n 33 | #ifdef _DEBUG\\n 34 | \\tva_list args;\\n 35 | \\tva_start( args, pMsgFormat );\\n 36 | \\n 37 | \\tDriverLogVarArgs( pMsgFormat, args );\\n 38 | \\n 39 | \\tva_end( args );\\n 40 | #endif\\n 41 | }\\n----\\n\\n# samples/drivers/utils/driverlog/CMakeLists.txt\\n  1 | add_library(util_driverlog STATIC driverlog.h driverlog.cpp)\\n  2 | target_include_directories(util_driverlog PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})\\n  3 | \\n  4 | target_link_libraries(util_driverlog PRIVATE ${OPENVR_LIBRARIES})\\n  5 | target_include_directories(util_driverlog PUBLIC ${OPENVR_INCLUDE_DIR})\\n----\\n\\n# samples/drivers/drivers/handskeletonsimulation/src/hmd_driver_factory.cpp\\n  1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\n  2 | #include \\\"device_provider.h\\\"\\n  3 | #include \\\"openvr_driver.h\\\"\\n  4 | #include <cstring>\\n  5 | \\n  6 | #if defined( _WIN32 )\\n  7 | #define HMD_DLL_EXPORT extern \\\"C\\\" __declspec( dllexport )\\n  8 | #define HMD_DLL_IMPORT extern \\\"C\\\" __declspec( dllimport )\\n  9 | #elif defined( __GNUC__ ) || defined( COMPILER_GCC ) || defined( __APPLE__ )\\n 10 | #define HMD_DLL_EXPORT extern \\\"C\\\" __attribute__( ( visibility( \\\"default\\\" ) ) )\\n 11 | #define HMD_DLL_IMPORT extern \\\"C\\\"\\n 12 | #else\\n 13 | #error \\\"Unsupported Platform.\\\"\\n 14 | #endif\\n 15 | \\n 16 | MyDeviceProvider device_provider;\\n 17 | \\n 18 | //-----------------------------------------------------------------------------\\n 19 | // Purpose: This is exported from the shared library to be called as the entry point into the driver by vrserver.\\n 20 | // You should return a point to your IServerTrackedDeviceProvider here, as well as optionally a watchdog (see other\\n 21 | // samples).\\n 22 | //-----------------------------------------------------------------------------\\n 23 | HMD_DLL_EXPORT void *HmdDriverFactory( const char *pInterfaceName, int *pReturnCode )\\n 24 | {\\n 25 | \\t// This is where we return our device provider, if the HmdDriverFactory call asks for it.\\n 26 | \\tif ( 0 == strcmp( vr::IServerTrackedDeviceProvider_Version, pInterfaceName ) )\\n 27 | \\t{\\n 28 | \\t\\treturn &device_provider;\\n 29 | \\t}\\n 30 | \\n 31 | \\t// Otherwise tell the runtime that we don't have this interface.\\n 32 | \\tif ( pReturnCode )\\n 33 | \\t\\t*pReturnCode = vr::VRInitError_Init_InterfaceNotFound;\\n 34 | \\n 35 | \\treturn NULL;\\n 36 | }\\n----\\n\\n# samples/drivers/drivers/handskeletonsimulation/src/hand_simulation.h\\n  1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\n  2 | #pragma once\\n  3 | \\n  4 | #include \\\"openvr_driver.h\\\"\\n  5 | \\n  6 | // 0-1 values (1 fully curled)\\n  7 | struct MyFingerCurls\\n  8 | {\\n  9 | \\tfloat thumb;\\n 10 | \\tfloat index;\\n 11 | \\tfloat middle;\\n 12 | \\tfloat ring;\\n 13 | \\tfloat pinky;\\n 14 | };\\n 15 | \\n 16 | //-1-1 values (1 fully to the left)\\n 17 | struct MyFingerSplays\\n 18 | {\\n 19 | \\tfloat thumb;\\n 20 | \\tfloat index;\\n 21 | \\tfloat middle;\\n 22 | \\tfloat ring;\\n 23 | \\tfloat pinky;\\n 24 | };\\n 25 | \\n 26 | enum HandSkeletonBone : vr::BoneIndex_t\\n 27 | {\\n 28 | \\teBone_Root = 0,\\n 29 | \\teBone_Wrist,\\n 30 | \\teBone_Thumb0,\\n 31 | \\teBone_Thumb1,\\n 32 | \\teBone_Thumb2,\\n 33 | \\teBone_Thumb3,\\n 34 | \\teBone_IndexFinger0,\\n 35 | \\teBone_IndexFinger1,\\n 36 | \\teBone_IndexFinger2,\\n 37 | \\teBone_IndexFinger3,\\n 38 | \\teBone_IndexFinger4,\\n 39 | \\teBone_MiddleFinger0,\\n 40 | \\teBone_MiddleFinger1,\\n 41 | \\teBone_MiddleFinger2,\\n 42 | \\teBone_MiddleFinger3,\\n 43 | \\teBone_MiddleFinger4,\\n 44 | \\teBone_RingFinger0,\\n 45 | \\teBone_RingFinger1,\\n 46 | \\teBone_RingFinger2,\\n 47 | \\teBone_RingFinger3,\\n 48 | \\teBone_RingFinger4,\\n 49 | \\teBone_PinkyFinger0,\\n 50 | \\teBone_PinkyFinger1,\\n 51 | \\teBone_PinkyFinger2,\\n 52 | \\teBone_PinkyFinger3,\\n 53 | \\teBone_PinkyFinger4,\\n 54 | \\teBone_Aux_Thumb,\\n 55 | \\teBone_Aux_IndexFinger,\\n 56 | \\teBone_Aux_MiddleFinger,\\n 57 | \\teBone_Aux_RingFinger,\\n 58 | \\teBone_Aux_PinkyFinger,\\n 59 | \\teBone_Count\\n 60 | };\\n 61 | \\n 62 | class MyHandSimulation\\n 63 | {\\n 64 | public:\\n 65 | \\tvoid ComputeSkeletonTransforms( vr::ETrackedControllerRole role, const MyFingerCurls &curls, const MyFingerSplays &splays, vr::VRBoneTransform_t *out_transforms );\\n 66 | };\\n----\\n\\n# samples/drivers/drivers/handskeletonsimulation/src/hand_simulation.cpp\\n  1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\n  2 | // Inspired by Moshi Turner's code from Monado https://gitlab.freedesktop.org/monado/monado/-/blob/main/src/xrt/auxiliary/util/u_hand_simulation.c\\n  3 | #include \\\"hand_simulation.h\\\"\\n  4 | #include \\\"vrmath.h\\\"\\n  5 | \\n  6 | struct HandSimSplayableJoint\\n  7 | {\\n  8 | \\tvr::HmdVector2_t swing = { 0.f, 0.f };\\n  9 | \\tfloat twist = 0.f;\\n 10 | };\\n 11 | \\n 12 | struct HandSimJoint\\n 13 | {\\n 14 | \\tfloat rotation = 0.f;\\n 15 | };\\n 16 | \\n 17 | struct HandSimThumb\\n 18 | {\\n 19 | \\tHandSimSplayableJoint metacarpal;\\n 20 | \\tHandSimSplayableJoint proximal;\\n 21 | \\tHandSimJoint distal;\\n 22 | };\\n 23 | \\n 24 | struct HandSimFinger\\n 25 | {\\n 26 | \\tHandSimSplayableJoint metacarpal;\\n 27 | \\tHandSimSplayableJoint proximal;\\n 28 | \\tHandSimJoint intermediate;\\n 29 | \\tHandSimJoint distal;\\n 30 | };\\n 31 | \\n 32 | struct HandSimHand\\n 33 | {\\n 34 | \\tvr::ETrackedControllerRole role; // Whether we're left or right handed\\n 35 | \\n 36 | \\tHandSimThumb thumb;\\n 37 | \\n 38 | \\t// index, middle, ring, pinky (in that order)\\n 39 | \\tHandSimFinger fingers[4];\\n 40 | };\\n 41 | \\n 42 | // rough finger lengths\\n 43 | static const float finger_joint_lengths[5][5] = {\\n 44 | \\t{ 0.05f, 0.05f, 0.035f, 0.025f, 0.f },\\t  // thumb\\n 45 | \\t{ 0.03f, 0.073f, 0.045f, 0.025f, 0.02f }, // index\\n 46 | \\t{ 0.01f, 0.091f, 0.049f, 0.03f, 0.02f },  // middle\\n 47 | \\t{ 0.02f, 0.073f, 0.045f, 0.03f, 0.03f },  // ring\\n 48 | \\t{ 0.03f, 0.067f, 0.03f, 0.025f, 0.02f },  // pinky\\n 49 | };\\n 50 | \\n 51 | //-----------------------------------------------------------------------------\\n 52 | // Purpose: Sets up a default open hand pose which can then be manipulated with curl and splay values.\\n 53 | // Much of this is very approximate.\\n 54 | //-----------------------------------------------------------------------------\\n 55 | static void InitHand(HandSimHand& out_hand)\\n 56 | {\\n 57 | \\t// Default curls for each of the fingers\\n 58 | \\tfor (auto& finger : out_hand.fingers)\\n 59 | \\t{\\n 60 | \\t\\tfinger.metacarpal.swing.v[1] = 0.f;\\n 61 | \\t\\tfinger.metacarpal.twist = 0.f;\\n 62 | \\n 63 | \\t\\tfinger.proximal.swing.v[1] = DEG_TO_RAD(10);\\n 64 | \\t\\tfinger.intermediate.rotation = DEG_TO_RAD(5.f);\\n 65 | \\n 66 | \\t\\tfinger.intermediate.rotation = DEG_TO_RAD(5.f);\\n 67 | \\t\\tfinger.distal.rotation = DEG_TO_RAD(5.f);\\n 68 | \\t}\\n 69 | \\n 70 | \\t// Curl, splay and \\\"twist\\\" the thumb into a default position\\n 71 | \\tout_hand.thumb.metacarpal.swing.v[0] = DEG_TO_RAD(10);\\n 72 | \\tout_hand.thumb.metacarpal.swing.v[1] = DEG_TO_RAD(40);\\n 73 | \\tout_hand.thumb.metacarpal.twist = DEG_TO_RAD(70);\\n 74 | \\n 75 | \\tout_hand.thumb.proximal.swing.v[0] = 0.f;\\n 76 | \\tout_hand.thumb.proximal.swing.v[1] = 0.f;\\n 77 | \\tout_hand.thumb.proximal.twist = 0.f;\\n 78 | \\n 79 | \\tout_hand.thumb.distal.rotation = 0.f;\\n 80 | \\n 81 | \\t// Metacarpal splays for each of the fingers. Do this to add some spread to the fingers' metacarpal (the joints that connect to the wrist).\\n 82 | \\tout_hand.fingers[0].metacarpal.swing.v[1] = DEG_TO_RAD(13.f);\\n 83 | \\tout_hand.fingers[1].metacarpal.swing.v[1] = DEG_TO_RAD(-0.f);\\n 84 | \\tout_hand.fingers[2].metacarpal.swing.v[1] = DEG_TO_RAD(-15.f);\\n 85 | \\tout_hand.fingers[3].metacarpal.swing.v[1] = DEG_TO_RAD(-27.f);\\n 86 | \\n 87 | \\t// Proximal splays for each of the fingers. Do this to add some spread to the finger's proximal joints. These joints are also the ones that splay with the values provided.\\n 88 | \\tout_hand.fingers[0].proximal.swing.v[1] = DEG_TO_RAD(3.f);\\n 89 | \\tout_hand.fingers[1].proximal.swing.v[1] = DEG_TO_RAD(0.f);\\n 90 | \\tout_hand.fingers[2].proximal.swing.v[1] = DEG_TO_RAD(-1.f);\\n 91 | \\tout_hand.fingers[3].proximal.swing.v[1] = DEG_TO_RAD(-2.f);\\n 92 | }\\n 93 | \\n 94 | //-----------------------------------------------------------------------------\\n 95 | // Purpose: All fingers (expect thumb) have basically the same properties in terms of curl and splay.\\n 96 | // You can splay only the proximal, and curl the proximal, intermediate and distal joints.\\n 97 | // This applies the curl and splay to these joints.\\n 98 | //-----------------------------------------------------------------------------\\n 99 | static void ApplyGenericFingerTransform(const float curl, const float splay, HandSimFinger& out_finger)\\n100 | {\\n101 | \\tout_finger.metacarpal.swing.v[0] += DEG_TO_RAD(curl * 5.f); // the metacarpal only curls a little\\n102 | \\n103 | \\tout_finger.proximal.swing.v[0] += DEG_TO_RAD(curl * 90.f);\\n104 | \\tout_finger.proximal.swing.v[1] += DEG_TO_RAD(splay * 15.f);\\n105 | \\n106 | \\tout_finger.intermediate.rotation += DEG_TO_RAD(curl * 80.f);\\n107 | \\tout_finger.distal.rotation += DEG_TO_RAD(curl * 80.f);\\n108 | }\\n109 | \\n110 | \\n111 | //-----------------------------------------------------------------------------\\n112 | // Purpose: Takes an orientation and length of a joint and converts it to a vr::VRBoneTransform_t\\n113 | // We have to do convert the quaternion as we use vr::HmdQuaternion_t for our representation, but OpenVR wants vr::HmdQuaternionf_t\\n114 | //-----------------------------------------------------------------------------\\n115 | static void ComputeBoneTransform(const vr::ETrackedControllerRole role, const vr::HmdQuaternion_t& orientation, const vr::HmdVector3_t& position, vr::VRBoneTransform_t& out_transform)\\n116 | {\\n117 | \\t// Note that we use vr::HmdQuaternion_t but the Skeletal Input API needs vr::HmdQuaternionf_t, so we'll use this helper to convert\\n118 | \\tHmdQuaternion_ConvertQuaternion(orientation, out_transform.orientation);\\n119 | \\n120 | \\t// Fit the HmdVector3_t into the HmdVector4_t that the Skeletal Input API accepts\\n121 | \\tHmdVector3_CovertVector(position, out_transform.position);\\n122 | \\tout_transform.position.v[3] = 1.f;\\n123 | \\n124 | \\t//\\\"up\\\" axis is flipped between hands, so inverse the joint length for the right hand, as we base all our computations of the left skeleton pose.\\n125 | \\tif (role == vr::TrackedControllerRole_RightHand)\\n126 | \\t{\\n127 | \\t\\tout_transform.position.v[0] *= -1.f;\\n128 | \\t}\\n129 | }\\n130 | \\n131 | \\n132 | //-----------------------------------------------------------------------------\\n133 | // Purpose: This is just a little helper function to make our calls when trying to compute each bone a little simpler by specifying just a float for joint length, instead of the whole vector\\n134 | //-----------------------------------------------------------------------------\\n135 | static void ComputeBoneTransform(const vr::ETrackedControllerRole role, const vr::HmdQuaternion_t& orientation, const float joint_length, vr::VRBoneTransform_t& out_transform)\\n136 | {\\n137 | \\tComputeBoneTransform(role, orientation, { joint_length, 0.f, 0.f }, out_transform);\\n138 | }\\n139 | \\n140 | //-----------------------------------------------------------------------------\\n141 | // Purpose: Takes an orientation and length of a joint and converts it to a vr::VRBoneTransform_t, but with the orientation applied to the offset\\n142 | // We have to do convert the quaternion as we use vr::HmdQuaternion_t for our representation, but OpenVR wants vr::HmdQuaternionf_t\\n143 | //-----------------------------------------------------------------------------\\n144 | static void ComputeBoneTransformMetacarpal(const vr::ETrackedControllerRole role, const vr::HmdQuaternion_t& orientation, const float joint_length, vr::VRBoneTransform_t& out_transform)\\n145 | {\\n146 | \\tconst vr::HmdVector3_t offset = { joint_length, 0.f, 0.f };\\n147 | \\n148 | \\t/*\\n149 | \\tThe Skeletal Input API is designed to be used with common industry tools, such as Maya, to make it easier to move content from 3D editors into VR.\\n150 | \\tThe way that FBX handles conversion to a different coordinate system is to transform the root bone (wrist), then counter-transform the root's children to account for the root's change, but then\\n151 | \\tleave the local coordinate systems of the remaining bones as-is This means that the metacarpals will be rotated 90 degrees from the wrist if trying to build a skeleton programmatically. So, we\\n152 | \\tapply this extra rotation to the metacarpals to account for this.\\n153 | \\t*/\\n154 | \\tvr::HmdQuaternion_t magic = { 0.5f, 0.5f, -0.5f, 0.5f };\\n155 | \\n156 | \\tvr::HmdQuaternion_t bone_orientation = magic * orientation;\\n157 | \\n158 | \\t// Rotate the offset vector by the orientation\\n159 | \\tvr::HmdVector3_t bone_position = offset * bone_orientation;\\n160 | \\n161 | \\t//\\\"up\\\" axis is flipped between hands, so we need to inverse the x and y axis for the right hand, as all our calculations are based on the left hand currently.\\n162 | \\tif (role == vr::TrackedControllerRole_RightHand)\\n163 | \\t{\\n164 | \\t\\tstd::swap(bone_orientation.w, bone_orientation.x);\\n165 | \\t\\tstd::swap(bone_orientation.y, bone_orientation.z);\\n166 | \\n167 | \\t\\tbone_orientation.x *= -1.f;\\n168 | \\t\\tbone_orientation.z *= -1.f;\\n169 | \\t}\\n170 | \\n171 | \\t// pass off to put the position and orientation we've calculated into the skeleton\\n172 | \\tComputeBoneTransform(role, bone_orientation, bone_position, out_transform);\\n173 | }\\n174 | \\n175 | //-----------------------------------------------------------------------------\\n176 | // Purpose: Get the OpenVR bone index from a finger (index=0, middle=1...) and the bone position in the finger. Used in ComputeSkeletalTransforms\\n177 | //-----------------------------------------------------------------------------\\n178 | static int CalculateBoneTransformPositionFromFinger(int finger, int bone_in_finger)\\n179 | {\\n180 | \\tconst int bone_transform_finger_start_offset = eBone_IndexFinger0;\\n181 | \\n182 | \\tconst int result = bone_transform_finger_start_offset + finger * 5 + bone_in_finger;\\n183 | \\n184 | \\treturn result;\\n185 | }\\n186 | \\n187 | //-----------------------------------------------------------------------------\\n188 | // Purpose: Given the curls and splays, convert this to a vr::VRBoneTransform_t array\\n189 | //-----------------------------------------------------------------------------\\n190 | static void ComputeSkeletalTransforms(const HandSimHand& hand, vr::VRBoneTransform_t* out_transforms)\\n191 | {\\n192 | \\t// Do the thumb separately as it's special and not like the other fingers\\n193 | \\tComputeBoneTransformMetacarpal(\\n194 | \\t\\thand.role, HmdQuaternion_FromSwingTwist(hand.thumb.metacarpal.swing, hand.thumb.metacarpal.twist), finger_joint_lengths[0][0], out_transforms[eBone_Thumb0]);\\n195 | \\tComputeBoneTransform(hand.role, HmdQuaternion_FromSwingTwist(hand.thumb.proximal.swing, hand.thumb.metacarpal.twist), finger_joint_lengths[0][1], out_transforms[eBone_Thumb1]);\\n196 | \\tComputeBoneTransform(hand.role, HmdQuaternion_FromEulerAngles(hand.thumb.distal.rotation, 0.f, 0.f), finger_joint_lengths[0][2], out_transforms[eBone_Thumb2]);\\n197 | \\tComputeBoneTransform(hand.role, HmdQuaternion_Identity, finger_joint_lengths[0][3], out_transforms[eBone_Thumb3]);\\n198 | \\n199 | \\t// index, middle, ring, pinky\\n200 | \\t// We can do these all together as they all require the same calculations\\n201 | \\tfor (int finger = 0; finger < 4; finger++)\\n202 | \\t{\\n203 | \\t\\tComputeBoneTransformMetacarpal(hand.role, HmdQuaternion_FromSwingTwist(hand.fingers[finger].metacarpal.swing, hand.fingers[finger].metacarpal.twist),\\n204 | \\t\\t\\tfinger_joint_lengths[finger + 1][0], out_transforms[CalculateBoneTransformPositionFromFinger(finger, 0)]);\\n205 | \\n206 | \\t\\tComputeBoneTransform(hand.role, HmdQuaternion_FromSwingTwist(hand.fingers[finger].proximal.swing, hand.fingers[finger].proximal.twist), finger_joint_lengths[finger + 1][1],\\n207 | \\t\\t\\tout_transforms[CalculateBoneTransformPositionFromFinger(finger, 1)]);\\n208 | \\n209 | \\t\\tComputeBoneTransform(hand.role, HmdQuaternion_FromEulerAngles(hand.fingers[finger].intermediate.rotation, 0.f, 0.f), finger_joint_lengths[finger + 1][2],\\n210 | \\t\\t\\tout_transforms[CalculateBoneTransformPositionFromFinger(finger, 2)]);\\n211 | \\n212 | \\t\\tComputeBoneTransform(hand.role, HmdQuaternion_FromEulerAngles(hand.fingers[finger].distal.rotation, 0.f, 0.f), finger_joint_lengths[finger + 1][3],\\n213 | \\t\\t\\tout_transforms[CalculateBoneTransformPositionFromFinger(finger, 3)]);\\n214 | \\n215 | \\t\\tComputeBoneTransform(hand.role, HmdQuaternion_Identity, finger_joint_lengths[finger + 1][4], out_transforms[CalculateBoneTransformPositionFromFinger(finger, 4)]);\\n216 | \\t}\\n217 | }\\n218 | \\n219 | void MyHandSimulation::ComputeSkeletonTransforms(vr::ETrackedControllerRole role, const MyFingerCurls& curls, const MyFingerSplays& splays, vr::VRBoneTransform_t* out_transforms)\\n220 | {\\n221 | \\t// This is where we store our internal representation of curls and splays for the hand.\\n222 | \\tHandSimHand hand{};\\n223 | \\n224 | \\t// Set the handed-ness of the current skeleton (left or right hand)\\n225 | \\thand.role = role;\\n226 | \\n227 | \\t// root bone. This is just 0s. It's aligned to /pose/raw.\\n228 | \\tout_transforms[0] = { { 0.000000f, 0.000000f, 0.000000f, 1.000000f }, { 1.000000f, -0.000000f, -0.000000f, 0.000000f } };\\n229 | \\n230 | \\t// wrist bone. This was taken from the index controller pose.\\n231 | \\n232 | \\tout_transforms[1] = { { -0.034038f, 0.036503f, 0.164722f, 1.000000f }, { -0.055147f, -0.078608f, -0.920279f, 0.379296f } };\\n233 | \\n234 | \\t//\\\"up\\\" axis is flipped between hands so invert\\n235 | \\tif (role == vr::TrackedControllerRole_RightHand)\\n236 | \\t{\\n237 | \\t\\tout_transforms[1].position.v[0] *= -1.f;\\n238 | \\n239 | \\t\\tout_transforms[1].orientation.y *= -1.f;\\n240 | \\t\\tout_transforms[1].orientation.z *= -1.f;\\n241 | \\t}\\n242 | \\n243 | \\t// Initialize a default hand pose\\n244 | \\tInitHand(hand);\\n245 | \\n246 | \\t// We need to apply the curls and splays separately to the thumb as it's special\\n247 | \\thand.thumb.metacarpal.swing.v[0] += DEG_TO_RAD(curls.thumb * 5.f);\\n248 | \\thand.thumb.metacarpal.swing.v[1] += DEG_TO_RAD(splays.thumb * 5.f);\\n249 | \\thand.thumb.metacarpal.twist = 0.f;\\n250 | \\n251 | \\thand.thumb.proximal.swing.v[0] += DEG_TO_RAD(curls.thumb * 90.f);\\n252 | \\thand.thumb.proximal.swing.v[1] += DEG_TO_RAD(splays.thumb * 20.f);\\n253 | \\thand.thumb.proximal.twist = 0.f;\\n254 | \\n255 | \\thand.thumb.distal.rotation += DEG_TO_RAD(curls.thumb * 90.f);\\n256 | \\n257 | \\t// But we can batch up the fingers with a generic apply function.\\n258 | \\tApplyGenericFingerTransform(curls.index, splays.index, hand.fingers[0]);\\n259 | \\tApplyGenericFingerTransform(curls.middle, splays.middle, hand.fingers[1]);\\n260 | \\tApplyGenericFingerTransform(curls.ring, splays.ring, hand.fingers[2]);\\n261 | \\tApplyGenericFingerTransform(curls.pinky, splays.pinky, hand.fingers[3]);\\n262 | \\n263 | \\t// Now compute\\n264 | \\tComputeSkeletalTransforms(hand, out_transforms);\\n265 | }\\n----\\n\\n<environment_details>\\n# VSCode Visible Files\\ndocs\\\\Driver_API_Documentation.md\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:35:40 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n126,623 (63%)\\n\\n# Current Cost\\n$0.94\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":105,\"cacheWrites\":13328,\"cacheReads\":126506,\"cost\":0.08951880000000001}"},{"ts":1744500943562,"type":"say","say":"api_req_retry_delayed","text":"429 {\"type\":\"error\",\"error\":{\"type\":\"rate_limit_error\",\"message\":\"This request would exceed the rate limit for your organization (c798c237-8869-4d4f-a50e-54a864da0eac) of 20,000 input tokens per minute. For details, refer to: https://docs.anthropic.com/en/api/rate-limits. You can see the response headers for current usage. Please reduce the prompt length or the maximum tokens requested, or try again later. You may also contact sales at https://www.anthropic.com/contact-sales to discuss your options for a rate limit increase.\"}}\n\nRetry attempt 1\nRetrying now...","partial":false},{"ts":1744501007699,"type":"say","say":"text","text":"I've found some sample drivers in the codebase. Let me look at the barebones driver implementation to understand the basic structure of an OpenVR driver:\n\nLet me look at the barebones driver implementation to understand the basic structure of an OpenVR driver:","partial":false},{"ts":1744501008841,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"samples/drivers/drivers/barebones/src/device_provider.h\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\samples\\\\drivers\\\\drivers\\\\barebones\\\\src\\\\device_provider.h\",\"reason\":\" (max 500 lines)\"}","partial":false},{"ts":1744501023511,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'samples/drivers/drivers/barebones/src/device_provider.h'] Result:\\n\\n<file><path>samples/drivers/drivers/barebones/src/device_provider.h</path>\\n<content lines=\\\"1-19\\\">\\n 1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\r\\n 2 | #pragma once\\r\\n 3 | #include \\\"openvr_driver.h\\\"\\r\\n 4 | \\r\\n 5 | // make sure your class is publicly inheriting vr::IServerTrackedDeviceProvider!\\r\\n 6 | class MyDeviceProvider : public vr::IServerTrackedDeviceProvider\\r\\n 7 | {\\r\\n 8 | public:\\r\\n 9 | \\tvr::EVRInitError Init( vr::IVRDriverContext *pDriverContext ) override;\\r\\n10 | \\tconst char *const *GetInterfaceVersions() override;\\r\\n11 | \\r\\n12 | \\tvoid RunFrame() override;\\r\\n13 | \\r\\n14 | \\tbool ShouldBlockStandbyMode() override;\\r\\n15 | \\tvoid EnterStandby() override;\\r\\n16 | \\tvoid LeaveStandby() override;\\r\\n17 | \\r\\n18 | \\tvoid Cleanup() override;\\r\\n19 | };\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\ndocs\\\\Driver_API_Documentation.md\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:37:03 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n139,943 (70%)\\n\\n# Current Cost\\n$1.03\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":82,\"cacheWrites\":715,\"cacheReads\":139834,\"cost\":0.04587345}"},{"ts":1744501026226,"type":"say","say":"text","text":"Now let me look at the implementation of the barebones device provider:\n\nLet me look at the implementation of the barebones device provider:","partial":false},{"ts":1744501026708,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"samples/drivers/drivers/barebones/src/device_provider.cpp\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\samples\\\\drivers\\\\drivers\\\\barebones\\\\src\\\\device_provider.cpp\",\"reason\":\" (max 500 lines)\"}","partial":false},{"ts":1744501244441,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'samples/drivers/drivers/barebones/src/device_provider.cpp'] Result:\\n\\n<file><path>samples/drivers/drivers/barebones/src/device_provider.cpp</path>\\n<content lines=\\\"1-73\\\">\\n 1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\r\\n 2 | #include \\\"device_provider.h\\\"\\r\\n 3 | \\r\\n 4 | #include \\\"driverlog.h\\\"\\r\\n 5 | \\r\\n 6 | //-----------------------------------------------------------------------------\\r\\n 7 | // Purpose: This is called by vrserver after it receives a pointer back from HmdDriverFactory.\\r\\n 8 | // You should do your resources allocations here (**not** in the constructor).\\r\\n 9 | //-----------------------------------------------------------------------------\\r\\n10 | vr::EVRInitError MyDeviceProvider::Init( vr::IVRDriverContext *pDriverContext )\\r\\n11 | {\\r\\n12 | \\t// We need to initialise our driver context to make calls to the server.\\r\\n13 | \\t// OpenVR provides a macro to do this for us.\\r\\n14 | \\tVR_INIT_SERVER_DRIVER_CONTEXT( pDriverContext );\\r\\n15 | \\r\\n16 | \\t// Init has been called. Let's just log to acknowledge. You'll see this\\r\\n17 | \\t// in the logs (SteamVR hamburger menu > Developer > Web Console)\\r\\n18 | \\r\\n19 | \\tDriverLog( \\\"Init called on MyDeviceProvider!\\\" );\\r\\n20 | \\r\\n21 | \\treturn vr::VRInitError_None;\\r\\n22 | }\\r\\n23 | \\r\\n24 | //-----------------------------------------------------------------------------\\r\\n25 | // Purpose: Tells the runtime which version of the API we are targeting.\\r\\n26 | // Helper variables in the header you're using contain this information, which can be returned here.\\r\\n27 | //-----------------------------------------------------------------------------\\r\\n28 | const char *const *MyDeviceProvider::GetInterfaceVersions()\\r\\n29 | {\\r\\n30 | \\treturn vr::k_InterfaceVersions;\\r\\n31 | }\\r\\n32 | \\r\\n33 | //-----------------------------------------------------------------------------\\r\\n34 | // Purpose: This function is deprecated and never called. But, it must still be defined, or we can't compile.\\r\\n35 | //-----------------------------------------------------------------------------\\r\\n36 | bool MyDeviceProvider::ShouldBlockStandbyMode()\\r\\n37 | {\\r\\n38 | \\treturn false;\\r\\n39 | }\\r\\n40 | \\r\\n41 | //-----------------------------------------------------------------------------\\r\\n42 | // Purpose: This is called in the main loop of vrserver.\\r\\n43 | // Drivers *can* do work here, but should ensure this work is relatively inexpensive.\\r\\n44 | // A good thing to do here is poll for events from the runtime or applications\\r\\n45 | //-----------------------------------------------------------------------------\\r\\n46 | void MyDeviceProvider::RunFrame()\\r\\n47 | {\\r\\n48 | }\\r\\n49 | \\r\\n50 | //-----------------------------------------------------------------------------\\r\\n51 | // Purpose: This function is called when the system enters a period of inactivity.\\r\\n52 | // The devices might want to turn off their displays or go into a low power mode to preserve them.\\r\\n53 | //-----------------------------------------------------------------------------\\r\\n54 | void MyDeviceProvider::EnterStandby()\\r\\n55 | {\\r\\n56 | }\\r\\n57 | \\r\\n58 | //-----------------------------------------------------------------------------\\r\\n59 | // Purpose: This function is called after the system has been in a period of inactivity, and is waking up again.\\r\\n60 | // Turn back on the displays or devices here.\\r\\n61 | //-----------------------------------------------------------------------------\\r\\n62 | void MyDeviceProvider::LeaveStandby()\\r\\n63 | {\\r\\n64 | }\\r\\n65 | \\r\\n66 | //-----------------------------------------------------------------------------\\r\\n67 | // Purpose: This function is called just before the driver is unloaded from vrserver.\\r\\n68 | // Drivers should free whatever resources they have acquired over the session here.\\r\\n69 | // Any calls to the server is guaranteed to be valid before this, but not after it has been called.\\r\\n70 | //-----------------------------------------------------------------------------\\r\\n71 | void MyDeviceProvider::Cleanup()\\r\\n72 | {\\r\\n73 | }\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\n.gitignore\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:40:44 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n140,635 (70%)\\n\\n# Current Cost\\n$1.08\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":89,\"cacheWrites\":1354,\"cacheReads\":140549,\"cost\":0.0485892}"},{"ts":1744501247184,"type":"say","say":"text","text":"Now let me look at the HMD driver factory implementation for the barebones driver:\n\nLet me look at the HMD driver factory implementation for the barebones driver:","partial":false},{"ts":1744501248130,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"samples/drivers/drivers/barebones/src/hmd_driver_factory.cpp\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\samples\\\\drivers\\\\drivers\\\\barebones\\\\src\\\\hmd_driver_factory.cpp\",\"reason\":\" (max 500 lines)\"}","partial":false},{"ts":1744501254387,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'samples/drivers/drivers/barebones/src/hmd_driver_factory.cpp'] Result:\\n\\n<file><path>samples/drivers/drivers/barebones/src/hmd_driver_factory.cpp</path>\\n<content lines=\\\"1-36\\\">\\n 1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\r\\n 2 | #include \\\"device_provider.h\\\"\\r\\n 3 | #include \\\"openvr_driver.h\\\"\\r\\n 4 | #include <cstring>\\r\\n 5 | \\r\\n 6 | #if defined( _WIN32 )\\r\\n 7 | #define HMD_DLL_EXPORT extern \\\"C\\\" __declspec( dllexport )\\r\\n 8 | #define HMD_DLL_IMPORT extern \\\"C\\\" __declspec( dllimport )\\r\\n 9 | #elif defined( __GNUC__ ) || defined( COMPILER_GCC ) || defined( __APPLE__ )\\r\\n10 | #define HMD_DLL_EXPORT extern \\\"C\\\" __attribute__( ( visibility( \\\"default\\\" ) ) )\\r\\n11 | #define HMD_DLL_IMPORT extern \\\"C\\\"\\r\\n12 | #else\\r\\n13 | #error \\\"Unsupported Platform.\\\"\\r\\n14 | #endif\\r\\n15 | \\r\\n16 | MyDeviceProvider device_provider;\\r\\n17 | \\r\\n18 | //-----------------------------------------------------------------------------\\r\\n19 | // Purpose: This is exported from the shared library to be called as the entry point into the driver by vrserver.\\r\\n20 | // You should return a point to your IServerTrackedDeviceProvider here, as well as optionally a watchdog (see other\\r\\n21 | // samples).\\r\\n22 | //-----------------------------------------------------------------------------\\r\\n23 | HMD_DLL_EXPORT void *HmdDriverFactory( const char *pInterfaceName, int *pReturnCode )\\r\\n24 | {\\r\\n25 | \\t// This is where we return our device provider, if the HmdDriverFactory call asks for it.\\r\\n26 | \\tif ( 0 == strcmp( vr::IServerTrackedDeviceProvider_Version, pInterfaceName ) )\\r\\n27 | \\t{\\r\\n28 | \\t\\treturn &device_provider;\\r\\n29 | \\t}\\r\\n30 | \\r\\n31 | \\t// Otherwise tell the runtime that we don't have this interface.\\r\\n32 | \\tif ( pReturnCode )\\r\\n33 | \\t\\t*pReturnCode = vr::VRInitError_Init_InterfaceNotFound;\\r\\n34 | \\t\\r\\n35 | \\treturn NULL;\\r\\n36 | }\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\n.gitignore\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:40:54 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n141,996 (71%)\\n\\n# Current Cost\\n$1.12\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":89,\"cacheWrites\":1010,\"cacheReads\":141903,\"cost\":0.047705399999999995}"},{"ts":1744501256931,"type":"say","say":"text","text":"Now let me look at the driver manifest file for the barebones driver:\n\nLet me look at the driver manifest file for the barebones driver:","partial":false},{"ts":1744501257468,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"samples/drivers/drivers/barebones/barebones/driver.vrdrivermanifest\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\samples\\\\drivers\\\\drivers\\\\barebones\\\\barebones\\\\driver.vrdrivermanifest\",\"reason\":\" (max 500 lines)\"}","partial":false},{"ts":1744501263535,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'samples/drivers/drivers/barebones/barebones/driver.vrdrivermanifest'] Result:\\n\\n<file><path>samples/drivers/drivers/barebones/barebones/driver.vrdrivermanifest</path>\\n<content lines=\\\"1-8\\\">\\n1 | {\\r\\n2 | \\t\\\"alwaysActivate\\\": true,\\r\\n3 | \\t\\\"name\\\" : \\\"barebones\\\",\\r\\n4 | \\t\\\"directory\\\" : \\\"\\\",\\r\\n5 | \\t\\\"resourceOnly\\\" : false,\\r\\n6 | \\r\\n7 | \\t\\\"hmd_presence\\\" : []\\r\\n8 | }\\r\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\n.gitignore\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:41:03 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n143,006 (72%)\\n\\n# Current Cost\\n$1.17\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":96,\"cacheWrites\":528,\"cacheReads\":142913,\"cost\":0.0463059}"},{"ts":1744501265741,"type":"say","say":"text","text":"Now let me look at the simplehmd driver to understand how to implement a custom HMD driver:\n\nLet me look at the simplehmd driver to understand how to implement a custom HMD driver:","partial":false},{"ts":1744501266530,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"samples/drivers/drivers/simplehmd/src/device_provider.h\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\samples\\\\drivers\\\\drivers\\\\simplehmd\\\\src\\\\device_provider.h\",\"reason\":\" (max 500 lines)\"}","partial":false},{"ts":1744501282815,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'samples/drivers/drivers/simplehmd/src/device_provider.h'] Result:\\n\\n<file><path>samples/drivers/drivers/simplehmd/src/device_provider.h</path>\\n<content lines=\\\"1-26\\\">\\n 1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\r\\n 2 | #pragma once\\r\\n 3 | \\r\\n 4 | #include <memory>\\r\\n 5 | \\r\\n 6 | #include \\\"hmd_device_driver.h\\\"\\r\\n 7 | #include \\\"openvr_driver.h\\\"\\r\\n 8 | \\r\\n 9 | // make sure your class is publicly inheriting vr::IServerTrackedDeviceProvider!\\r\\n10 | class MyDeviceProvider : public vr::IServerTrackedDeviceProvider\\r\\n11 | {\\r\\n12 | public:\\r\\n13 | \\tvr::EVRInitError Init( vr::IVRDriverContext *pDriverContext ) override;\\r\\n14 | \\tconst char *const *GetInterfaceVersions() override;\\r\\n15 | \\r\\n16 | \\tvoid RunFrame() override;\\r\\n17 | \\r\\n18 | \\tbool ShouldBlockStandbyMode() override;\\r\\n19 | \\tvoid EnterStandby() override;\\r\\n20 | \\tvoid LeaveStandby() override;\\r\\n21 | \\r\\n22 | \\tvoid Cleanup() override;\\r\\n23 | \\r\\n24 | private:\\r\\n25 | \\tstd::unique_ptr<MyHMDControllerDeviceDriver> my_hmd_device_;\\r\\n26 | };\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\n.gitignore\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:41:22 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n143,541 (72%)\\n\\n# Current Cost\\n$1.22\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":81,\"cacheWrites\":772,\"cacheReads\":143441,\"cost\":0.047154299999999996}"},{"ts":1744501285206,"type":"say","say":"text","text":"Now let me look at the HMD device driver implementation:\n\nLet me look at the HMD device driver implementation:","partial":false},{"ts":1744501285659,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"samples/drivers/drivers/simplehmd/src/hmd_device_driver.h\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\samples\\\\drivers\\\\drivers\\\\simplehmd\\\\src\\\\hmd_device_driver.h\",\"reason\":\" (max 500 lines)\"}","partial":false},{"ts":1744501302109,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'samples/drivers/drivers/simplehmd/src/hmd_device_driver.h'] Result:\\n\\n<file><path>samples/drivers/drivers/simplehmd/src/hmd_device_driver.h</path>\\n<content lines=\\\"1-84\\\">\\n 1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\r\\n 2 | #pragma once\\r\\n 3 | \\r\\n 4 | #include <array>\\r\\n 5 | #include <string>\\r\\n 6 | \\r\\n 7 | #include \\\"openvr_driver.h\\\"\\r\\n 8 | #include <atomic>\\r\\n 9 | #include <thread>\\r\\n10 | \\r\\n11 | enum MyComponent\\r\\n12 | {\\r\\n13 | \\tMyComponent_system_touch,\\r\\n14 | \\tMyComponent_system_click,\\r\\n15 | \\r\\n16 | \\tMyComponent_MAX\\r\\n17 | };\\r\\n18 | \\r\\n19 | struct MyHMDDisplayDriverConfiguration\\r\\n20 | {\\r\\n21 | \\tint32_t window_x;\\r\\n22 | \\tint32_t window_y;\\r\\n23 | \\r\\n24 | \\tint32_t window_width;\\r\\n25 | \\tint32_t window_height;\\r\\n26 | \\r\\n27 | \\tint32_t render_width;\\r\\n28 | \\tint32_t render_height;\\r\\n29 | };\\r\\n30 | \\r\\n31 | class MyHMDDisplayComponent : public vr::IVRDisplayComponent\\r\\n32 | {\\r\\n33 | public:\\r\\n34 | \\texplicit MyHMDDisplayComponent( const MyHMDDisplayDriverConfiguration &config );\\r\\n35 | \\r\\n36 | \\t// ----- Functions to override vr::IVRDisplayComponent -----\\r\\n37 | \\tbool IsDisplayOnDesktop() override;\\r\\n38 | \\tbool IsDisplayRealDisplay() override;\\r\\n39 | \\tvoid GetRecommendedRenderTargetSize( uint32_t *pnWidth, uint32_t *pnHeight ) override;\\r\\n40 | \\tvoid GetEyeOutputViewport( vr::EVREye eEye, uint32_t *pnX, uint32_t *pnY, uint32_t *pnWidth, uint32_t *pnHeight ) override;\\r\\n41 | \\tvoid GetProjectionRaw( vr::EVREye eEye, float *pfLeft, float *pfRight, float *pfTop, float *pfBottom ) override;\\r\\n42 | \\tvr::DistortionCoordinates_t ComputeDistortion( vr::EVREye eEye, float fU, float fV ) override;\\r\\n43 | \\tvoid GetWindowBounds( int32_t *pnX, int32_t *pnY, uint32_t *pnWidth, uint32_t *pnHeight ) override;\\r\\n44 | \\r\\n45 | private:\\r\\n46 | \\tMyHMDDisplayDriverConfiguration config_;\\r\\n47 | };\\r\\n48 | \\r\\n49 | //-----------------------------------------------------------------------------\\r\\n50 | // Purpose: Represents a single tracked device in the system.\\r\\n51 | // What this device actually is (controller, hmd) depends on what the\\r\\n52 | // IServerTrackedDeviceProvider calls to TrackedDeviceAdded and the\\r\\n53 | // properties within Activate() of the ITrackedDeviceServerDriver class.\\r\\n54 | //-----------------------------------------------------------------------------\\r\\n55 | class MyHMDControllerDeviceDriver : public vr::ITrackedDeviceServerDriver\\r\\n56 | {\\r\\n57 | public:\\r\\n58 | \\tMyHMDControllerDeviceDriver();\\r\\n59 | \\tvr::EVRInitError Activate( uint32_t unObjectId ) override;\\r\\n60 | \\tvoid EnterStandby() override;\\r\\n61 | \\tvoid *GetComponent( const char *pchComponentNameAndVersion ) override;\\r\\n62 | \\tvoid DebugRequest( const char *pchRequest, char *pchResponseBuffer, uint32_t unResponseBufferSize ) override;\\r\\n63 | \\tvr::DriverPose_t GetPose() override;\\r\\n64 | \\tvoid Deactivate() override;\\r\\n65 | \\r\\n66 | \\t// ----- Functions we declare ourselves below -----\\r\\n67 | \\tconst std::string &MyGetSerialNumber();\\r\\n68 | \\tvoid MyRunFrame();\\r\\n69 | \\tvoid MyProcessEvent( const vr::VREvent_t &vrevent );\\r\\n70 | \\tvoid MyPoseUpdateThread();\\r\\n71 | \\r\\n72 | private:\\r\\n73 | \\tstd::unique_ptr< MyHMDDisplayComponent > my_display_component_;\\r\\n74 | \\r\\n75 | \\tstd::string my_hmd_model_number_;\\r\\n76 | \\tstd::string my_hmd_serial_number_;\\r\\n77 | \\r\\n78 | \\tstd::array< vr::VRInputComponentHandle_t, MyComponent_MAX > my_input_handles_{};\\r\\n79 | \\tstd::atomic< int > frame_number_;\\r\\n80 | \\tstd::atomic< bool > is_active_;\\r\\n81 | \\tstd::atomic< uint32_t > device_index_;\\r\\n82 | \\r\\n83 | \\tstd::thread my_pose_update_thread_;\\r\\n84 | };\\r\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\n.gitignore\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:41:42 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n144,298 (72%)\\n\\n# Current Cost\\n$1.27\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":126,\"cacheWrites\":1674,\"cacheReads\":144213,\"cost\":0.0514434}"},{"ts":1744501304515,"type":"say","say":"text","text":"Now let me look at the implementation of the HMD device driver to understand how it handles poses and IMU data:\n\nLet me look at the implementation of the HMD device driver to understand how it handles poses and IMU data:","partial":false},{"ts":1744501305918,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"samples/drivers/drivers/simplehmd/src/hmd_device_driver.cpp\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\samples\\\\drivers\\\\drivers\\\\simplehmd\\\\src\\\\hmd_device_driver.cpp\",\"reason\":\" (lines 1-100)\"}","partial":false},{"ts":1744501324586,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'samples/drivers/drivers/simplehmd/src/hmd_device_driver.cpp'] Result:\\n\\n<file><path>samples/drivers/drivers/simplehmd/src/hmd_device_driver.cpp</path>\\n<content lines=\\\"1-100\\\">\\n  1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\r\\n  2 | #include \\\"hmd_device_driver.h\\\"\\r\\n  3 | \\r\\n  4 | #include \\\"driverlog.h\\\"\\r\\n  5 | #include \\\"vrmath.h\\\"\\r\\n  6 | #include <string.h>\\r\\n  7 | \\r\\n  8 | // Let's create some variables for strings used in getting settings.\\r\\n  9 | // This is the section where all of the settings we want are stored. A section name can be anything,\\r\\n 10 | // but if you want to store driver specific settings, it's best to namespace the section with the driver identifier\\r\\n 11 | // ie \\\"<my_driver>_<section>\\\" to avoid collisions\\r\\n 12 | static const char *my_hmd_main_settings_section = \\\"driver_simplehmd\\\";\\r\\n 13 | static const char *my_hmd_display_settings_section = \\\"simplehmd_display\\\";\\r\\n 14 | \\r\\n 15 | MyHMDControllerDeviceDriver::MyHMDControllerDeviceDriver()\\r\\n 16 | {\\r\\n 17 | \\t// Keep track of whether Activate() has been called\\r\\n 18 | \\tis_active_ = false;\\r\\n 19 | \\r\\n 20 | \\t// We have our model number and serial number stored in SteamVR settings. We need to get them and do so here.\\r\\n 21 | \\t// Other IVRSettings methods (to get int32, floats, bools) return the data, instead of modifying, but strings are\\r\\n 22 | \\t// different.\\r\\n 23 | \\tchar model_number[ 1024 ];\\r\\n 24 | \\tvr::VRSettings()->GetString( my_hmd_main_settings_section, \\\"model_number\\\", model_number, sizeof( model_number ) );\\r\\n 25 | \\tmy_hmd_model_number_ = model_number;\\r\\n 26 | \\r\\n 27 | \\t// Get our serial number depending on our \\\"handedness\\\"\\r\\n 28 | \\tchar serial_number[ 1024 ];\\r\\n 29 | \\tvr::VRSettings()->GetString( my_hmd_main_settings_section, \\\"serial_number\\\", serial_number, sizeof( serial_number ) );\\r\\n 30 | \\tmy_hmd_serial_number_ = serial_number;\\r\\n 31 | \\r\\n 32 | \\t// Here's an example of how to use our logging wrapper around IVRDriverLog\\r\\n 33 | \\t// In SteamVR logs (SteamVR Hamburger Menu > Developer Settings > Web console) drivers have a prefix of\\r\\n 34 | \\t// \\\"<driver_name>:\\\". You can search this in the top search bar to find the info that you've logged.\\r\\n 35 | \\tDriverLog( \\\"My Dummy HMD Model Number: %s\\\", my_hmd_model_number_.c_str() );\\r\\n 36 | \\tDriverLog( \\\"My Dummy HMD Serial Number: %s\\\", my_hmd_serial_number_.c_str() );\\r\\n 37 | \\r\\n 38 | \\t// Display settings\\r\\n 39 | \\tMyHMDDisplayDriverConfiguration display_configuration{};\\r\\n 40 | \\tdisplay_configuration.window_x = vr::VRSettings()->GetInt32( my_hmd_display_settings_section, \\\"window_x\\\" );\\r\\n 41 | \\tdisplay_configuration.window_y = vr::VRSettings()->GetInt32( my_hmd_display_settings_section, \\\"window_y\\\" );\\r\\n 42 | \\r\\n 43 | \\tdisplay_configuration.window_width = vr::VRSettings()->GetInt32( my_hmd_display_settings_section, \\\"window_width\\\" );\\r\\n 44 | \\tdisplay_configuration.window_height = vr::VRSettings()->GetInt32( my_hmd_display_settings_section, \\\"window_height\\\" );\\r\\n 45 | \\r\\n 46 | \\tdisplay_configuration.render_width = vr::VRSettings()->GetInt32( my_hmd_display_settings_section, \\\"render_width\\\" );\\r\\n 47 | \\tdisplay_configuration.render_height = vr::VRSettings()->GetInt32( my_hmd_display_settings_section, \\\"render_height\\\" );\\r\\n 48 | \\r\\n 49 | \\t// Instantiate our display component\\r\\n 50 | \\tmy_display_component_ = std::make_unique< MyHMDDisplayComponent >( display_configuration );\\r\\n 51 | }\\r\\n 52 | \\r\\n 53 | //-----------------------------------------------------------------------------\\r\\n 54 | // Purpose: This is called by vrserver after our\\r\\n 55 | //  IServerTrackedDeviceProvider calls IVRServerDriverHost::TrackedDeviceAdded.\\r\\n 56 | //-----------------------------------------------------------------------------\\r\\n 57 | vr::EVRInitError MyHMDControllerDeviceDriver::Activate( uint32_t unObjectId )\\r\\n 58 | {\\r\\n 59 | \\t// Let's keep track of our device index. It'll be useful later.\\r\\n 60 | \\t// Also, if we re-activate, be sure to set this.\\r\\n 61 | \\tdevice_index_ = unObjectId;\\r\\n 62 | \\r\\n 63 | \\t// Set a member to keep track of whether we've activated yet or not\\r\\n 64 | \\tis_active_ = true;\\r\\n 65 | \\r\\n 66 | \\t// For keeping track of frame number for animating motion.\\r\\n 67 | \\tframe_number_ = 0;\\r\\n 68 | \\r\\n 69 | \\t// Properties are stored in containers, usually one container per device index. We need to get this container to set\\r\\n 70 | \\t// The properties we want, so we call this to retrieve a handle to it.\\r\\n 71 | \\tvr::PropertyContainerHandle_t container = vr::VRProperties()->TrackedDeviceToPropertyContainer( device_index_ );\\r\\n 72 | \\r\\n 73 | \\t// Let's begin setting up the properties now we've got our container.\\r\\n 74 | \\t// A list of properties available is contained in vr::ETrackedDeviceProperty.\\r\\n 75 | \\r\\n 76 | \\t// First, let's set the model number.\\r\\n 77 | \\tvr::VRProperties()->SetStringProperty( container, vr::Prop_ModelNumber_String, my_hmd_model_number_.c_str() );\\r\\n 78 | \\r\\n 79 | \\t// Next, display settings\\r\\n 80 | \\r\\n 81 | \\t// Get the ipd of the user from SteamVR settings\\r\\n 82 | \\tconst float ipd = vr::VRSettings()->GetFloat( vr::k_pch_SteamVR_Section, vr::k_pch_SteamVR_IPD_Float );\\r\\n 83 | \\tvr::VRProperties()->SetFloatProperty( container, vr::Prop_UserIpdMeters_Float, ipd );\\r\\n 84 | \\r\\n 85 | \\t// For HMDs, it's required that a refresh rate is set otherwise VRCompositor will fail to start.\\r\\n 86 | \\tvr::VRProperties()->SetFloatProperty( container, vr::Prop_DisplayFrequency_Float, 0.f );\\r\\n 87 | \\r\\n 88 | \\t// The distance from the user's eyes to the display in meters. This is used for reprojection.\\r\\n 89 | \\tvr::VRProperties()->SetFloatProperty( container, vr::Prop_UserHeadToEyeDepthMeters_Float, 0.f );\\r\\n 90 | \\r\\n 91 | \\t// How long from the compositor to submit a frame to the time it takes to display it on the screen.\\r\\n 92 | \\tvr::VRProperties()->SetFloatProperty( container, vr::Prop_SecondsFromVsyncToPhotons_Float, 0.11f );\\r\\n 93 | \\r\\n 94 | \\t// avoid \\\"not fullscreen\\\" warnings from vrmonitor\\r\\n 95 | \\tvr::VRProperties()->SetBoolProperty( container, vr::Prop_IsOnDesktop_Bool, false );\\r\\n 96 | \\r\\n 97 | \\tvr::VRProperties()->SetBoolProperty(container, vr::Prop_DisplayDebugMode_Bool, true);\\r\\n 98 | \\r\\n 99 | \\t// Now let's set up our inputs\\r\\n100 | \\t// This tells the UI what to show the user for bindings for this controller,\\r\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\n.gitignore\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:42:04 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n146,017 (73%)\\n\\n# Current Cost\\n$1.32\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":120,\"cacheWrites\":2600,\"cacheReads\":145887,\"cost\":0.0553281}"},{"ts":1744501327386,"type":"say","say":"text","text":"Let me continue reading the HMD device driver implementation to understand how it handles poses and IMU data:\n\nLet me continue reading the HMD device driver implementation to understand how it handles poses and IMU data:","partial":false},{"ts":1744501328324,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"samples/drivers/drivers/simplehmd/src/hmd_device_driver.cpp\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\samples\\\\drivers\\\\drivers\\\\simplehmd\\\\src\\\\hmd_device_driver.cpp\",\"reason\":\" (lines 100-200)\"}","partial":false},{"ts":1744501332100,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'samples/drivers/drivers/simplehmd/src/hmd_device_driver.cpp'] Result:\\n\\n<file><path>samples/drivers/drivers/simplehmd/src/hmd_device_driver.cpp</path>\\n<content lines=\\\"100-200\\\">\\n100 | \\t// This tells the UI what to show the user for bindings for this controller,\\r\\n101 | \\t// As well as what default bindings should be for legacy apps.\\r\\n102 | \\t// Note, we can use the wildcard {<driver_name>} to match the root folder location\\r\\n103 | \\t// of our driver.\\r\\n104 | \\tvr::VRProperties()->SetStringProperty( container, vr::Prop_InputProfilePath_String, \\\"{simplehmd}/input/mysimplehmd_profile.json\\\" );\\r\\n105 | \\r\\n106 | \\t// Let's set up handles for all of our components.\\r\\n107 | \\t// Even though these are also defined in our input profile,\\r\\n108 | \\t// We need to get handles to them to update the inputs.\\r\\n109 | \\tvr::VRDriverInput()->CreateBooleanComponent( container, \\\"/input/system/touch\\\", &my_input_handles_[ MyComponent_system_touch ] );\\r\\n110 | \\tvr::VRDriverInput()->CreateBooleanComponent( container, \\\"/input/system/click\\\", &my_input_handles_[ MyComponent_system_click ] );\\r\\n111 | \\r\\n112 | \\tmy_pose_update_thread_ = std::thread( &MyHMDControllerDeviceDriver::MyPoseUpdateThread, this );\\r\\n113 | \\r\\n114 | \\t// We've activated everything successfully!\\r\\n115 | \\t// Let's tell SteamVR that by saying we don't have any errors.\\r\\n116 | \\treturn vr::VRInitError_None;\\r\\n117 | }\\r\\n118 | \\r\\n119 | //-----------------------------------------------------------------------------\\r\\n120 | // Purpose: If you're an HMD, this is where you would return an implementation\\r\\n121 | // of vr::IVRDisplayComponent, vr::IVRVirtualDisplay or vr::IVRDirectModeComponent.\\r\\n122 | //-----------------------------------------------------------------------------\\r\\n123 | void *MyHMDControllerDeviceDriver::GetComponent( const char *pchComponentNameAndVersion )\\r\\n124 | {\\r\\n125 | \\tif ( strcmp( pchComponentNameAndVersion, vr::IVRDisplayComponent_Version ) == 0 )\\r\\n126 | \\t{\\r\\n127 | \\t\\treturn my_display_component_.get();\\r\\n128 | \\t}\\r\\n129 | \\r\\n130 | \\treturn nullptr;\\r\\n131 | }\\r\\n132 | \\r\\n133 | //-----------------------------------------------------------------------------\\r\\n134 | // Purpose: This is called by vrserver when a debug request has been made from an application to the driver.\\r\\n135 | // What is in the response and request is up to the application and driver to figure out themselves.\\r\\n136 | //-----------------------------------------------------------------------------\\r\\n137 | void MyHMDControllerDeviceDriver::DebugRequest( const char *pchRequest, char *pchResponseBuffer, uint32_t unResponseBufferSize )\\r\\n138 | {\\r\\n139 | \\tif ( unResponseBufferSize >= 1 )\\r\\n140 | \\t\\tpchResponseBuffer[ 0 ] = 0;\\r\\n141 | }\\r\\n142 | \\r\\n143 | //-----------------------------------------------------------------------------\\r\\n144 | // Purpose: This is never called by vrserver in recent OpenVR versions,\\r\\n145 | // but is useful for giving data to vr::VRServerDriverHost::TrackedDevicePoseUpdated.\\r\\n146 | //-----------------------------------------------------------------------------\\r\\n147 | vr::DriverPose_t MyHMDControllerDeviceDriver::GetPose()\\r\\n148 | {\\r\\n149 | \\t// Let's retrieve the Hmd pose to base our controller pose off.\\r\\n150 | \\r\\n151 | \\t// First, initialize the struct that we'll be submitting to the runtime to tell it we've updated our pose.\\r\\n152 | \\tvr::DriverPose_t pose = { 0 };\\r\\n153 | \\r\\n154 | \\t// These need to be set to be valid quaternions. The device won't appear otherwise.\\r\\n155 | \\tpose.qWorldFromDriverRotation.w = 1.f;\\r\\n156 | \\tpose.qDriverFromHeadRotation.w = 1.f;\\r\\n157 | \\r\\n158 | \\tpose.qRotation.w = 1.f;\\r\\n159 | \\r\\n160 | \\tpose.vecPosition[ 0 ] = 0.0f;\\r\\n161 | \\tpose.vecPosition[ 1 ] = sin( frame_number_ * 0.01 ) * 0.1f + 1.0f; // slowly move the hmd up and down.\\r\\n162 | \\tpose.vecPosition[ 2 ] = 0.0f;\\r\\n163 | \\r\\n164 | \\t// The pose we provided is valid.\\r\\n165 | \\t// This should be set is\\r\\n166 | \\tpose.poseIsValid = true;\\r\\n167 | \\r\\n168 | \\t// Our device is always connected.\\r\\n169 | \\t// In reality with physical devices, when they get disconnected,\\r\\n170 | \\t// set this to false and icons in SteamVR will be updated to show the device is disconnected\\r\\n171 | \\tpose.deviceIsConnected = true;\\r\\n172 | \\r\\n173 | \\t// The state of our tracking. For our virtual device, it's always going to be ok,\\r\\n174 | \\t// but this can get set differently to inform the runtime about the state of the device's tracking\\r\\n175 | \\t// and update the icons to inform the user accordingly.\\r\\n176 | \\tpose.result = vr::TrackingResult_Running_OK;\\r\\n177 | \\r\\n178 | \\t// For HMDs we want to apply rotation/motion prediction\\r\\n179 | \\tpose.shouldApplyHeadModel = true;\\r\\n180 | \\r\\n181 | \\treturn pose;\\r\\n182 | }\\r\\n183 | \\r\\n184 | void MyHMDControllerDeviceDriver::MyPoseUpdateThread()\\r\\n185 | {\\r\\n186 | \\twhile ( is_active_ )\\r\\n187 | \\t{\\r\\n188 | \\t\\t// Inform the vrserver that our tracked device's pose has updated, giving it the pose returned by our GetPose().\\r\\n189 | \\t\\tvr::VRServerDriverHost()->TrackedDevicePoseUpdated( device_index_, GetPose(), sizeof( vr::DriverPose_t ) );\\r\\n190 | \\r\\n191 | \\t\\t// Update our pose every five milliseconds.\\r\\n192 | \\t\\t// In reality, you should update the pose whenever you have new data from your device.\\r\\n193 | \\t\\tstd::this_thread::sleep_for( std::chrono::milliseconds( 5 ) );\\r\\n194 | \\t}\\r\\n195 | }\\r\\n196 | \\r\\n197 | //-----------------------------------------------------------------------------\\r\\n198 | // Purpose: This is called by vrserver when the device should enter standby mode.\\r\\n199 | // The device should be put into whatever low power mode it has.\\r\\n200 | // We don't really have anything to do here, so let's just log something.\\r\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\n.gitignore\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:42:12 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n148,611 (74%)\\n\\n# Current Cost\\n$1.37\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":121,\"cacheWrites\":2169,\"cacheReads\":148487,\"cost\":0.054506849999999996}"},{"ts":1744501334781,"type":"say","say":"text","text":"Let me continue reading the HMD device driver implementation to understand how it handles poses and IMU data:\n\nLet me continue reading the HMD device driver implementation to understand how it handles poses and IMU data:","partial":false},{"ts":1744501335663,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"samples/drivers/drivers/simplehmd/src/hmd_device_driver.cpp\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\samples\\\\drivers\\\\drivers\\\\simplehmd\\\\src\\\\hmd_device_driver.cpp\",\"reason\":\" (lines 200-300)\"}","partial":false},{"ts":1744501339264,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'samples/drivers/drivers/simplehmd/src/hmd_device_driver.cpp'] Result:\\n\\n<file><path>samples/drivers/drivers/simplehmd/src/hmd_device_driver.cpp</path>\\n<content lines=\\\"200-300\\\">\\n200 | // We don't really have anything to do here, so let's just log something.\\r\\n201 | //-----------------------------------------------------------------------------\\r\\n202 | void MyHMDControllerDeviceDriver::EnterStandby()\\r\\n203 | {\\r\\n204 | \\tDriverLog( \\\"HMD has been put into standby.\\\" );\\r\\n205 | }\\r\\n206 | \\r\\n207 | //-----------------------------------------------------------------------------\\r\\n208 | // Purpose: This is called by vrserver when the device should deactivate.\\r\\n209 | // This is typically at the end of a session\\r\\n210 | // The device should free any resources it has allocated here.\\r\\n211 | //-----------------------------------------------------------------------------\\r\\n212 | void MyHMDControllerDeviceDriver::Deactivate()\\r\\n213 | {\\r\\n214 | \\t// Let's join our pose thread that's running\\r\\n215 | \\t// by first checking then setting is_active_ to false to break out\\r\\n216 | \\t// of the while loop, if it's running, then call .join() on the thread\\r\\n217 | \\tif ( is_active_.exchange( false ) )\\r\\n218 | \\t{\\r\\n219 | \\t\\tmy_pose_update_thread_.join();\\r\\n220 | \\t}\\r\\n221 | \\r\\n222 | \\t// unassign our controller index (we don't want to be calling vrserver anymore after Deactivate() has been called\\r\\n223 | \\tdevice_index_ = vr::k_unTrackedDeviceIndexInvalid;\\r\\n224 | }\\r\\n225 | \\r\\n226 | \\r\\n227 | //-----------------------------------------------------------------------------\\r\\n228 | // Purpose: This is called by our IServerTrackedDeviceProvider when its RunFrame() method gets called.\\r\\n229 | // It's not part of the ITrackedDeviceServerDriver interface, we created it ourselves.\\r\\n230 | //-----------------------------------------------------------------------------\\r\\n231 | void MyHMDControllerDeviceDriver::MyRunFrame()\\r\\n232 | {\\r\\n233 | \\tframe_number_++;\\r\\n234 | \\t// update our inputs here\\r\\n235 | }\\r\\n236 | \\r\\n237 | \\r\\n238 | //-----------------------------------------------------------------------------\\r\\n239 | // Purpose: This is called by our IServerTrackedDeviceProvider when it pops an event off the event queue.\\r\\n240 | // It's not part of the ITrackedDeviceServerDriver interface, we created it ourselves.\\r\\n241 | //-----------------------------------------------------------------------------\\r\\n242 | void MyHMDControllerDeviceDriver::MyProcessEvent( const vr::VREvent_t &vrevent )\\r\\n243 | {\\r\\n244 | }\\r\\n245 | \\r\\n246 | \\r\\n247 | //-----------------------------------------------------------------------------\\r\\n248 | // Purpose: Our IServerTrackedDeviceProvider needs our serial number to add us to vrserver.\\r\\n249 | // It's not part of the ITrackedDeviceServerDriver interface, we created it ourselves.\\r\\n250 | //-----------------------------------------------------------------------------\\r\\n251 | const std::string &MyHMDControllerDeviceDriver::MyGetSerialNumber()\\r\\n252 | {\\r\\n253 | \\treturn my_hmd_serial_number_;\\r\\n254 | }\\r\\n255 | \\r\\n256 | //-----------------------------------------------------------------------------\\r\\n257 | // DISPLAY DRIVER METHOD DEFINITIONS\\r\\n258 | //-----------------------------------------------------------------------------\\r\\n259 | \\r\\n260 | MyHMDDisplayComponent::MyHMDDisplayComponent( const MyHMDDisplayDriverConfiguration &config )\\r\\n261 | \\t: config_( config )\\r\\n262 | {\\r\\n263 | }\\r\\n264 | \\r\\n265 | //-----------------------------------------------------------------------------\\r\\n266 | // Purpose: To inform vrcompositor if this display is considered an on-desktop display.\\r\\n267 | //-----------------------------------------------------------------------------\\r\\n268 | bool MyHMDDisplayComponent::IsDisplayOnDesktop()\\r\\n269 | {\\r\\n270 | \\treturn true;\\r\\n271 | }\\r\\n272 | \\r\\n273 | //-----------------------------------------------------------------------------\\r\\n274 | // Purpose: To as vrcompositor to search for this display.\\r\\n275 | //-----------------------------------------------------------------------------\\r\\n276 | bool MyHMDDisplayComponent::IsDisplayRealDisplay()\\r\\n277 | {\\r\\n278 | \\treturn false;\\r\\n279 | }\\r\\n280 | \\r\\n281 | //-----------------------------------------------------------------------------\\r\\n282 | // Purpose: To inform the rest of the vr system what the recommended target size should be\\r\\n283 | //-----------------------------------------------------------------------------\\r\\n284 | void MyHMDDisplayComponent::GetRecommendedRenderTargetSize( uint32_t *pnWidth, uint32_t *pnHeight )\\r\\n285 | {\\r\\n286 | \\t*pnWidth = config_.render_width;\\r\\n287 | \\t*pnHeight = config_.render_height;\\r\\n288 | }\\r\\n289 | \\r\\n290 | //-----------------------------------------------------------------------------\\r\\n291 | // Purpose: To inform vrcompositor how the screens should be organized.\\r\\n292 | //-----------------------------------------------------------------------------\\r\\n293 | void MyHMDDisplayComponent::GetEyeOutputViewport( vr::EVREye eEye, uint32_t *pnX, uint32_t *pnY, uint32_t *pnWidth, uint32_t *pnHeight )\\r\\n294 | {\\r\\n295 | \\t*pnY = 0;\\r\\n296 | \\r\\n297 | \\t// Each eye will have half the window\\r\\n298 | \\t*pnWidth = config_.window_width / 2;\\r\\n299 | \\r\\n300 | \\t// Each eye will have the full height\\r\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\n.gitignore\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:42:19 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n150,781 (75%)\\n\\n# Current Cost\\n$1.43\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":120,\"cacheWrites\":1758,\"cacheReads\":150656,\"cost\":0.0536013}"},{"ts":1744501342192,"type":"say","say":"text","text":"Let me continue reading the HMD device driver implementation to understand how it handles poses and IMU data:\n\nLet me continue reading the HMD device driver implementation to understand how it handles poses and IMU data:","partial":false},{"ts":1744501342996,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"samples/drivers/drivers/simplehmd/src/hmd_device_driver.cpp\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\samples\\\\drivers\\\\drivers\\\\simplehmd\\\\src\\\\hmd_device_driver.cpp\",\"reason\":\" (lines 300-400)\"}","partial":false},{"ts":1744501346302,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'samples/drivers/drivers/simplehmd/src/hmd_device_driver.cpp'] Result:\\n\\n<file><path>samples/drivers/drivers/simplehmd/src/hmd_device_driver.cpp</path>\\n<content lines=\\\"300-400\\\">\\n300 | \\t// Each eye will have the full height\\r\\n301 | \\t*pnHeight = config_.window_height;\\r\\n302 | \\r\\n303 | \\tif ( eEye == vr::Eye_Left )\\r\\n304 | \\t{\\r\\n305 | \\t\\t// Left eye viewport on the left half of the window\\r\\n306 | \\t\\t*pnX = 0;\\r\\n307 | \\t}\\r\\n308 | \\telse\\r\\n309 | \\t{\\r\\n310 | \\t\\t// Right eye viewport on the right half of the window\\r\\n311 | \\t\\t*pnX = config_.window_width / 2;\\r\\n312 | \\t}\\r\\n313 | }\\r\\n314 | \\r\\n315 | //-----------------------------------------------------------------------------\\r\\n316 | // Purpose: To inform the compositor what the projection parameters are for this HMD.\\r\\n317 | //-----------------------------------------------------------------------------\\r\\n318 | void MyHMDDisplayComponent::GetProjectionRaw( vr::EVREye eEye, float *pfLeft, float *pfRight, float *pfTop, float *pfBottom )\\r\\n319 | {\\r\\n320 | \\t*pfLeft = -1.0;\\r\\n321 | \\t*pfRight = 1.0;\\r\\n322 | \\t*pfTop = -1.0;\\r\\n323 | \\t*pfBottom = 1.0;\\r\\n324 | }\\r\\n325 | \\r\\n326 | //-----------------------------------------------------------------------------\\r\\n327 | // Purpose: To compute the distortion properties for a given uv in an image.\\r\\n328 | //-----------------------------------------------------------------------------\\r\\n329 | vr::DistortionCoordinates_t MyHMDDisplayComponent::ComputeDistortion( vr::EVREye eEye, float fU, float fV )\\r\\n330 | {\\r\\n331 | \\tvr::DistortionCoordinates_t coordinates{};\\r\\n332 | \\tcoordinates.rfBlue[ 0 ] = fU;\\r\\n333 | \\tcoordinates.rfBlue[ 1 ] = fV;\\r\\n334 | \\tcoordinates.rfGreen[ 0 ] = fU;\\r\\n335 | \\tcoordinates.rfGreen[ 1 ] = fV;\\r\\n336 | \\tcoordinates.rfRed[ 0 ] = fU;\\r\\n337 | \\tcoordinates.rfRed[ 1 ] = fV;\\r\\n338 | \\treturn coordinates;\\r\\n339 | }\\r\\n340 | \\r\\n341 | //-----------------------------------------------------------------------------\\r\\n342 | // Purpose: To inform vrcompositor what the window bounds for this virtual HMD are.\\r\\n343 | //-----------------------------------------------------------------------------\\r\\n344 | void MyHMDDisplayComponent::GetWindowBounds( int32_t *pnX, int32_t *pnY, uint32_t *pnWidth, uint32_t *pnHeight )\\r\\n345 | {\\r\\n346 | \\t*pnX = config_.window_x;\\r\\n347 | \\t*pnY = config_.window_y;\\r\\n348 | \\t*pnWidth = config_.window_width;\\r\\n349 | \\t*pnHeight = config_.window_height;\\r\\n350 | }\\r\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\n.gitignore\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:42:26 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n152,538 (76%)\\n\\n# Current Cost\\n$1.48\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":81,\"cacheWrites\":1221,\"cacheReads\":152414,\"cost\":0.05152995}"},{"ts":1744501348905,"type":"say","say":"text","text":"Now let me look at the device provider implementation for the simplehmd driver:\n\nLet me look at the device provider implementation for the simplehmd driver:","partial":false},{"ts":1744501350002,"type":"ask","ask":"tool","text":"{\"tool\":\"readFile\",\"path\":\"samples/drivers/drivers/simplehmd/src/device_provider.cpp\",\"isOutsideWorkspace\":false,\"content\":\"c:\\\\Users\\\\decid\\\\Documents\\\\projects\\\\openvr-resilient\\\\samples\\\\drivers\\\\drivers\\\\simplehmd\\\\src\\\\device_provider.cpp\",\"reason\":\" (max 500 lines)\"}","partial":false},{"ts":1744501356847,"type":"say","say":"api_req_started","text":"{\"request\":\"[read_file for 'samples/drivers/drivers/simplehmd/src/device_provider.cpp'] Result:\\n\\n<file><path>samples/drivers/drivers/simplehmd/src/device_provider.cpp</path>\\n<content lines=\\\"1-96\\\">\\n 1 | //============ Copyright (c) Valve Corporation, All rights reserved. ============\\r\\n 2 | #include \\\"device_provider.h\\\"\\r\\n 3 | \\r\\n 4 | #include \\\"driverlog.h\\\"\\r\\n 5 | \\r\\n 6 | //-----------------------------------------------------------------------------\\r\\n 7 | // Purpose: This is called by vrserver after it receives a pointer back from HmdDriverFactory.\\r\\n 8 | // You should do your resources allocations here (**not** in the constructor).\\r\\n 9 | //-----------------------------------------------------------------------------\\r\\n10 | vr::EVRInitError MyDeviceProvider::Init( vr::IVRDriverContext *pDriverContext )\\r\\n11 | {\\r\\n12 | \\t// We need to initialise our driver context to make calls to the server.\\r\\n13 | \\t// OpenVR provides a macro to do this for us.\\r\\n14 | \\tVR_INIT_SERVER_DRIVER_CONTEXT( pDriverContext );\\r\\n15 | \\r\\n16 | \\t// First, initialize our hmd, which we'll later pass OpenVR a pointer to.\\r\\n17 | \\tmy_hmd_device_ = std::make_unique< MyHMDControllerDeviceDriver >();\\r\\n18 | \\r\\n19 | \\t// TrackedDeviceAdded returning true means we have had our device added to SteamVR.\\r\\n20 | \\tif ( !vr::VRServerDriverHost()->TrackedDeviceAdded( my_hmd_device_->MyGetSerialNumber().c_str(), vr::TrackedDeviceClass_HMD, my_hmd_device_.get() ) )\\r\\n21 | \\t{\\r\\n22 | \\t\\tDriverLog( \\\"Failed to create hmd device!\\\" );\\r\\n23 | \\t\\treturn vr::VRInitError_Driver_Unknown;\\r\\n24 | \\t}\\r\\n25 | \\r\\n26 | \\treturn vr::VRInitError_None;\\r\\n27 | }\\r\\n28 | \\r\\n29 | //-----------------------------------------------------------------------------\\r\\n30 | // Purpose: Tells the runtime which version of the API we are targeting.\\r\\n31 | // Helper variables in the header you're using contain this information, which can be returned here.\\r\\n32 | //-----------------------------------------------------------------------------\\r\\n33 | const char *const *MyDeviceProvider::GetInterfaceVersions()\\r\\n34 | {\\r\\n35 | \\treturn vr::k_InterfaceVersions;\\r\\n36 | }\\r\\n37 | \\r\\n38 | //-----------------------------------------------------------------------------\\r\\n39 | // Purpose: This function is deprecated and never called. But, it must still be defined, or we can't compile.\\r\\n40 | //-----------------------------------------------------------------------------\\r\\n41 | bool MyDeviceProvider::ShouldBlockStandbyMode()\\r\\n42 | {\\r\\n43 | \\treturn false;\\r\\n44 | }\\r\\n45 | \\r\\n46 | //-----------------------------------------------------------------------------\\r\\n47 | // Purpose: This is called in the main loop of vrserver.\\r\\n48 | // Drivers *can* do work here, but should ensure this work is relatively inexpensive.\\r\\n49 | // A good thing to do here is poll for events from the runtime or applications\\r\\n50 | //-----------------------------------------------------------------------------\\r\\n51 | void MyDeviceProvider::RunFrame()\\r\\n52 | {\\r\\n53 | \\t// call our devices to run a frame\\r\\n54 | \\tif ( my_hmd_device_ != nullptr )\\r\\n55 | \\t{\\r\\n56 | \\t\\tmy_hmd_device_->MyRunFrame();\\r\\n57 | \\t}\\r\\n58 | \\r\\n59 | \\r\\n60 | \\t//Now, process events that were submitted for this frame.\\r\\n61 | \\tvr::VREvent_t vrevent{};\\r\\n62 | \\twhile ( vr::VRServerDriverHost()->PollNextEvent( &vrevent, sizeof( vr::VREvent_t ) ) )\\r\\n63 | \\t{\\r\\n64 | \\t\\tif ( my_hmd_device_ != nullptr )\\r\\n65 | \\t\\t{\\r\\n66 | \\t\\t\\tmy_hmd_device_->MyProcessEvent( vrevent );\\r\\n67 | \\t\\t}\\r\\n68 | \\t}\\r\\n69 | }\\r\\n70 | \\r\\n71 | //-----------------------------------------------------------------------------\\r\\n72 | // Purpose: This function is called when the system enters a period of inactivity.\\r\\n73 | // The devices might want to turn off their displays or go into a low power mode to preserve them.\\r\\n74 | //-----------------------------------------------------------------------------\\r\\n75 | void MyDeviceProvider::EnterStandby()\\r\\n76 | {\\r\\n77 | }\\r\\n78 | \\r\\n79 | //-----------------------------------------------------------------------------\\r\\n80 | // Purpose: This function is called after the system has been in a period of inactivity, and is waking up again.\\r\\n81 | // Turn back on the displays or devices here.\\r\\n82 | //-----------------------------------------------------------------------------\\r\\n83 | void MyDeviceProvider::LeaveStandby()\\r\\n84 | {\\r\\n85 | }\\r\\n86 | \\r\\n87 | //-----------------------------------------------------------------------------\\r\\n88 | // Purpose: This function is called just before the driver is unloaded from vrserver.\\r\\n89 | // Drivers should free whatever resources they have acquired over the session here.\\r\\n90 | // Any calls to the server is guaranteed to be valid before this, but not after it has been called.\\r\\n91 | //-----------------------------------------------------------------------------\\r\\n92 | void MyDeviceProvider::Cleanup()\\r\\n93 | {\\r\\n94 | \\t// Our controller devices will have already deactivated. Let's now destroy them.\\r\\n95 | \\tmy_hmd_device_ = nullptr;\\r\\n96 | }\\n</content>\\n</file>\\n\\n<environment_details>\\n# VSCode Visible Files\\n.gitignore\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:42:36 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n153,720 (77%)\\n\\n# Current Cost\\n$1.53\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":3225,\"cacheWrites\":1751,\"cacheReads\":153635,\"cost\":0.10104375}"},{"ts":1744501359628,"type":"say","say":"text","text":"Based on all the information I've gathered, I now have a good understanding of the OpenVR driver architecture and how to implement a custom driver that can access raw IMU data when optical tracking is lost. Let me now create a detailed plan for designing a custom driver solution that wraps the existing lighthouse driver and accesses raw IMU data.\n\n# Custom OpenVR Driver Design for IMU Data Access\n\nBased on my analysis of the OpenVR driver architecture, I've developed a comprehensive plan for creating a custom driver that can access raw IMU data when optical tracking is lost. This design will wrap the existing lighthouse driver while providing additional functionality to expose IMU data through a custom interface.\n\n## 1. Overall Architecture\n\n```mermaid\ngraph TD\n    A[SteamVR Runtime] --> B[Our Custom Driver]\n    B --> C[Lighthouse Driver]\n    B --> D[Custom IMU Interface]\n    C --> E[Tracking & Pose Data]\n    D --> F[Raw IMU Data]\n    A --> G[Applications]\n    G --> H[Standard OpenVR API]\n    G --> I[Custom IMU API]\n    I --> D\n```\n\nOur solution will consist of the following components:\n\n1. **Custom Driver Wrapper** - The main driver that will be loaded by SteamVR\n2. **Lighthouse Driver Interface** - Component that communicates with the existing lighthouse driver\n3. **IMU Data Provider** - Component that accesses and exposes raw IMU data\n4. **Custom API Interface** - Interface for applications to access the IMU data\n\n## 2. Key Components and Interfaces\n\n### 2.1 Custom Driver Wrapper\n\nThis is the main entry point for our driver. It will implement:\n\n- `IServerTrackedDeviceProvider` - The main interface required by OpenVR for driver implementation\n- `HmdDriverFactory` - The factory function that returns our driver implementation\n\n```cpp\nclass IMUEnabledDeviceProvider : public vr::IServerTrackedDeviceProvider {\npublic:\n    vr::EVRInitError Init(vr::IVRDriverContext *pDriverContext) override;\n    void Cleanup() override;\n    const char *const *GetInterfaceVersions() override;\n    void RunFrame() override;\n    bool ShouldBlockStandbyMode() override;\n    void EnterStandby() override;\n    void LeaveStandby() override;\n\nprivate:\n    std::unique_ptr<LighthouseDriverWrapper> m_lighthouseDriver;\n    std::unique_ptr<IMUDataProvider> m_imuDataProvider;\n};\n```\n\n### 2.2 Lighthouse Driver Wrapper\n\nThis component will load and communicate with the existing lighthouse driver:\n\n```cpp\nclass LighthouseDriverWrapper {\npublic:\n    LighthouseDriverWrapper();\n    ~LighthouseDriverWrapper();\n    \n    bool Initialize();\n    void Shutdown();\n    \n    // Forward calls to the lighthouse driver\n    void RunFrame();\n    void EnterStandby();\n    void LeaveStandby();\n    \nprivate:\n    void *m_lighthouseDriverLib;\n    vr::IServerTrackedDeviceProvider *m_lighthouseProvider;\n};\n```\n\n### 2.3 IMU Data Provider\n\nThis component will access and expose the raw IMU data:\n\n```cpp\nclass IMUDataProvider {\npublic:\n    IMUDataProvider();\n    ~IMUDataProvider();\n    \n    bool Initialize();\n    void Shutdown();\n    \n    // Get the latest IMU sample for a specific device\n    bool GetLatestIMUSample(uint32_t unDeviceIndex, vr::ImuSample_t *pSample);\n    \n    // Register a device for IMU data access\n    void RegisterDevice(uint32_t unDeviceIndex);\n    \n    // Check if IMU data is available for a device\n    bool IsIMUDataAvailable(uint32_t unDeviceIndex);\n    \nprivate:\n    std::map<uint32_t, std::queue<vr::ImuSample_t>> m_imuSamples;\n    std::mutex m_imuSamplesMutex;\n};\n```\n\n### 2.4 Custom Device Driver\n\nWe'll need to create a custom device driver that wraps the existing device drivers and adds our IMU functionality:\n\n```cpp\nclass IMUEnabledDeviceDriver : public vr::ITrackedDeviceServerDriver {\npublic:\n    IMUEnabledDeviceDriver(vr::ITrackedDeviceServerDriver *pWrappedDriver, IMUDataProvider *pIMUDataProvider);\n    ~IMUEnabledDeviceDriver();\n    \n    // ITrackedDeviceServerDriver interface\n    vr::EVRInitError Activate(uint32_t unObjectId) override;\n    void Deactivate() override;\n    void EnterStandby() override;\n    void *GetComponent(const char *pchComponentNameAndVersion) override;\n    void DebugRequest(const char *pchRequest, char *pchResponseBuffer, uint32_t unResponseBufferSize) override;\n    vr::DriverPose_t GetPose() override;\n    \nprivate:\n    vr::ITrackedDeviceServerDriver *m_pWrappedDriver;\n    IMUDataProvider *m_pIMUDataProvider;\n    uint32_t m_unDeviceId;\n};\n```\n\n### 2.5 Custom IMU Component Interface\n\nWe'll create a custom component interface that applications can use to access the IMU data:\n\n```cpp\nclass IVRIMUComponent {\npublic:\n    // Get the latest IMU sample\n    virtual bool GetLatestIMUSample(vr::ImuSample_t *pSample) = 0;\n    \n    // Check if IMU data is available\n    virtual bool IsIMUDataAvailable() = 0;\n    \n    // Get IMU data even when optical tracking is lost\n    virtual bool GetIMUDataInFallbackMode(vr::ImuSample_t *pSample) = 0;\n};\n\nstatic const char *IVRIMUComponent_Version = \"IVRIMUComponent_001\";\n```\n\n## 3. Implementation Details\n\n### 3.1 Driver Loading and Initialization\n\n1. SteamVR loads our custom driver\n2. Our driver loads the lighthouse driver\n3. We initialize our IMU data provider\n4. We register our custom device drivers with SteamVR\n\n```cpp\nvr::EVRInitError IMUEnabledDeviceProvider::Init(vr::IVRDriverContext *pDriverContext) {\n    VR_INIT_SERVER_DRIVER_CONTEXT(pDriverContext);\n    \n    // Initialize the lighthouse driver wrapper\n    m_lighthouseDriver = std::make_unique<LighthouseDriverWrapper>();\n    if (!m_lighthouseDriver->Initialize()) {\n        return vr::VRInitError_Driver_Failed;\n    }\n    \n    // Initialize the IMU data provider\n    m_imuDataProvider = std::make_unique<IMUDataProvider>();\n    if (!m_imuDataProvider->Initialize()) {\n        return vr::VRInitError_Driver_Failed;\n    }\n    \n    return vr::VRInitError_None;\n}\n```\n\n### 3.2 Accessing IMU Data\n\nThe key to our solution is accessing the raw IMU data from the devices. We'll do this by:\n\n1. Using the `ImuSample_t` struct defined in openvr_driver.h\n2. Monitoring the device's tracking state to detect when optical tracking is lost\n3. Providing the IMU data through our custom component interface\n\n```cpp\nbool IMUDataProvider::GetLatestIMUSample(uint32_t unDeviceIndex, vr::ImuSample_t *pSample) {\n    std::lock_guard<std::mutex> lock(m_imuSamplesMutex);\n    \n    auto it = m_imuSamples.find(unDeviceIndex);\n    if (it == m_imuSamples.end() || it->second.empty()) {\n        return false;\n    }\n    \n    *pSample = it->second.front();\n    it->second.pop();\n    \n    return true;\n}\n```\n\n### 3.3 Handling Optical Tracking Loss\n\nWhen optical tracking is lost, we'll detect this through the tracking result in the device pose:\n\n```cpp\nvoid *IMUEnabledDeviceDriver::GetComponent(const char *pchComponentNameAndVersion) {\n    // First check if the wrapped driver provides this component\n    void *pComponent = m_pWrappedDriver->GetComponent(pchComponentNameAndVersion);\n    if (pComponent) {\n        return pComponent;\n    }\n    \n    // If the component is our custom IMU component, return it\n    if (strcmp(pchComponentNameAndVersion, IVRIMUComponent_Version) == 0) {\n        return static_cast<IVRIMUComponent*>(this);\n    }\n    \n    return nullptr;\n}\n\nbool IMUEnabledDeviceDriver::GetIMUDataInFallbackMode(vr::ImuSample_t *pSample) {\n    vr::DriverPose_t pose = GetPose();\n    \n    // Check if optical tracking is lost\n    if (pose.result == vr::TrackingResult_Fallback_RotationOnly ||\n        pose.result == vr::TrackingResult_Calibrating_OutOfRange ||\n        pose.result == vr::TrackingResult_Running_OutOfRange) {\n        \n        // Get the IMU data from the provider\n        return m_pIMUDataProvider->GetLatestIMUSample(m_unDeviceId, pSample);\n    }\n    \n    return false;\n}\n```\n\n### 3.4 Exposing IMU Data to Applications\n\nApplications will access the IMU data through our custom component interface:\n\n```cpp\n// In the application\nvr::IVRIMUComponent *pIMUComponent = (vr::IVRIMUComponent*)\n    vr::VRSystem()->GetTrackedDeviceInterface(\n        vr::k_unTrackedDeviceIndex_Hmd, \n        IVRIMUComponent_Version);\n\nif (pIMUComponent) {\n    vr::ImuSample_t imuSample;\n    if (pIMUComponent->GetLatestIMUSample(&imuSample)) {\n        // Use the IMU data\n        // imuSample.vAccel - Accelerometer data\n        // imuSample.vGyro - Gyroscope data\n        // imuSample.fSampleTime - Timestamp\n    }\n}\n```\n\n## 4. Driver Configuration\n\n### 4.1 Driver Manifest\n\n```json\n{\n  \"alwaysActivate\": true,\n  \"name\": \"imu_enabled_driver\",\n  \"directory\": \"\",\n  \"resourceOnly\": false,\n  \"hmd_presence\": [\"*.*\"]\n}\n```\n\n### 4.2 Settings\n\nWe'll provide configuration options in the driver's settings:\n\n```json\n{\n  \"driver_imu_enabled\": {\n    \"enable\": true,\n    \"loadPriority\": 100,\n    \"enableImuFallback\": true,\n    \"imuSampleRate\": 1000,\n    \"imuBufferSize\": 100\n  }\n}\n```\n\n## 5. Implementation Challenges and Solutions\n\n### 5.1 Challenge: Accessing the Lighthouse Driver's IMU Data\n\nThe lighthouse driver doesn't directly expose IMU data through a public interface.\n\n**Solution**: We'll use the `k_pch_Lighthouse_EnableImuFallback_Bool` setting to enable IMU fallback in the lighthouse driver, and then intercept the IMU data through our wrapper.\n\n### 5.2 Challenge: Synchronizing with the Lighthouse Driver\n\nWe need to ensure our driver doesn't interfere with the lighthouse driver's normal operation.\n\n**Solution**: We'll use a proxy pattern to forward all calls to the lighthouse driver while adding our IMU functionality.\n\n### 5.3 Challenge: Performance Impact\n\nAccessing raw IMU data could impact performance.\n\n**Solution**: We'll implement efficient buffering and only process IMU data when needed.\n\n## 6. Testing and Validation\n\n1. **Unit Testing**: Test each component in isolation\n2. **Integration Testing**: Test the complete driver with SteamVR\n3. **Performance Testing**: Measure the performance impact of our driver\n4. **Validation Testing**: Verify that IMU data is available when optical tracking is lost\n\n## 7. Implementation Roadmap\n\n1. **Phase 1**: Create the basic driver structure and wrapper for the lighthouse driver\n2. **Phase 2**: Implement the IMU data provider and custom component interface\n3. **Phase 3**: Test and validate the solution\n4. **Phase 4**: Optimize performance and reliability\n5. **Phase 5**: Document the API and provide sample code for applications\n\n## Conclusion\n\nThis design provides a comprehensive solution for accessing raw IMU data from OpenVR devices, even when optical tracking is lost. By wrapping the existing lighthouse driver and providing a custom interface, we can expose this data to applications without modifying the core OpenVR runtime.\n\nThe solution is modular, extensible, and follows the OpenVR driver architecture patterns. It should be compatible with existing applications and provide a seamless experience for users.\n\nWould you like me to elaborate on any specific aspect of this design?","partial":false},{"ts":1744501404411,"type":"say","say":"api_req_started","text":"{\"request\":\"[ERROR] You did not use a tool in your previous response! Please retry with a tool use.\\n\\n# Reminder: Instructions for Tool Use\\n\\nTool uses are formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:\\n\\n<tool_name>\\n<parameter1_name>value1</parameter1_name>\\n<parameter2_name>value2</parameter2_name>\\n...\\n</tool_name>\\n\\nFor example:\\n\\n<attempt_completion>\\n<result>\\nI have completed the task...\\n</result>\\n</attempt_completion>\\n\\nAlways adhere to this format for all tool uses to ensure proper parsing and execution.\\n\\n# Next Steps\\n\\nIf you have completed the user's task, use the attempt_completion tool. \\nIf you require additional information from the user, use the ask_followup_question tool. \\nOtherwise, if you have not completed the task and do not need additional information, then proceed with the next step of the task. \\n(This is an automated message, so do not respond to it conversationally.)\\n\\n<environment_details>\\n# VSCode Visible Files\\n.gitignore\\n\\n# VSCode Open Tabs\\nREADME.md,OpenVR_Modifications.md,docs/Driver_API_Documentation.md,build.bat,src/vrcore/pathtools_public_fixed.h,src/vrcore/sharedlibtools_public_fixed.cpp,src/vrcore/strtools_public_fixed.cpp,src/vrcore/pathtools_public.h,src/vrcore/vrpathregistry_public_fixed.cpp,headers/openvr_capi.h,.gitignore,headers/openvr_driver.h,headers/openvr.h,src/openvr_api_public.cpp,src/vrcore/pathtools_public_fixed.cpp,openvr_api.vcxproj\\n\\n# Current Time\\n4/12/2025, 4:43:24 PM (America/Los_Angeles, UTC-7:00)\\n\\n# Current Context Size (Tokens)\\n158,615 (79%)\\n\\n# Current Cost\\n$1.63\\n\\n# Current Mode\\n<slug>architect</slug>\\n<name>Architect</name>\\n</environment_details>\",\"tokensIn\":4,\"tokensOut\":3198,\"cacheWrites\":3760,\"cacheReads\":155386,\"cost\":0.1086978}"},{"ts":1744501407682,"type":"say","say":"text","text":"I need to use a tool to present my design plan. Since I've completed the analysis and created a detailed plan for the custom driver solution, I should use the attempt_completion tool.","partial":false},{"ts":1744501408749,"type":"say","say":"completion_result","text":"# Custom OpenVR Driver Design for IMU Data Access\n\nBased on my analysis of the OpenVR driver architecture, I've developed a comprehensive plan for creating a custom driver that can access raw IMU data when optical tracking is lost. This design will wrap the existing lighthouse driver while providing additional functionality to expose IMU data through a custom interface.\n\n## 1. Overall Architecture\n\n```mermaid\ngraph TD\n    A[SteamVR Runtime] --> B[Our Custom Driver]\n    B --> C[Lighthouse Driver]\n    B --> D[Custom IMU Interface]\n    C --> E[Tracking & Pose Data]\n    D --> F[Raw IMU Data]\n    A --> G[Applications]\n    G --> H[Standard OpenVR API]\n    G --> I[Custom IMU API]\n    I --> D\n```\n\nOur solution will consist of the following components:\n\n1. **Custom Driver Wrapper** - The main driver that will be loaded by SteamVR\n2. **Lighthouse Driver Interface** - Component that communicates with the existing lighthouse driver\n3. **IMU Data Provider** - Component that accesses and exposes raw IMU data\n4. **Custom API Interface** - Interface for applications to access the IMU data\n\n## 2. Key Components and Interfaces\n\n### 2.1 Custom Driver Wrapper\n\nThis is the main entry point for our driver. It will implement:\n\n- `IServerTrackedDeviceProvider` - The main interface required by OpenVR for driver implementation\n- `HmdDriverFactory` - The factory function that returns our driver implementation\n\n```cpp\nclass IMUEnabledDeviceProvider : public vr::IServerTrackedDeviceProvider {\npublic:\n    vr::EVRInitError Init(vr::IVRDriverContext *pDriverContext) override;\n    void Cleanup() override;\n    const char *const *GetInterfaceVersions() override;\n    void RunFrame() override;\n    bool ShouldBlockStandbyMode() override;\n    void EnterStandby() override;\n    void LeaveStandby() override;\n\nprivate:\n    std::unique_ptr<LighthouseDriverWrapper> m_lighthouseDriver;\n    std::unique_ptr<IMUDataProvider> m_imuDataProvider;\n};\n```\n\n### 2.2 Lighthouse Driver Wrapper\n\nThis component will load and communicate with the existing lighthouse driver:\n\n```cpp\nclass LighthouseDriverWrapper {\npublic:\n    LighthouseDriverWrapper();\n    ~LighthouseDriverWrapper();\n    \n    bool Initialize();\n    void Shutdown();\n    \n    // Forward calls to the lighthouse driver\n    void RunFrame();\n    void EnterStandby();\n    void LeaveStandby();\n    \nprivate:\n    void *m_lighthouseDriverLib;\n    vr::IServerTrackedDeviceProvider *m_lighthouseProvider;\n};\n```\n\n### 2.3 IMU Data Provider\n\nThis component will access and expose the raw IMU data:\n\n```cpp\nclass IMUDataProvider {\npublic:\n    IMUDataProvider();\n    ~IMUDataProvider();\n    \n    bool Initialize();\n    void Shutdown();\n    \n    // Get the latest IMU sample for a specific device\n    bool GetLatestIMUSample(uint32_t unDeviceIndex, vr::ImuSample_t *pSample);\n    \n    // Register a device for IMU data access\n    void RegisterDevice(uint32_t unDeviceIndex);\n    \n    // Check if IMU data is available for a device\n    bool IsIMUDataAvailable(uint32_t unDeviceIndex);\n    \nprivate:\n    std::map<uint32_t, std::queue<vr::ImuSample_t>> m_imuSamples;\n    std::mutex m_imuSamplesMutex;\n};\n```\n\n### 2.4 Custom Device Driver\n\nWe'll need to create a custom device driver that wraps the existing device drivers and adds our IMU functionality:\n\n```cpp\nclass IMUEnabledDeviceDriver : public vr::ITrackedDeviceServerDriver {\npublic:\n    IMUEnabledDeviceDriver(vr::ITrackedDeviceServerDriver *pWrappedDriver, IMUDataProvider *pIMUDataProvider);\n    ~IMUEnabledDeviceDriver();\n    \n    // ITrackedDeviceServerDriver interface\n    vr::EVRInitError Activate(uint32_t unObjectId) override;\n    void Deactivate() override;\n    void EnterStandby() override;\n    void *GetComponent(const char *pchComponentNameAndVersion) override;\n    void DebugRequest(const char *pchRequest, char *pchResponseBuffer, uint32_t unResponseBufferSize) override;\n    vr::DriverPose_t GetPose() override;\n    \nprivate:\n    vr::ITrackedDeviceServerDriver *m_pWrappedDriver;\n    IMUDataProvider *m_pIMUDataProvider;\n    uint32_t m_unDeviceId;\n};\n```\n\n### 2.5 Custom IMU Component Interface\n\nWe'll create a custom component interface that applications can use to access the IMU data:\n\n```cpp\nclass IVRIMUComponent {\npublic:\n    // Get the latest IMU sample\n    virtual bool GetLatestIMUSample(vr::ImuSample_t *pSample) = 0;\n    \n    // Check if IMU data is available\n    virtual bool IsIMUDataAvailable() = 0;\n    \n    // Get IMU data even when optical tracking is lost\n    virtual bool GetIMUDataInFallbackMode(vr::ImuSample_t *pSample) = 0;\n};\n\nstatic const char *IVRIMUComponent_Version = \"IVRIMUComponent_001\";\n```\n\n## 3. Implementation Details\n\n### 3.1 Driver Loading and Initialization\n\n1. SteamVR loads our custom driver\n2. Our driver loads the lighthouse driver\n3. We initialize our IMU data provider\n4. We register our custom device drivers with SteamVR\n\n```cpp\nvr::EVRInitError IMUEnabledDeviceProvider::Init(vr::IVRDriverContext *pDriverContext) {\n    VR_INIT_SERVER_DRIVER_CONTEXT(pDriverContext);\n    \n    // Initialize the lighthouse driver wrapper\n    m_lighthouseDriver = std::make_unique<LighthouseDriverWrapper>();\n    if (!m_lighthouseDriver->Initialize()) {\n        return vr::VRInitError_Driver_Failed;\n    }\n    \n    // Initialize the IMU data provider\n    m_imuDataProvider = std::make_unique<IMUDataProvider>();\n    if (!m_imuDataProvider->Initialize()) {\n        return vr::VRInitError_Driver_Failed;\n    }\n    \n    return vr::VRInitError_None;\n}\n```\n\n### 3.2 Accessing IMU Data\n\nThe key to our solution is accessing the raw IMU data from the devices. We'll do this by:\n\n1. Using the `ImuSample_t` struct defined in openvr_driver.h\n2. Monitoring the device's tracking state to detect when optical tracking is lost\n3. Providing the IMU data through our custom component interface\n\n```cpp\nbool IMUDataProvider::GetLatestIMUSample(uint32_t unDeviceIndex, vr::ImuSample_t *pSample) {\n    std::lock_guard<std::mutex> lock(m_imuSamplesMutex);\n    \n    auto it = m_imuSamples.find(unDeviceIndex);\n    if (it == m_imuSamples.end() || it->second.empty()) {\n        return false;\n    }\n    \n    *pSample = it->second.front();\n    it->second.pop();\n    \n    return true;\n}\n```\n\n### 3.3 Handling Optical Tracking Loss\n\nWhen optical tracking is lost, we'll detect this through the tracking result in the device pose:\n\n```cpp\nvoid *IMUEnabledDeviceDriver::GetComponent(const char *pchComponentNameAndVersion) {\n    // First check if the wrapped driver provides this component\n    void *pComponent = m_pWrappedDriver->GetComponent(pchComponentNameAndVersion);\n    if (pComponent) {\n        return pComponent;\n    }\n    \n    // If the component is our custom IMU component, return it\n    if (strcmp(pchComponentNameAndVersion, IVRIMUComponent_Version) == 0) {\n        return static_cast<IVRIMUComponent*>(this);\n    }\n    \n    return nullptr;\n}\n\nbool IMUEnabledDeviceDriver::GetIMUDataInFallbackMode(vr::ImuSample_t *pSample) {\n    vr::DriverPose_t pose = GetPose();\n    \n    // Check if optical tracking is lost\n    if (pose.result == vr::TrackingResult_Fallback_RotationOnly ||\n        pose.result == vr::TrackingResult_Calibrating_OutOfRange ||\n        pose.result == vr::TrackingResult_Running_OutOfRange) {\n        \n        // Get the IMU data from the provider\n        return m_pIMUDataProvider->GetLatestIMUSample(m_unDeviceId, pSample);\n    }\n    \n    return false;\n}\n```\n\n### 3.4 Exposing IMU Data to Applications\n\nApplications will access the IMU data through our custom component interface:\n\n```cpp\n// In the application\nvr::IVRIMUComponent *pIMUComponent = (vr::IVRIMUComponent*)\n    vr::VRSystem()->GetTrackedDeviceInterface(\n        vr::k_unTrackedDeviceIndex_Hmd, \n        IVRIMUComponent_Version);\n\nif (pIMUComponent) {\n    vr::ImuSample_t imuSample;\n    if (pIMUComponent->GetLatestIMUSample(&imuSample)) {\n        // Use the IMU data\n        // imuSample.vAccel - Accelerometer data\n        // imuSample.vGyro - Gyroscope data\n        // imuSample.fSampleTime - Timestamp\n    }\n}\n```\n\n## 4. Driver Configuration\n\n### 4.1 Driver Manifest\n\n```json\n{\n  \"alwaysActivate\": true,\n  \"name\": \"imu_enabled_driver\",\n  \"directory\": \"\",\n  \"resourceOnly\": false,\n  \"hmd_presence\": [\"*.*\"]\n}\n```\n\n### 4.2 Settings\n\nWe'll provide configuration options in the driver's settings:\n\n```json\n{\n  \"driver_imu_enabled\": {\n    \"enable\": true,\n    \"loadPriority\": 100,\n    \"enableImuFallback\": true,\n    \"imuSampleRate\": 1000,\n    \"imuBufferSize\": 100\n  }\n}\n```\n\n## 5. Implementation Challenges and Solutions\n\n### 5.1 Challenge: Accessing the Lighthouse Driver's IMU Data\n\nThe lighthouse driver doesn't directly expose IMU data through a public interface.\n\n**Solution**: We'll use the `k_pch_Lighthouse_EnableImuFallback_Bool` setting to enable IMU fallback in the lighthouse driver, and then intercept the IMU data through our wrapper.\n\n### 5.2 Challenge: Synchronizing with the Lighthouse Driver\n\nWe need to ensure our driver doesn't interfere with the lighthouse driver's normal operation.\n\n**Solution**: We'll use a proxy pattern to forward all calls to the lighthouse driver while adding our IMU functionality.\n\n### 5.3 Challenge: Performance Impact\n\nAccessing raw IMU data could impact performance.\n\n**Solution**: We'll implement efficient buffering and only process IMU data when needed.\n\n## 6. Testing and Validation\n\n1. **Unit Testing**: Test each component in isolation\n2. **Integration Testing**: Test the complete driver with SteamVR\n3. **Performance Testing**: Measure the performance impact of our driver\n4. **Validation Testing**: Verify that IMU data is available when optical tracking is lost\n\n## 7. Implementation Roadmap\n\n1. **Phase 1**: Create the basic driver structure and wrapper for the lighthouse driver\n2. **Phase 2**: Implement the IMU data provider and custom component interface\n3. **Phase 3**: Test and validate the solution\n4. **Phase 4**: Optimize performance and reliability\n5. **Phase 5**: Document the API and provide sample code for applications\n\n## Conclusion\n\nThis design provides a comprehensive solution for accessing raw IMU data from OpenVR devices, even when optical tracking is lost. By wrapping the existing lighthouse driver and providing a custom interface, we can expose this data to applications without modifying the core OpenVR runtime.\n\nThe solution is modular, extensible, and follows the OpenVR driver architecture patterns. It should be compatible with existing applications and provide a seamless experience for users.","partial":false},{"ts":1744501449842,"type":"ask","ask":"tool","text":"{\"tool\":\"finishTask\"}"}]